summaryrefslogtreecommitdiffstats
path: root/mdk-stage1
diff options
context:
space:
mode:
authorAntoine Ginies <aginies@mandriva.com>2011-01-19 10:44:49 +0000
committerAntoine Ginies <aginies@mandriva.com>2011-01-19 10:44:49 +0000
commit530a16ec071db0e24e6e949e265a96848864967c (patch)
treefe40cacd28d67b98186754c551b7fd339ebc7e17 /mdk-stage1
downloaddrakx-530a16ec071db0e24e6e949e265a96848864967c.tar
drakx-530a16ec071db0e24e6e949e265a96848864967c.tar.gz
drakx-530a16ec071db0e24e6e949e265a96848864967c.tar.bz2
drakx-530a16ec071db0e24e6e949e265a96848864967c.tar.xz
drakx-530a16ec071db0e24e6e949e265a96848864967c.zip
add mes5-2.6.33 branch
Diffstat (limited to 'mdk-stage1')
-rw-r--r--mdk-stage1/Makefile223
-rw-r--r--mdk-stage1/Makefile.common68
-rw-r--r--mdk-stage1/NEWS131
-rw-r--r--mdk-stage1/adsl.c183
-rw-r--r--mdk-stage1/adsl.h34
-rw-r--r--mdk-stage1/automatic.c166
-rw-r--r--mdk-stage1/automatic.h33
-rw-r--r--mdk-stage1/bootsplash.c70
-rw-r--r--mdk-stage1/bootsplash.h25
-rw-r--r--mdk-stage1/cdrom.c219
-rw-r--r--mdk-stage1/cdrom.h29
-rw-r--r--mdk-stage1/config-stage1.h82
-rw-r--r--mdk-stage1/dhcp.c678
-rw-r--r--mdk-stage1/dhcp.h37
-rw-r--r--mdk-stage1/directory.c169
-rw-r--r--mdk-stage1/directory.h29
-rw-r--r--mdk-stage1/disk.c225
-rw-r--r--mdk-stage1/disk.h27
-rw-r--r--mdk-stage1/dns.c224
-rw-r--r--mdk-stage1/dns.h30
-rw-r--r--mdk-stage1/doc/HACKING31
-rw-r--r--mdk-stage1/doc/README185
-rw-r--r--mdk-stage1/doc/TECH-INFOS106
-rw-r--r--mdk-stage1/doc/UPDATEMODULES95
-rw-r--r--mdk-stage1/doc/WHY-DIETLIBC50
-rw-r--r--mdk-stage1/doc/documented..frontend.h69
-rw-r--r--mdk-stage1/frontend-common.c64
-rw-r--r--mdk-stage1/frontend.h68
-rw-r--r--mdk-stage1/init.c565
-rw-r--r--mdk-stage1/ka.c193
-rw-r--r--mdk-stage1/ka.h20
-rw-r--r--mdk-stage1/log.c94
-rw-r--r--mdk-stage1/log.h34
-rw-r--r--mdk-stage1/lomount.c194
-rw-r--r--mdk-stage1/lomount.h21
-rw-r--r--mdk-stage1/modules.c478
-rw-r--r--mdk-stage1/modules.h43
-rw-r--r--mdk-stage1/mount.c239
-rw-r--r--mdk-stage1/mount.h32
-rw-r--r--mdk-stage1/mount_rpcgen.h208
-rw-r--r--mdk-stage1/network.c1209
-rw-r--r--mdk-stage1/network.h66
-rw-r--r--mdk-stage1/newt-frontend.c388
-rw-r--r--mdk-stage1/newt/Makefile42
-rw-r--r--mdk-stage1/newt/button.c192
-rw-r--r--mdk-stage1/newt/buttonbar.c46
-rw-r--r--mdk-stage1/newt/checkbox.c292
-rw-r--r--mdk-stage1/newt/checkboxtree.c714
-rw-r--r--mdk-stage1/newt/entry.c378
-rw-r--r--mdk-stage1/newt/form.c713
-rw-r--r--mdk-stage1/newt/grid.c389
-rw-r--r--mdk-stage1/newt/label.c81
-rw-r--r--mdk-stage1/newt/listbox.c752
-rw-r--r--mdk-stage1/newt/newt.c672
-rw-r--r--mdk-stage1/newt/newt.h362
-rw-r--r--mdk-stage1/newt/newt_pr.h82
-rw-r--r--mdk-stage1/newt/scale.c72
-rw-r--r--mdk-stage1/newt/scrollbar.c124
-rw-r--r--mdk-stage1/newt/textbox.c409
-rw-r--r--mdk-stage1/newt/windows.c275
-rw-r--r--mdk-stage1/nfs_mount4.h54
-rw-r--r--mdk-stage1/nfsmount.c740
-rw-r--r--mdk-stage1/nfsmount.h331
-rw-r--r--mdk-stage1/params.c175
-rw-r--r--mdk-stage1/params.h31
-rw-r--r--mdk-stage1/partition.c170
-rw-r--r--mdk-stage1/partition.h28
-rw-r--r--mdk-stage1/pci-resource/Makefile25
-rwxr-xr-xmdk-stage1/pci-resource/update-pci-ids.pl27
-rw-r--r--mdk-stage1/pcmcia-resource/Makefile24
-rwxr-xr-xmdk-stage1/pcmcia-resource/update-pcmcia-ids.pl42
-rw-r--r--mdk-stage1/pcmcia/Makefile52
-rw-r--r--mdk-stage1/pcmcia/bulkmem.h195
-rw-r--r--mdk-stage1/pcmcia/cirrus.h157
-rw-r--r--mdk-stage1/pcmcia/cistpl.h604
-rw-r--r--mdk-stage1/pcmcia/cs.h433
-rw-r--r--mdk-stage1/pcmcia/cs_types.h70
-rw-r--r--mdk-stage1/pcmcia/driver_ops.h73
-rw-r--r--mdk-stage1/pcmcia/ds.h148
-rw-r--r--mdk-stage1/pcmcia/i82365.h135
-rw-r--r--mdk-stage1/pcmcia/lex_config.l224
-rwxr-xr-xmdk-stage1/pcmcia/merge_from_pcitable47
-rw-r--r--mdk-stage1/pcmcia/pcmcia.h21
-rw-r--r--mdk-stage1/pcmcia/probe.c524
-rw-r--r--mdk-stage1/pcmcia/startup.c271
-rw-r--r--mdk-stage1/pcmcia/startup.h54
-rw-r--r--mdk-stage1/pcmcia/tcic.h266
-rw-r--r--mdk-stage1/pcmcia/version.h4
-rw-r--r--mdk-stage1/pcmcia/vg468.h106
-rw-r--r--mdk-stage1/pcmcia/yacc_config.y133
-rw-r--r--mdk-stage1/ppp/Changes-2.3441
-rw-r--r--mdk-stage1/ppp/FAQ634
-rw-r--r--mdk-stage1/ppp/PLUGINS131
-rw-r--r--mdk-stage1/ppp/README168
-rw-r--r--mdk-stage1/ppp/README.MSCHAP80284
-rw-r--r--mdk-stage1/ppp/README.cbcp97
-rw-r--r--mdk-stage1/ppp/README.linux297
-rw-r--r--mdk-stage1/ppp/README.sol2220
-rw-r--r--mdk-stage1/ppp/README.sunos462
-rw-r--r--mdk-stage1/ppp/SETUP111
-rw-r--r--mdk-stage1/ppp/chat/Makefile.linux27
-rw-r--r--mdk-stage1/ppp/chat/Makefile.linux.makeopt27
-rw-r--r--mdk-stage1/ppp/chat/Makefile.sol219
-rw-r--r--mdk-stage1/ppp/chat/Makefile.sunos419
-rw-r--r--mdk-stage1/ppp/chat/chat.8515
-rw-r--r--mdk-stage1/ppp/chat/chat.c1756
-rw-r--r--mdk-stage1/ppp/common/zlib.c5376
-rw-r--r--mdk-stage1/ppp/common/zlib.h1010
-rwxr-xr-xmdk-stage1/ppp/configure141
-rw-r--r--mdk-stage1/ppp/contrib/pppgetpass/Makefile.linux16
-rw-r--r--mdk-stage1/ppp/contrib/pppgetpass/pppgetpass.818
-rw-r--r--mdk-stage1/ppp/contrib/pppgetpass/pppgetpass.gtk.c92
-rwxr-xr-xmdk-stage1/ppp/contrib/pppgetpass/pppgetpass.sh7
-rw-r--r--mdk-stage1/ppp/contrib/pppgetpass/pppgetpass.vt.c218
-rw-r--r--mdk-stage1/ppp/etc.ppp/chap-secrets2
-rw-r--r--mdk-stage1/ppp/etc.ppp/options5
-rw-r--r--mdk-stage1/ppp/etc.ppp/options.options1
-rw-r--r--mdk-stage1/ppp/etc.ppp/pap-secrets2
-rw-r--r--mdk-stage1/ppp/include/linux/if_ppp.h155
-rw-r--r--mdk-stage1/ppp/include/linux/if_pppvar.h138
-rw-r--r--mdk-stage1/ppp/include/linux/ppp-comp.h203
-rw-r--r--mdk-stage1/ppp/include/linux/ppp_defs.h185
-rw-r--r--mdk-stage1/ppp/include/net/if_ppp.h133
-rw-r--r--mdk-stage1/ppp/include/net/ppp-comp.h165
-rw-r--r--mdk-stage1/ppp/include/net/ppp_defs.h184
-rw-r--r--mdk-stage1/ppp/include/net/pppio.h99
-rw-r--r--mdk-stage1/ppp/include/net/slcompress.h148
-rw-r--r--mdk-stage1/ppp/include/net/vjcompress.h144
-rw-r--r--mdk-stage1/ppp/include/pcap-int.h117
-rw-r--r--mdk-stage1/ppp/linux/Makefile.top55
-rw-r--r--mdk-stage1/ppp/modules/bsd-comp.c1116
-rw-r--r--mdk-stage1/ppp/modules/deflate.c760
-rw-r--r--mdk-stage1/ppp/modules/if_ppp.c865
-rw-r--r--mdk-stage1/ppp/modules/ppp.c2486
-rw-r--r--mdk-stage1/ppp/modules/ppp_ahdlc.c878
-rw-r--r--mdk-stage1/ppp/modules/ppp_comp.c1126
-rw-r--r--mdk-stage1/ppp/modules/ppp_mod.h190
-rw-r--r--mdk-stage1/ppp/modules/vjcompress.c587
-rw-r--r--mdk-stage1/ppp/pppd/Makefile51
-rw-r--r--mdk-stage1/ppp/pppd/Makefile.linux129
-rw-r--r--mdk-stage1/ppp/pppd/Makefile.linux.make131
-rw-r--r--mdk-stage1/ppp/pppd/Makefile.linux.makeopt129
-rw-r--r--mdk-stage1/ppp/pppd/Makefile.sol248
-rw-r--r--mdk-stage1/ppp/pppd/Makefile.sunos426
-rw-r--r--mdk-stage1/ppp/pppd/auth.c1939
-rw-r--r--mdk-stage1/ppp/pppd/cbcp.c456
-rw-r--r--mdk-stage1/ppp/pppd/cbcp.h26
-rw-r--r--mdk-stage1/ppp/pppd/ccp.c1257
-rw-r--r--mdk-stage1/ppp/pppd/ccp.h48
-rw-r--r--mdk-stage1/ppp/pppd/chap.c860
-rw-r--r--mdk-stage1/ppp/pppd/chap.h124
-rw-r--r--mdk-stage1/ppp/pppd/chap_ms.c338
-rw-r--r--mdk-stage1/ppp/pppd/chap_ms.h33
-rw-r--r--mdk-stage1/ppp/pppd/demand.c351
-rw-r--r--mdk-stage1/ppp/pppd/eui64.c40
-rw-r--r--mdk-stage1/ppp/pppd/eui64.h97
-rw-r--r--mdk-stage1/ppp/pppd/fsm.c762
-rw-r--r--mdk-stage1/ppp/pppd/fsm.h144
-rw-r--r--mdk-stage1/ppp/pppd/ipcp.c2054
-rw-r--r--mdk-stage1/ppp/pppd/ipcp.h73
-rw-r--r--mdk-stage1/ppp/pppd/ipv6cp.c1512
-rw-r--r--mdk-stage1/ppp/pppd/ipv6cp.h126
-rw-r--r--mdk-stage1/ppp/pppd/ipxcp.c1570
-rw-r--r--mdk-stage1/ppp/pppd/ipxcp.h71
-rw-r--r--mdk-stage1/ppp/pppd/lcp.c2224
-rw-r--r--mdk-stage1/ppp/pppd/lcp.h95
-rw-r--r--mdk-stage1/ppp/pppd/magic.c88
-rw-r--r--mdk-stage1/ppp/pppd/magic.h23
-rw-r--r--mdk-stage1/ppp/pppd/main.c1846
-rw-r--r--mdk-stage1/ppp/pppd/md4.c298
-rw-r--r--mdk-stage1/ppp/pppd/md4.h64
-rw-r--r--mdk-stage1/ppp/pppd/md5.c309
-rw-r--r--mdk-stage1/ppp/pppd/md5.h58
-rw-r--r--mdk-stage1/ppp/pppd/multilink.c397
-rw-r--r--mdk-stage1/ppp/pppd/options.c1513
-rw-r--r--mdk-stage1/ppp/pppd/patchlevel.h4
-rw-r--r--mdk-stage1/ppp/pppd/pathnames.h25
-rw-r--r--mdk-stage1/ppp/pppd/plugins/Makefile.linux19
-rw-r--r--mdk-stage1/ppp/pppd/plugins/Makefile.sol227
-rw-r--r--mdk-stage1/ppp/pppd/plugins/minconn.c46
-rw-r--r--mdk-stage1/ppp/pppd/plugins/passprompt.c108
-rw-r--r--mdk-stage1/ppp/pppd/ppp.pam6
-rw-r--r--mdk-stage1/ppp/pppd/pppd.81591
-rw-r--r--mdk-stage1/ppp/pppd/pppd.h787
-rw-r--r--mdk-stage1/ppp/pppd/pppd.h.wtmp789
-rw-r--r--mdk-stage1/ppp/pppd/sys-linux.c2672
-rw-r--r--mdk-stage1/ppp/pppd/sys-linux.c.wtmp2750
-rw-r--r--mdk-stage1/ppp/pppd/sys-solaris.c2737
-rw-r--r--mdk-stage1/ppp/pppd/sys-sunos4.c1559
-rw-r--r--mdk-stage1/ppp/pppd/tdb.c1282
-rw-r--r--mdk-stage1/ppp/pppd/tdb.h77
-rw-r--r--mdk-stage1/ppp/pppd/tty.c1164
-rw-r--r--mdk-stage1/ppp/pppd/upap.c640
-rw-r--r--mdk-stage1/ppp/pppd/upap.h87
-rw-r--r--mdk-stage1/ppp/pppd/utils.c949
-rw-r--r--mdk-stage1/ppp/pppdump/Makefile.linux17
-rw-r--r--mdk-stage1/ppp/pppdump/Makefile.linux.makeopt17
-rw-r--r--mdk-stage1/ppp/pppdump/Makefile.linux.pppdump-Makefile17
-rw-r--r--mdk-stage1/ppp/pppdump/Makefile.sol221
-rw-r--r--mdk-stage1/ppp/pppdump/Makefile.sunos421
-rw-r--r--mdk-stage1/ppp/pppdump/bsd-comp.c750
-rw-r--r--mdk-stage1/ppp/pppdump/deflate.c344
-rw-r--r--mdk-stage1/ppp/pppdump/ppp-comp.h150
-rw-r--r--mdk-stage1/ppp/pppdump/pppdump.862
-rw-r--r--mdk-stage1/ppp/pppdump/pppdump.c502
-rw-r--r--mdk-stage1/ppp/pppdump/zlib.c4614
-rw-r--r--mdk-stage1/ppp/pppdump/zlib.h631
-rw-r--r--mdk-stage1/ppp/pppstats/Makefile.linux32
-rw-r--r--mdk-stage1/ppp/pppstats/Makefile.sol220
-rw-r--r--mdk-stage1/ppp/pppstats/Makefile.sunos430
-rw-r--r--mdk-stage1/ppp/pppstats/pppstats.8217
-rw-r--r--mdk-stage1/ppp/pppstats/pppstats.c557
-rw-r--r--mdk-stage1/ppp/sample/auth-down17
-rw-r--r--mdk-stage1/ppp/sample/auth-up17
-rw-r--r--mdk-stage1/ppp/sample/ip-down22
-rw-r--r--mdk-stage1/ppp/sample/ip-up23
-rw-r--r--mdk-stage1/ppp/sample/options153
-rw-r--r--mdk-stage1/ppp/sample/options.ttyXX14
-rw-r--r--mdk-stage1/ppp/sample/pap-secrets28
-rw-r--r--mdk-stage1/ppp/scripts/README143
-rwxr-xr-xmdk-stage1/ppp/scripts/callback77
-rw-r--r--mdk-stage1/ppp/scripts/chat-callback98
-rw-r--r--mdk-stage1/ppp/scripts/chatchat/README134
-rw-r--r--mdk-stage1/ppp/scripts/chatchat/chatchat.c409
-rw-r--r--mdk-stage1/ppp/scripts/ip-down.local.add20
-rw-r--r--mdk-stage1/ppp/scripts/ip-up.local.add24
-rw-r--r--mdk-stage1/ppp/scripts/options-rsh-loc1
-rw-r--r--mdk-stage1/ppp/scripts/options-rsh-rem1
-rw-r--r--mdk-stage1/ppp/scripts/options-ssh-loc1
-rw-r--r--mdk-stage1/ppp/scripts/options-ssh-rem1
-rwxr-xr-xmdk-stage1/ppp/scripts/ppp-off34
-rwxr-xr-xmdk-stage1/ppp/scripts/ppp-on36
-rwxr-xr-xmdk-stage1/ppp/scripts/ppp-on-dialer17
-rwxr-xr-xmdk-stage1/ppp/scripts/ppp-on-rsh72
-rwxr-xr-xmdk-stage1/ppp/scripts/ppp-on-ssh76
-rwxr-xr-xmdk-stage1/ppp/scripts/redialer96
-rw-r--r--mdk-stage1/ppp/scripts/secure-card111
-rw-r--r--mdk-stage1/ppp/solaris/Makedefs16
-rw-r--r--mdk-stage1/ppp/solaris/Makedefs.sol259
-rw-r--r--mdk-stage1/ppp/solaris/Makefile.sol266
-rw-r--r--mdk-stage1/ppp/solaris/Makefile.sol2-6485
-rw-r--r--mdk-stage1/ppp/solaris/Makefile.top50
-rw-r--r--mdk-stage1/ppp/solaris/ppp.c2486
-rw-r--r--mdk-stage1/ppp/solaris/ppp.conf1
-rw-r--r--mdk-stage1/ppp/solaris/ppp_ahdlc.c878
-rw-r--r--mdk-stage1/ppp/solaris/ppp_ahdlc_mod.c49
-rw-r--r--mdk-stage1/ppp/solaris/ppp_comp.c1126
-rw-r--r--mdk-stage1/ppp/solaris/ppp_comp_mod.c81
-rw-r--r--mdk-stage1/ppp/solaris/ppp_mod.c174
-rw-r--r--mdk-stage1/ppp/solaris/ppp_mod.h190
-rw-r--r--mdk-stage1/ppp/sunos4/Makedefs13
-rw-r--r--mdk-stage1/ppp/sunos4/Makefile57
-rw-r--r--mdk-stage1/ppp/sunos4/Makefile.top46
-rw-r--r--mdk-stage1/ppp/sunos4/if_ppp_vdcmd.c57
-rwxr-xr-xmdk-stage1/ppp/sunos4/ppp.INSTALL104
-rw-r--r--mdk-stage1/ppp/sunos4/ppp_ahdlc_vdcmd.c57
-rw-r--r--mdk-stage1/ppp/sunos4/ppp_comp_vdcmd.c57
-rw-r--r--mdk-stage1/ppp/sunos4/ppp_vdcmd.c81
-rw-r--r--mdk-stage1/ppp/svr4/Makedefs16
-rw-r--r--mdk-stage1/ppp/svr4/Makedefs.sol259
-rw-r--r--mdk-stage1/ppp/svr4/Makefile.sol266
-rw-r--r--mdk-stage1/ppp/svr4/Makefile.sol2-6485
-rw-r--r--mdk-stage1/ppp/svr4/Makefile.svr460
-rw-r--r--mdk-stage1/ppp/svr4/Makefile.top50
-rw-r--r--mdk-stage1/ppp/svr4/ppp.Master1
-rw-r--r--mdk-stage1/ppp/svr4/ppp.Node1
-rw-r--r--mdk-stage1/ppp/svr4/ppp.System1
-rw-r--r--mdk-stage1/ppp/svr4/ppp.conf1
-rw-r--r--mdk-stage1/ppp/svr4/ppp_ahdl.Master1
-rw-r--r--mdk-stage1/ppp/svr4/ppp_ahdl.System1
-rw-r--r--mdk-stage1/ppp/svr4/ppp_ahdlc_mod.c49
-rw-r--r--mdk-stage1/ppp/svr4/ppp_comp.Master1
-rw-r--r--mdk-stage1/ppp/svr4/ppp_comp.System1
-rw-r--r--mdk-stage1/ppp/svr4/ppp_comp_mod.c81
-rw-r--r--mdk-stage1/ppp/svr4/ppp_mod.c174
-rw-r--r--mdk-stage1/probe-modules.c70
-rw-r--r--mdk-stage1/probing.c959
-rw-r--r--mdk-stage1/probing.h65
-rw-r--r--mdk-stage1/rescue-gui.c297
-rw-r--r--mdk-stage1/rp-pppoe/README87
-rw-r--r--mdk-stage1/rp-pppoe/configs/firewall-masq35
-rw-r--r--mdk-stage1/rp-pppoe/configs/firewall-standalone32
-rw-r--r--mdk-stage1/rp-pppoe/configs/pap-secrets9
-rw-r--r--mdk-stage1/rp-pppoe/configs/pppoe-server-options5
-rw-r--r--mdk-stage1/rp-pppoe/configs/pppoe.conf126
-rw-r--r--mdk-stage1/rp-pppoe/doc/CHANGES177
-rw-r--r--mdk-stage1/rp-pppoe/doc/HOW-TO-CONNECT295
-rw-r--r--mdk-stage1/rp-pppoe/doc/KERNEL-MODE-PPPOE39
-rw-r--r--mdk-stage1/rp-pppoe/doc/LICENSE339
-rw-r--r--mdk-stage1/rp-pppoe/doc/PROBLEMS3
-rwxr-xr-xmdk-stage1/rp-pppoe/go43
-rwxr-xr-xmdk-stage1/rp-pppoe/go-gui92
-rw-r--r--mdk-stage1/rp-pppoe/gui/Makefile.in64
-rw-r--r--mdk-stage1/rp-pppoe/gui/html/tkpppoe.html181
-rw-r--r--mdk-stage1/rp-pppoe/gui/pppoe-wrapper.145
-rw-r--r--mdk-stage1/rp-pppoe/gui/tkpppoe.136
-rwxr-xr-xmdk-stage1/rp-pppoe/gui/tkpppoe.in2891
-rw-r--r--mdk-stage1/rp-pppoe/gui/wrapper.c234
-rw-r--r--mdk-stage1/rp-pppoe/man/adsl-connect.866
-rw-r--r--mdk-stage1/rp-pppoe/man/adsl-setup.823
-rw-r--r--mdk-stage1/rp-pppoe/man/adsl-start.827
-rw-r--r--mdk-stage1/rp-pppoe/man/adsl-status.825
-rw-r--r--mdk-stage1/rp-pppoe/man/adsl-stop.821
-rw-r--r--mdk-stage1/rp-pppoe/man/pppoe-relay.8124
-rw-r--r--mdk-stage1/rp-pppoe/man/pppoe-server.8123
-rw-r--r--mdk-stage1/rp-pppoe/man/pppoe-sniff.877
-rw-r--r--mdk-stage1/rp-pppoe/man/pppoe.8236
-rw-r--r--mdk-stage1/rp-pppoe/man/pppoe.conf.5168
-rw-r--r--mdk-stage1/rp-pppoe/rp-pppoe-gui.spec98
-rw-r--r--mdk-stage1/rp-pppoe/rp-pppoe.spec71
-rwxr-xr-xmdk-stage1/rp-pppoe/scripts/adsl-connect.in278
-rwxr-xr-xmdk-stage1/rp-pppoe/scripts/adsl-init-suse.in62
-rwxr-xr-xmdk-stage1/rp-pppoe/scripts/adsl-init-turbolinux.in62
-rwxr-xr-xmdk-stage1/rp-pppoe/scripts/adsl-init.in64
-rwxr-xr-xmdk-stage1/rp-pppoe/scripts/adsl-setup.in346
-rwxr-xr-xmdk-stage1/rp-pppoe/scripts/adsl-start.in186
-rwxr-xr-xmdk-stage1/rp-pppoe/scripts/adsl-status82
-rwxr-xr-xmdk-stage1/rp-pppoe/scripts/adsl-stop.in84
-rw-r--r--mdk-stage1/rp-pppoe/src/Makefile45
-rw-r--r--mdk-stage1/rp-pppoe/src/Makefile.in257
-rw-r--r--mdk-stage1/rp-pppoe/src/common.c485
-rw-r--r--mdk-stage1/rp-pppoe/src/config.h135
-rw-r--r--mdk-stage1/rp-pppoe/src/config.h.in134
-rwxr-xr-xmdk-stage1/rp-pppoe/src/configure2356
-rw-r--r--mdk-stage1/rp-pppoe/src/configure.in231
-rw-r--r--mdk-stage1/rp-pppoe/src/debug.c143
-rw-r--r--mdk-stage1/rp-pppoe/src/discovery.c629
-rw-r--r--mdk-stage1/rp-pppoe/src/if.c1092
-rwxr-xr-xmdk-stage1/rp-pppoe/src/install-sh238
-rw-r--r--mdk-stage1/rp-pppoe/src/md5.c246
-rw-r--r--mdk-stage1/rp-pppoe/src/md5.h27
-rw-r--r--mdk-stage1/rp-pppoe/src/plugin.c397
-rw-r--r--mdk-stage1/rp-pppoe/src/ppp.c258
-rw-r--r--mdk-stage1/rp-pppoe/src/pppoe-server.c1247
-rw-r--r--mdk-stage1/rp-pppoe/src/pppoe-sniff.c258
-rw-r--r--mdk-stage1/rp-pppoe/src/pppoe.c834
-rw-r--r--mdk-stage1/rp-pppoe/src/pppoe.h331
-rw-r--r--mdk-stage1/rp-pppoe/src/relay.c1541
-rw-r--r--mdk-stage1/rp-pppoe/src/relay.h97
-rw-r--r--mdk-stage1/slang/Makefile42
-rw-r--r--mdk-stage1/slang/_slang.h743
-rw-r--r--mdk-stage1/slang/config.h163
-rw-r--r--mdk-stage1/slang/jdmacros.h53
-rw-r--r--mdk-stage1/slang/keywhash.c190
-rw-r--r--mdk-stage1/slang/sl-feat.h60
-rw-r--r--mdk-stage1/slang/slang.c5547
-rw-r--r--mdk-stage1/slang/slang.h1930
-rw-r--r--mdk-stage1/slang/slarith.c1656
-rw-r--r--mdk-stage1/slang/slarith.inc783
-rw-r--r--mdk-stage1/slang/slarray.c3139
-rw-r--r--mdk-stage1/slang/slarrfun.c464
-rw-r--r--mdk-stage1/slang/slarrfun.inc257
-rw-r--r--mdk-stage1/slang/slarrmis.c38
-rw-r--r--mdk-stage1/slang/slassoc.c713
-rw-r--r--mdk-stage1/slang/slbstr.c615
-rw-r--r--mdk-stage1/slang/slclass.c1391
-rw-r--r--mdk-stage1/slang/slcmd.c351
-rw-r--r--mdk-stage1/slang/slcmplex.c1142
-rw-r--r--mdk-stage1/slang/slcompat.c34
-rw-r--r--mdk-stage1/slang/slcurses.c972
-rw-r--r--mdk-stage1/slang/slcurses.h353
-rw-r--r--mdk-stage1/slang/sldisply.c2596
-rw-r--r--mdk-stage1/slang/slerr.c181
-rw-r--r--mdk-stage1/slang/slerrno.c219
-rw-r--r--mdk-stage1/slang/slgetkey.c306
-rw-r--r--mdk-stage1/slang/slimport.c281
-rw-r--r--mdk-stage1/slang/slinclud.h26
-rw-r--r--mdk-stage1/slang/slintall.c27
-rw-r--r--mdk-stage1/slang/slistruc.c218
-rw-r--r--mdk-stage1/slang/slkeymap.c596
-rw-r--r--mdk-stage1/slang/slkeypad.c163
-rw-r--r--mdk-stage1/slang/sllimits.h64
-rw-r--r--mdk-stage1/slang/slmalloc.c165
-rw-r--r--mdk-stage1/slang/slmath.c565
-rw-r--r--mdk-stage1/slang/slmemchr.c47
-rw-r--r--mdk-stage1/slang/slmemcmp.c76
-rw-r--r--mdk-stage1/slang/slmemcpy.c49
-rw-r--r--mdk-stage1/slang/slmemset.c39
-rw-r--r--mdk-stage1/slang/slmisc.c330
-rw-r--r--mdk-stage1/slang/slnspace.c242
-rw-r--r--mdk-stage1/slang/slospath.c73
-rw-r--r--mdk-stage1/slang/slpack.c785
-rw-r--r--mdk-stage1/slang/slparse.c1970
-rw-r--r--mdk-stage1/slang/slpath.c344
-rw-r--r--mdk-stage1/slang/slposdir.c1057
-rw-r--r--mdk-stage1/slang/slposio.c568
-rw-r--r--mdk-stage1/slang/slprepr.c427
-rw-r--r--mdk-stage1/slang/slproc.c155
-rw-r--r--mdk-stage1/slang/slregexp.c935
-rw-r--r--mdk-stage1/slang/slrline.c836
-rw-r--r--mdk-stage1/slang/slscanf.c718
-rw-r--r--mdk-stage1/slang/slscroll.c450
-rw-r--r--mdk-stage1/slang/slsearch.c239
-rw-r--r--mdk-stage1/slang/slsignal.c336
-rw-r--r--mdk-stage1/slang/slsmg.c1584
-rw-r--r--mdk-stage1/slang/slstd.c724
-rw-r--r--mdk-stage1/slang/slstdio.c1050
-rw-r--r--mdk-stage1/slang/slstring.c546
-rw-r--r--mdk-stage1/slang/slstrops.c1686
-rw-r--r--mdk-stage1/slang/slstruct.c932
-rw-r--r--mdk-stage1/slang/sltermin.c1155
-rw-r--r--mdk-stage1/slang/sltime.c310
-rw-r--r--mdk-stage1/slang/sltoken.c1702
-rw-r--r--mdk-stage1/slang/sltypes.c966
-rw-r--r--mdk-stage1/slang/slutty.c596
-rw-r--r--mdk-stage1/slang/slxstrng.c43
-rw-r--r--mdk-stage1/stage1.c463
-rw-r--r--mdk-stage1/stage1.h62
-rw-r--r--mdk-stage1/stdio-frontend.c357
-rw-r--r--mdk-stage1/sysfs/Makefile39
-rw-r--r--mdk-stage1/sysfs/libsysfs.h90
-rw-r--r--mdk-stage1/sysfs/sysfs.h64
-rw-r--r--mdk-stage1/sysfs/sysfs_attr.c241
-rw-r--r--mdk-stage1/sysfs/sysfs_utils.c59
-rw-r--r--mdk-stage1/thirdparty.c460
-rw-r--r--mdk-stage1/thirdparty.h35
-rw-r--r--mdk-stage1/tools.c361
-rw-r--r--mdk-stage1/tools.h49
-rw-r--r--mdk-stage1/url.c560
-rw-r--r--mdk-stage1/url.h46
-rw-r--r--mdk-stage1/usb-resource/Makefile25
-rwxr-xr-xmdk-stage1/usb-resource/update-usb-ids.pl24
-rw-r--r--mdk-stage1/utils.c191
-rw-r--r--mdk-stage1/utils.h38
-rw-r--r--mdk-stage1/wireless.c160
-rw-r--r--mdk-stage1/wireless.h25
-rw-r--r--mdk-stage1/zlibsupport.c119
-rw-r--r--mdk-stage1/zlibsupport.h11
428 files changed, 161780 insertions, 0 deletions
diff --git a/mdk-stage1/Makefile b/mdk-stage1/Makefile
new file mode 100644
index 000000000..59a5fdbba
--- /dev/null
+++ b/mdk-stage1/Makefile
@@ -0,0 +1,223 @@
+ #******************************************************************************
+ #
+ # mdk-stage1 - the program that will load second-stage install
+ #
+ # $Id: Makefile 260563 2009-09-17 13:02:47Z pterjan $
+ #
+ # Pixel (pixel@mandrakesoft.com) (mostly done by Guillaume Cottenceau)
+ #
+ # Copyright 2000-2004 Mandrakesoft
+ #
+ # This software may be freely redistributed under the terms of the GNU
+ # public license.
+ #
+ # 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.
+
+VERSION=1.32.1
+PRODUCT=drakx-installer-binaries
+
+ #
+ # Portions from Erik Troan (ewt@redhat.com) Copyright 1996 Red Hat Software
+ #
+ #*****************************************************************************
+ #
+ # Currently:
+ #
+ # ix86
+ # init with dietlibc
+ # stage1 with dietlibc
+ #
+ # ppc
+ # init with dietlibc
+ # stage1 with glibc
+ #
+ # ia64
+ # init with glibc
+ # stage1 with glibc
+ #
+ # x86-64
+ # init with dietlibc
+ # stage1 with dietlibc
+ #
+ #*****************************************************************************
+
+
+top_dir = .
+
+include $(top_dir)/Makefile.common
+include $(top_dir)/../Makefile.config
+ARCHDIR=$(ARCH)
+ifeq (i386, $(ARCH))
+ARCHDIR=i586
+endif
+
+DEFS = -DDISTRIB_NAME=\"$(DISTRIB_NAME)\" -DDISTRIB_VERSION=\"$(DISTRIB_VERSION)\" -DDISTRIB_TYPE=\"$(DISTRIB_TYPE)\" -DDISTRIB_DESCR=\"$(DISTRIB_DESCR)\" $(ADDITIONAL_DEFS) -D_FILE_OFFSET_BITS=64 -DARCH=\"$(ARCHDIR)\" -DCONFIG_USE_ZLIB
+
+COMPILE = $(CC) $(DEFS) $(CFLAGS)
+
+INIT_DEFS =
+INITSRC = init.c
+ifneq (DIETLIBC, $(L))
+INIT_DEFS += $(GLIBC_INCLUDES)
+endif
+
+INITOBJS = $(subst .c,.o,$(INITSRC))
+
+
+ #- frontends
+NEWT_FRONTEND_SRC = newt-frontend.c
+NEWT_FRONTEND_LIBS = newt/libnewt.a slang/libslang.a
+
+STDIO_FRONTEND_SRC = stdio-frontend.c
+STDIO_FRONTEND_LIBS =
+STDIO_FRONTEND_LIBS =
+
+
+FRONTEND_OBJS = $(subst .c,.o,$($(F)_FRONTEND_SRC))
+
+FRONTEND_LINK = $(FRONTEND_OBJS) $($(F)_FRONTEND_LIBS)
+
+STAGE1_STATIC_LIBS = libmodprobe.a
+STAGE1_STATIC_USR_LIBS = libz.a libldetect.a libpci.a
+STAGE1_OWN_LIBS =
+ifeq (DIETLIBC, $(L))
+STAGE1_OWN_LIBS = $(patsubst %,/usr/lib/dietlibc/lib-$(ARCH)/%,$(STAGE1_STATIC_USR_LIBS) $(STAGE1_STATIC_LIBS))
+else
+STAGE1_OWN_LIBS = $(patsubst %,/usr/$(LIB)/%,$(STAGE1_STATIC_USR_LIBS)) $(patsubst %,/$(LIB)/%,$(STAGE1_STATIC_LIBS))
+endif
+
+
+ifeq (DIETLIBC, $(L))
+STAGE1_NETWORK_LIBS = /usr/lib/dietlibc/lib-$(ARCH)/librpc.a
+else
+STAGE1_NETWORK_LIBS = /usr/$(LIB)/libresolv.a
+endif
+
+ #- stage1 itself
+STAGE1SRC = stage1.c log.c utils.c params.c tools.c modules.c probing.c mount.c automatic.c frontend-common.c lomount.c thirdparty.c zlibsupport.c
+CDROMSRC = cdrom.c
+DISKSRC = disk.c directory.c partition.c
+NETWORKSRC = network.c nfsmount.c dhcp.c url.c dns.c adsl.c directory.c wireless.c
+KASRC = ka.c
+
+# use sort to remove duplicates
+STAGE1_ALLSRC = $(sort $(STAGE1SRC) $(CDROMSRC) $(DISKSRC) $(NETWORKSRC) $(KASRC))
+ALLSRC = $(INITSRC) $(STAGE1_ALLSRC)
+
+
+
+CDROM_DEFS = -DSPAWN_SHELL -DDISABLE_DISK -DDISABLE_NETWORK
+
+
+STAGE1OBJS-NETWORK = $(subst .c,-NETWORK.o,$(STAGE1SRC) $(NETWORKSRC))
+
+NETWORK_DEFS = -DSPAWN_SHELL -DDISABLE_CDROM -DDISABLE_DISK -DDISABLE_KA
+
+
+STAGE1OBJS-NETWORK-STANDALONE = $(subst .c,-NETWORK-STANDALONE.o,$(STAGE1SRC) $(NETWORKSRC))
+
+NETWORK_STANDALONE_DEFS = -DDISABLE_CDROM -DDISABLE_DISK -DENABLE_NETWORK_STANDALONE -DDISABLE_KA
+
+
+STAGE1OBJS-FULL = $(subst .c,-FULL.o,$(STAGE1_ALLSRC))
+
+BINS = init stage1 dhcp-client rescue-gui probe-modules
+
+DIRS += pci-resource usb-resource slang newt ppp/pppd rp-pppoe/src
+ifeq (i386, $(ARCH))
+DIRS += pcmcia pcmcia-resource sysfs
+endif
+ifeq (x86_64, $(ARCH))
+DIRS += pcmcia pcmcia-resource sysfs
+endif
+
+
+ifeq (i386,$(ARCH))
+PCMCIA_LIB = pcmcia/libpcmcia.a sysfs/libsysfs.a
+PCMCIA_DEFS = -DENABLE_PCMCIA
+endif
+ifeq (x86_64,$(ARCH))
+PCMCIA_LIB = pcmcia/libpcmcia.a sysfs/libsysfs.a
+PCMCIA_DEFS = -DENABLE_PCMCIA
+endif
+
+
+USB_DEFS_GEN = -DENABLE_USB
+USB_DEFS = -DENABLE_USB -DDISABLE_PCIADAPTERS
+
+all: dirs $(BINS)
+
+dirs:
+ @for n in . $(DIRS); do \
+ [ "$$n" = "." ] || make -C $$n || exit 1 ;\
+ done
+
+init: $(INITOBJS) $(STAGE1_LIBC)
+ $(DIET) $(CC) $(LDFLAGS) -o $@ $^
+ $(STRIPCMD) $@
+
+stage1: $(STAGE1OBJS-FULL) $(STAGE1_OWN_LIBS) $(STAGE1_NETWORK_LIBS) $(FRONTEND_LINK) bootsplash.o $(PCMCIA_LIB) $(STAGE1_LIBC)
+ $(DIET) $(CC) $(LDFLAGS) -o $@ $^
+ $(STRIPCMD) $@
+
+dhcp-client: $(STAGE1OBJS-NETWORK-STANDALONE) $(STAGE1_OWN_LIBS) $(STAGE1_NETWORK_LIBS) $(FRONTEND_LINK) $(STAGE1_LIBC)
+ $(DIET) $(CC) $(LDFLAGS) -o $@ $^
+ $(STRIPCMD) $@
+
+
+$(INITOBJS): %.o: %.c
+ $(COMPILE) $(INIT_DEFS) -c $<
+
+$(STAGE1OBJS-NETWORK): %-NETWORK.o: %.c
+ $(DIET) $(COMPILE) $(INCLUDES) $(NETWORK_DEFS) $(PCMCIA_DEFS) $(USB_DEFS_GEN) -DENABLE_ADDITIONAL_MODULES -c $< -o $@
+
+$(STAGE1OBJS-NETWORK-STANDALONE): %-NETWORK-STANDALONE.o: %.c
+ $(DIET) $(COMPILE) $(INCLUDES) $(NETWORK_STANDALONE_DEFS) $(USB_DEFS_GEN) -c $< -o $@
+
+$(STAGE1OBJS-FULL): %-FULL.o: %.c
+ $(DIET) $(COMPILE) $(INCLUDES) -DSPAWN_SHELL $(USB_DEFS_GEN) $(PCMCIA_DEFS) -DENABLE_BOOTSPLASH -c $< -o $@
+
+.c.o:
+ $(DIET) $(COMPILE) $(INCLUDES) -DENABLE_BOOTSPLASH -c $<
+
+
+clean: localclean
+ @for n in $(DIRS); do \
+ (cd $$n; make clean) \
+ done
+
+localclean:
+ rm -f *.o .depend *.rdz *.img $(BINS)
+
+
+rescue-gui: rescue-gui.o frontend-common.o params.o utils.o log.o automatic.o $(FRONTEND_LINK) $(STAGE1_LIBC)
+ $(DIET) $(CC) $(LDFLAGS) -o $@ $^
+ $(STRIPCMD) $@
+
+probe-modules: probe-modules.o probing-FULL.o modules-FULL.o params-FULL.o utils-FULL.o log-FULL.o automatic-FULL.o frontend-common-FULL.o stdio-frontend.o zlibsupport-FULL.o $(STAGE1_OWN_LIBS) $(PCMCIA_LIB) $(STAGE1_LIBC)
+ $(DIET) $(CC) $(LDFLAGS) -o $@ $^
+ $(STRIPCMD) $@
+
+tar:
+ rm -rf $(PRODUCT)*.tar* $(PRODUCT)-$(VERSION)
+ mkdir -p $(PRODUCT)-$(VERSION)
+ svn export -q -rBASE . $(PRODUCT)-$(VERSION)/mdk-stage1
+ svn export -q -rBASE ../kernel $(PRODUCT)-$(VERSION)/kernel
+ cp ../Makefile.config $(PRODUCT)-$(VERSION)/
+ tar cfj $(PRODUCT)-$(VERSION).tar.bz2 $(PRODUCT)-$(VERSION)
+ rm -rf $(PRODUCT)-$(VERSION)
+
+.depend:
+ $(CPP) $(CFLAGS) -M $(ALLSRC) > .depend
+
+ifeq (.depend,$(wildcard .depend))
+include .depend
+endif
+
+
+*-NETWORK.o: %-NETWORK.o: %.o
+
+*-FULL.o: %-FULL.o: %.o
+
diff --git a/mdk-stage1/Makefile.common b/mdk-stage1/Makefile.common
new file mode 100644
index 000000000..f5209a58e
--- /dev/null
+++ b/mdk-stage1/Makefile.common
@@ -0,0 +1,68 @@
+ # -*- makefile -*-
+ #******************************************************************************
+ #
+ # Guillaume Cottenceau (gc@mandrakesoft.com)
+ #
+ # Copyright 2000 Mandrakesoft
+ #
+ # This software may be freely redistributed under the terms of the GNU
+ # public license.
+ #
+ # 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.
+ #
+ #*****************************************************************************
+
+ARCH := $(patsubst i%86,i386,$(shell uname -m))
+ARCH := $(patsubst sparc%,sparc,$(ARCH))
+
+# DEBUG = 1
+
+ #- default frontend is newt (honoured by main Makefile whenever possible)
+ifdef DEBUG
+F = STDIO
+else
+F = NEWT
+endif
+
+DIET = $(shell test -x /usr/bin/diet && echo diet)
+
+ifeq ($(DIET), diet)
+ #- default lib is dietlibc (honoured by main Makefile whenever possible)
+L = DIETLIBC
+else
+L = GLIBC
+endif
+
+ifdef DEBUG
+OPTFLAGS = -g
+else
+OPTFLAGS = -Os
+endif
+
+#- flags used by all stuff
+CFLAGS = $(OPTFLAGS) -pipe -Wall -fomit-frame-pointer -fno-strict-aliasing
+
+ifneq (ppc, $(ARCH))
+ifneq (sparc, $(ARCH))
+CFLAGS += -Werror
+endif
+endif
+
+DIETLIBC_INCLUDES = -I/usr/lib/dietlibc/include -I.
+DIETLIBC_LIBC = /usr/lib/dietlibc/lib-$(ARCH)/libcompat.a
+GLIBC_INCLUDES = -I.
+INCLUDES = $($(L)_INCLUDES)
+
+GLIBC_LDFLAGS = -static
+LDFLAGS = $($(L)_LDFLAGS)
+
+STAGE1_LIBC = $($(L)_LIBC)
+
+ifdef DEBUG
+STRIPCMD = echo not stripping
+else
+STRIPCMD = strip -R .note -R .comment
+endif
+
diff --git a/mdk-stage1/NEWS b/mdk-stage1/NEWS
new file mode 100644
index 000000000..608e5d60b
--- /dev/null
+++ b/mdk-stage1/NEWS
@@ -0,0 +1,131 @@
+1.32.2:
+- fix installing from hard drive on cciss (#57973)
+
+1.32.1:
+- handle virtio
+
+1.32:
+- automatically find compressed stage2 with automatic=method:disk
+
+1.31:
+- usbkbd is dead, using usbhid instead
+
+1.30:
+- add back "ide-generic" support (incorrectly removed in 1.17), the
+ module that we want to avoid is "ide-pci-generic" (previously "generic"),
+ and this is handled by ldetect-lst preferred modules list
+- handle ide-cd being renamed as ide-cd_mod
+
+1.29:
+- allow to pass module options to probe-modules
+- build fixes for gcc 4.3
+
+1.28:
+- fix segfault with empty device description (can happen for USB devices)
+
+1.27.1:
+- fix build
+
+1.27:
+- do not set firmware timeout to 1 second in probe-modules helper for
+ Mandriva One (#39216)
+
+1.26:
+- load bus/firewire controllers (#31356)
+- really ask dhcp domain if not guessed
+
+1.25:
+- do not allow to choose outdated cooker mirror list (#37278)
+
+1.24:
+- load disk/ide before disk/scsi (#38451, to prevent sata deps from
+ overriding non-libata pata modules, like in stage2)
+- fix asking modules when no controller is detected
+
+1.23:
+- probe usb-storage/sbp2 only when probing USB/SCSI buses
+ (to make automatic boot faster on IDE)
+- make dhcp the first choice (instead of static) in the network type menu
+- clear tty2 after shell is killed
+- log "killed shell" message on tty3
+- add a space in front of top line (like help message)
+- space-pad top line with spaces to the right (like help message)
+
+1.22:
+- fix automatic IDE media detection (was broken with multiple CD drives, #36161)
+- fix bootsplash in automatic CD-Rom mode (as a result of IDE media detection fix)
+- wait only 1 second for firmware upload (not to hang boot with iwl3945, #37279)
+
+1.21:
+- load nls_cp437 and nls_iso8859_1 when loading vfat
+ (used to be in custom modules.dep)
+
+1.20:
+- probe-modules:
+ o handle the "--usb" option instead of "usb"
+ o load module passed as argument (if any), instead of probing bus
+- switch to modules from /lib/modules/`uname -r`, modules.dep containing full filename
+
+1.19:
+- rebuild with list_modules to handle atl2 ethernet driver
+
+1.18:
+- add probe-modules helper
+
+1.17:
+- use modules from disk/ide category (#33043)
+- do not explicitely try to load ide-generic, ldetect will fallback to
+ ide-generic when appropriate (#33043)
+
+1.16:
+- if you give nfs directory xxx, try to use xxx/ARCH
+- handle cdroms with and without ARCH at the root
+
+1.15:
+- ask loading modules from /modules if needed
+- read modules description from /modules/modules.description
+
+1.14:
+- fix segfault in USB detection code (when no module match, #32624)
+
+1.13:
+- use module names instead of filenames
+- convert module name to filename before loading it
+ (using modules.dep to get filename)
+- keep module in dependencies list even if it has no dependencies
+ (to keep track of its filename)
+- use '_' in module names when explicitely loading modules (cosmetics)
+
+1.12:
+- adapt to new list_modules
+
+1.11:
+- use ldetect/libmodprobe/libpci instead of custom pci/usb probe
+- rename rescue "GUI" as rescue "menu"
+
+1.10.1:
+- link init with dietlibc instead of minilibc on ix86/x86-64
+- add missing includes for wireless
+- fix build of pppoe by using dietlibc termios header
+
+1.10:
+- add ide-disk module
+- load ide-disk when detecting disks (ide is now modularized...)
+
+1.9:
+- ide is now modularized
+
+1.8:
+- build pcmcia header only on i386/x86_64 (#30668)
+- use api.mandriva.com to retrieve mirror list (#29346)
+
+1.7:
+- don't kill our init/klogd when running stage2
+ (bug introduced when switching to initramfs)
+
+1.6:
+- write DNS settings in temporary ifcfg file
+ (fixes resolv.conf post install)
+
+1.5:
+- fix infinite loop in wired interface mode
diff --git a/mdk-stage1/adsl.c b/mdk-stage1/adsl.c
new file mode 100644
index 000000000..03eeeb9a9
--- /dev/null
+++ b/mdk-stage1/adsl.c
@@ -0,0 +1,183 @@
+/*
+ * Guillaume Cottenceau (gc@mandrakesoft.com)
+ *
+ * Copyright 2000 Mandrakesoft
+ *
+ * This software may be freely redistributed under the terms of the GNU
+ * public license.
+ *
+ * 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.
+ *
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <resolv.h>
+#include <signal.h>
+
+#include "stage1.h"
+#include "log.h"
+#include "network.h"
+#include "modules.h"
+#include "utils.h"
+#include "frontend.h"
+#include "automatic.h"
+
+#include "adsl.h"
+
+
+static enum return_type adsl_connect(struct interface_info * intf, char * username, char * password, char * acname)
+{
+ char pppoe_call[500];
+ char * pppd_launch[] = { "/sbin/pppd", "pty", pppoe_call, "noipdefault", "noauth", "default-asyncmap", "defaultroute",
+ "hide-password", "nodetach", "usepeerdns", "local", "mtu", "1492", "mru", "1492", "noaccomp",
+ "noccp", "nobsdcomp", "nodeflate", "nopcomp", "novj", "novjccomp", "user", username,
+ "password", password, "lcp-echo-interval", "20", "lcp-echo-failure", "3", "lock", "persist", NULL };
+ int fd;
+ int retries = 10;
+ char * tty_adsl = "/dev/tty6";
+ enum return_type status = RETURN_ERROR;
+ pid_t ppp_pid;
+
+ snprintf(pppoe_call, sizeof(pppoe_call), "/sbin/pppoe -p /var/run/pppoe.conf-adsl.pid.pppoe -I %s -T 80 -U -m 1412", intf->device);
+
+ if (!streq(acname, "")) {
+ strcat(pppoe_call, "-C ");
+ strcat(pppoe_call, acname);
+ }
+
+ fd = open(tty_adsl, O_RDWR);
+ if (fd == -1) {
+ log_message("cannot open tty -- no pppd");
+ return RETURN_ERROR;
+ }
+ else if (access(pppd_launch[0], X_OK)) {
+ log_message("cannot open pppd - %s doesn't exist", pppd_launch[0]);
+ return RETURN_ERROR;
+ }
+
+ if (!(ppp_pid = fork())) {
+ dup2(fd, 0);
+ dup2(fd, 1);
+ dup2(fd, 2);
+
+ close(fd);
+ setsid();
+ if (ioctl(0, TIOCSCTTY, NULL))
+ log_perror("could not set new controlling tty");
+
+ printf("\t(exec of pppd)\n");
+ execv(pppd_launch[0], pppd_launch);
+ log_message("execve of %s failed: %s", pppd_launch[0], strerror(errno));
+ exit(-1);
+ }
+ close(fd);
+ while (retries > 0 && kill(ppp_pid, 0) == 0) {
+ FILE * f;
+ if ((f = fopen("/var/run/pppd.tdb", "rb"))) {
+ while (1) {
+ char buf[500];
+ char *p;
+ if (!fgets(buf, sizeof(buf), f))
+ break;
+ p = strstr(buf, "IPLOCAL=");
+ if (p) {
+ struct sockaddr_in addr;
+ if (inet_aton(p + 8, &addr.sin_addr))
+ intf->ip = addr.sin_addr;
+ status = RETURN_OK;
+ }
+ }
+ fclose(f);
+ if (status == RETURN_OK) {
+ log_message("PPP: connected!");
+ break;
+ }
+ }
+ retries--;
+ log_message("PPP: <sleep>");
+ sleep(2);
+ }
+
+ if (status != RETURN_OK) {
+ log_message("PPP: could not connect");
+ kill(ppp_pid, SIGTERM);
+ sleep(1);
+ kill(ppp_pid, SIGKILL);
+ sleep(1);
+ }
+ return status;
+}
+
+
+enum return_type perform_adsl(struct interface_info * intf)
+{
+ struct in_addr addr;
+ char * questions[] = { "Username", "Password", "AC Name", NULL };
+ char * questions_auto[] = { "adsluser", "adslpass", "adslacname", NULL };
+ static char ** answers = NULL;
+ enum return_type results;
+
+ inet_aton("10.0.0.10", &addr);
+ memcpy(&intf->ip, &addr, sizeof(addr));
+
+ inet_aton("255.255.255.0", &addr);
+ memcpy(&intf->netmask, &addr, sizeof(addr));
+
+ *((uint32_t *) &intf->broadcast) = (*((uint32_t *) &intf->ip) &
+ *((uint32_t *) &intf->netmask)) | ~(*((uint32_t *) &intf->netmask));
+
+ intf->is_ptp = 0;
+
+ if (configure_net_device(intf)) {
+ stg1_error_message("Could not configure..");
+ return RETURN_ERROR;
+ }
+
+ results = ask_from_entries_auto("Please enter the username and password for your ADSL account.\n"
+ "Leave blank the AC Name field if you don't know what it means.\n"
+ "(Warning! only PPPoE protocol is supported)",
+ questions, &answers, 40, questions_auto, NULL);
+ if (results != RETURN_OK)
+ return results;
+
+ intf->boot_proto = BOOTPROTO_ADSL_PPPOE;
+
+ wait_message("Waiting for ADSL connection to show up...");
+ my_insmod("ppp_generic", ANY_DRIVER_TYPE, NULL, 1);
+ my_insmod("ppp_async", ANY_DRIVER_TYPE, NULL, 1);
+ results = adsl_connect(intf, answers[0], answers[1], answers[2]);
+ remove_wait_message();
+
+ if (results != RETURN_OK) {
+ wait_message("Retrying the ADSL connection...");
+ results = adsl_connect(intf, answers[0], answers[1], answers[2]);
+ remove_wait_message();
+ } else {
+ intf->user = strdup(answers[0]);
+ intf->pass = strdup(answers[1]);
+ intf->acname = strdup(answers[2]);
+ }
+
+ if (results != RETURN_OK) {
+ stg1_error_message("I could not connect to the ADSL network.");
+ return perform_adsl(intf);
+ }
+
+ sleep(1);
+ res_init(); /* reinit the resolver, pppd modified /etc/resolv.conf */
+
+ return RETURN_OK;
+}
diff --git a/mdk-stage1/adsl.h b/mdk-stage1/adsl.h
new file mode 100644
index 000000000..fb0baf327
--- /dev/null
+++ b/mdk-stage1/adsl.h
@@ -0,0 +1,34 @@
+/*
+ * Guillaume Cottenceau (gc@mandrakesoft.com)
+ *
+ * Copyright 2000 Mandrakesoft
+ *
+ * View the homepage: http://us.mandrakesoft.com/~gc/html/stage1.html
+ *
+ *
+ * This software may be freely redistributed under the terms of the GNU
+ * public license.
+ *
+ * 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.
+ *
+ */
+
+/*
+ * Portions from GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2000 Free Software Foundation, Inc.
+ *
+ * Itself based on etherboot-4.6.4 by Martin Renters.
+ *
+ */
+
+#ifndef _ADSL_H_
+#define _ADSL_H_
+
+#include "stage1.h"
+#include "network.h"
+
+enum return_type perform_adsl(struct interface_info * intf);
+
+#endif
diff --git a/mdk-stage1/automatic.c b/mdk-stage1/automatic.c
new file mode 100644
index 000000000..e5c909624
--- /dev/null
+++ b/mdk-stage1/automatic.c
@@ -0,0 +1,166 @@
+/*
+ * Guillaume Cottenceau (gc@mandrakesoft.com)
+ *
+ * Copyright 2000 Mandrakesoft
+ *
+ * This software may be freely redistributed under the terms of the GNU
+ * public license.
+ *
+ * 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.
+ *
+ */
+
+/*
+ * This is supposed to replace the redhat "kickstart", by name but
+ * also by design (less code pollution).
+ *
+ */
+
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include "tools.h"
+#include "utils.h"
+#include "stage1.h"
+#include "frontend.h"
+#include "log.h"
+
+#include "automatic.h"
+
+
+static struct param_elem * automatic_params;
+static char * value_not_bound = "";
+
+void grab_automatic_params(char * line)
+{
+ int i, p;
+ struct param_elem tmp_params[50];
+
+ i = 0; p = 0;
+ while (line[i] != '\0') {
+ char *name, *value;
+ int k;
+ int j = i;
+ while (line[i] != ':' && line[i] != '\0')
+ i++;
+ name = memdup(&line[j], i-j + 1);
+ name[i-j] = 0;
+
+ k = i+1;
+ i++;
+ while (line[i] != ',' && line[i] != '\0')
+ i++;
+ value = memdup(&line[k], i-k + 1);
+ value[i-k] = 0;
+
+ tmp_params[p].name = name;
+ tmp_params[p].value = value;
+ p++;
+ if (line[i] == '\0')
+ break;
+ i++;
+ }
+
+ tmp_params[p++].name = NULL;
+ automatic_params = memdup(tmp_params, sizeof(struct param_elem) * p);
+
+ log_message("AUTOMATIC MODE: got %d params", p-1);
+}
+
+
+char * get_auto_value(char * auto_param)
+{
+ struct param_elem * ptr = automatic_params;
+
+ struct param_elem short_aliases[] =
+ { { "method", "met" }, { "network", "netw" }, { "interface", "int" }, { "gateway", "gat" },
+ { "netmask", "netm" }, { "adsluser", "adslu" }, { "adslpass", "adslp" }, { "hostname", "hos" },
+ { "domain", "dom" }, { "server", "ser" }, { "directory", "dir" }, { "user", "use" },
+ { "pass", "pas" }, { "disk", "dis" }, { "partition", "par" }, { "proxy_host", "proxh" },
+ { "proxy_port", "proxp" }, { NULL, NULL } };
+ struct param_elem * ptr_alias = short_aliases;
+ while (ptr_alias->name) {
+ if (streq(auto_param, ptr_alias->name))
+ break;
+ ptr_alias++;
+ }
+
+ while (ptr->name) {
+ if (streq(ptr->name, auto_param)
+ || (ptr_alias->name && streq(ptr_alias->value, ptr->name)))
+ return ptr->value;
+ ptr++;
+ }
+
+ return value_not_bound;
+}
+
+
+enum return_type ask_from_list_auto(char *msg, char ** elems, char ** choice, char * auto_param, char ** elems_auto)
+{
+ if (!IS_AUTOMATIC) {
+ exit_bootsplash();
+ return ask_from_list(msg, elems, choice);
+ } else {
+ char ** sav_elems = elems;
+ char * tmp = get_auto_value(auto_param);
+ while (elems && *elems) {
+ if (!strcmp(tmp, *elems_auto)) {
+ *choice = *elems;
+ log_message("AUTOMATIC: parameter %s for %s means returning %s", tmp, auto_param, *elems);
+ return RETURN_OK;
+ }
+ elems++;
+ elems_auto++;
+ }
+ unset_automatic(); /* we are in a fallback mode */
+ return ask_from_list(msg, sav_elems, choice);
+ }
+}
+
+enum return_type ask_from_list_comments_auto(char *msg, char ** elems, char ** elems_comments, char ** choice, char * auto_param, char ** elems_auto)
+{
+ if (!IS_AUTOMATIC) {
+ exit_bootsplash();
+ return ask_from_list_comments(msg, elems, elems_comments, choice);
+ } else {
+ char ** sav_elems = elems;
+ char * tmp = get_auto_value(auto_param);
+ while (elems && *elems) {
+ if (!strcmp(tmp, *elems_auto)) {
+ *choice = *elems;
+ log_message("AUTOMATIC: parameter %s for %s means returning %s", tmp, auto_param, *elems);
+ return RETURN_OK;
+ }
+ elems++;
+ elems_auto++;
+ }
+ unset_automatic(); /* we are in a fallback mode */
+ return ask_from_list_comments(msg, sav_elems, elems_comments, choice);
+ }
+}
+
+
+enum return_type ask_from_entries_auto(char *msg, char ** questions, char *** answers, int entry_size, char ** questions_auto, void (*callback_func)(char ** strings))
+{
+ if (!IS_AUTOMATIC) {
+ exit_bootsplash();
+ return ask_from_entries(msg, questions, answers, entry_size, callback_func);
+ } else {
+ char * tmp_answers[50];
+ int i = 0;
+ while (questions && *questions) {
+ tmp_answers[i] = get_auto_value(*questions_auto);
+ log_message("AUTOMATIC: question %s answers %s because of param %s", *questions, tmp_answers[i], *questions_auto);
+ i++;
+ questions++;
+ questions_auto++;
+
+ }
+ *answers = memdup(tmp_answers, sizeof(char *) * i);
+ return RETURN_OK;
+ }
+}
diff --git a/mdk-stage1/automatic.h b/mdk-stage1/automatic.h
new file mode 100644
index 000000000..a5bfe212b
--- /dev/null
+++ b/mdk-stage1/automatic.h
@@ -0,0 +1,33 @@
+/*
+ * Guillaume Cottenceau (gc@mandrakesoft.com)
+ *
+ * Copyright 2000 Mandrakesoft
+ *
+ * This software may be freely redistributed under the terms of the GNU
+ * public license.
+ *
+ * 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.
+ *
+ */
+
+/*
+ * This is supposed to replace the redhat "kickstart", by name but
+ * also by design (no code pollution).
+ *
+ */
+
+#ifndef _AUTOMATIC_H_
+#define _AUTOMATIC_H_
+
+#include "stage1.h"
+
+void grab_automatic_params(char * line);
+char * get_auto_value(char * auto_param);
+
+enum return_type ask_from_list_auto(char *msg, char ** elems, char ** choice, char * auto_param, char ** elems_auto);
+enum return_type ask_from_list_comments_auto(char *msg, char ** elems, char ** elems_comments, char ** choice, char * auto_param, char ** elems_auto);
+enum return_type ask_from_entries_auto(char *msg, char ** questions, char *** answers, int entry_size, char ** questions_auto, void (*callback_func)(char ** strings));
+
+#endif
diff --git a/mdk-stage1/bootsplash.c b/mdk-stage1/bootsplash.c
new file mode 100644
index 000000000..d51deb543
--- /dev/null
+++ b/mdk-stage1/bootsplash.c
@@ -0,0 +1,70 @@
+/*
+ * Pixel (pixel@mandrakesoft.com)
+ *
+ * Copyright 2004 Mandrakesoft
+ *
+ * This software may be freely redistributed under the terms of the GNU
+ * public license.
+ *
+ * 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.
+ *
+ */
+
+#include <stdio.h>
+#include "bootsplash.h"
+#include "frontend.h"
+#include "log.h"
+
+static int total_size;
+static float previous;
+static FILE* splash = NULL;
+
+static void update_progression_only(int current_size)
+{
+ if (splash && total_size) {
+ float ratio = (float) (current_size + 1) / total_size;
+ if (ratio > previous + 0.01) {
+ fprintf(splash, "show %d\n", (int) (ratio * 65534));
+ fflush(splash);
+ previous = ratio;
+ }
+ }
+}
+
+static void open_bootsplash(void)
+{
+ if (!splash) splash = fopen("/proc/splash", "w");
+ if (!splash) log_message("opening /proc/splash failed");
+}
+
+void exit_bootsplash(void)
+{
+ log_message("exiting bootsplash");
+ open_bootsplash();
+ if (splash) {
+ fprintf(splash, "verbose\n");
+ fflush(splash);
+ }
+}
+
+
+void init_progression(char *msg, int size)
+{
+ previous = 0; total_size = size;
+ open_bootsplash();
+ update_progression_only(0);
+ init_progression_raw(msg, size);
+}
+
+void update_progression(int current_size)
+{
+ update_progression_only(current_size);
+ update_progression_raw(current_size);
+}
+
+void end_progression(void)
+{
+ end_progression_raw();
+}
diff --git a/mdk-stage1/bootsplash.h b/mdk-stage1/bootsplash.h
new file mode 100644
index 000000000..7d1c8403c
--- /dev/null
+++ b/mdk-stage1/bootsplash.h
@@ -0,0 +1,25 @@
+/*
+ * Pixel (pixel@mandrakesoft.com)
+ *
+ * Copyright 2004 Mandrakesoft
+ *
+ * This software may be freely redistributed under the terms of the GNU
+ * public license.
+ *
+ * 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.
+ *
+ */
+
+#ifndef _BOOTSPLASH_H_
+#define _BOOTSPLASH_H_
+
+#ifdef ENABLE_BOOTSPLASH
+void exit_bootsplash(void);
+void tell_bootsplash(char *cmd);
+#else
+#define exit_bootsplash()
+#endif
+
+#endif
diff --git a/mdk-stage1/cdrom.c b/mdk-stage1/cdrom.c
new file mode 100644
index 000000000..f87307499
--- /dev/null
+++ b/mdk-stage1/cdrom.c
@@ -0,0 +1,219 @@
+/*
+ * Guillaume Cottenceau (gc@mandrakesoft.com)
+ *
+ * Copyright 2000 Mandrakesoft
+ *
+ * This software may be freely redistributed under the terms of the GNU
+ * public license.
+ *
+ * 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.
+ *
+ */
+
+/*
+ * Portions from Erik Troan (ewt@redhat.com)
+ *
+ * Copyright 1996 Red Hat Software
+ *
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdio.h>
+#include <sys/mount.h>
+#include "stage1.h"
+#include "frontend.h"
+#include "modules.h"
+#include "probing.h"
+#include "log.h"
+#include "mount.h"
+#include "tools.h"
+#include "utils.h"
+
+#include "cdrom.h"
+
+
+static int mount_that_cd_device(char * dev_name)
+{
+ char device_fullname[50];
+ int mount_result;
+
+ snprintf(device_fullname, sizeof(device_fullname), "/dev/%s", dev_name);
+
+ mount_result = my_mount(device_fullname, MEDIA_LOCATION, "iso9660", 0);
+
+ create_IMAGE_LOCATION(MEDIA_LOCATION);
+
+ return mount_result;
+}
+
+
+static enum return_type try_with_device(char * dev_name, char * dev_model);
+
+static enum return_type do_with_device(char * dev_name, char * dev_model)
+{
+ if (!image_has_stage2()) {
+ enum return_type results;
+ umount(MEDIA_LOCATION);
+ results = ask_yes_no("That CDROM disc does not seem to be a " DISTRIB_NAME " Installation CDROM.\nRetry with another disc?");
+ if (results == RETURN_OK)
+ return try_with_device(dev_name, dev_model);
+ return results;
+ }
+
+ log_message("found a " DISTRIB_NAME " CDROM, good news!");
+
+ may_load_compressed_image();
+
+ if (!KEEP_MOUNTED)
+ /* in rescue mode, we don't need the media anymore */
+ umount(MEDIA_LOCATION);
+
+ add_to_env("METHOD", "cdrom");
+ return RETURN_OK;
+}
+
+static enum return_type try_with_device(char * dev_name, char * dev_model)
+{
+ wait_message("Trying to access a CDROM disc (drive %s)", dev_model);
+
+ if (mount_that_cd_device(dev_name) == -1) {
+ enum return_type results;
+ char msg[500];
+ unset_automatic(); /* we are in a fallback mode */
+ remove_wait_message();
+
+ snprintf(msg, sizeof(msg), "I can't access a " DISTRIB_NAME " Installation disc in your CDROM drive (%s).\nRetry?", dev_model);
+ results = ask_yes_no(msg);
+ if (results == RETURN_OK)
+ return try_with_device(dev_name, dev_model);
+ return results;
+ }
+ remove_wait_message();
+
+ return do_with_device(dev_name, dev_model);
+}
+
+int try_automatic(char ** medias, char ** medias_models)
+{
+ static char * already_tried[50] = { NULL };
+ char ** model = medias_models;
+ char ** ptr = medias;
+ int i = 0;
+ while (ptr && *ptr) {
+ char ** p;
+ for (p = already_tried; p && *p; p++)
+ if (streq(*p, *ptr))
+ goto try_automatic_already_tried;
+ *p = strdup(*ptr);
+ *(p+1) = NULL;
+
+ wait_message("Trying to access " DISTRIB_NAME " CDROM disc (drive %s)", *model);
+ if (mount_that_cd_device(*ptr) != -1) {
+ if (image_has_stage2()) {
+ remove_wait_message();
+ return i;
+ }
+ else
+ umount(MEDIA_LOCATION);
+ }
+ remove_wait_message();
+
+ try_automatic_already_tried:
+ ptr++;
+ model++;
+ i++;
+ }
+ return -1;
+}
+
+enum return_type cdrom_prepare(void)
+{
+ char ** medias, ** ptr, ** medias_models;
+ char * choice;
+ int i, count = 0;
+ enum return_type results;
+ static int already_probed_ide_generic = 0;
+
+ my_insmod("ide_cd_mod", ANY_DRIVER_TYPE, NULL, 0);
+
+ if (IS_AUTOMATIC) {
+ get_medias(CDROM, &medias, &medias_models, BUS_IDE);
+ if ((i = try_automatic(medias, medias_models)) != -1)
+ return do_with_device(medias[i], medias_models[i]);
+
+ get_medias(CDROM, &medias, &medias_models, BUS_PCMCIA);
+ if ((i = try_automatic(medias, medias_models)) != -1)
+ return do_with_device(medias[i], medias_models[i]);
+
+ my_insmod("sr_mod", ANY_DRIVER_TYPE, NULL, 0);
+ get_medias(CDROM, &medias, &medias_models, BUS_SCSI);
+ if ((i = try_automatic(medias, medias_models)) != -1)
+ return do_with_device(medias[i], medias_models[i]);
+
+ get_medias(CDROM, &medias, &medias_models, BUS_USB);
+ if ((i = try_automatic(medias, medias_models)) != -1)
+ return do_with_device(medias[i], medias_models[i]);
+
+ unset_automatic();
+ } else
+ my_insmod("sr_mod", ANY_DRIVER_TYPE, NULL, 0);
+
+
+ get_medias(CDROM, &medias, &medias_models, BUS_ANY);
+ ptr = medias;
+ while (ptr && *ptr) {
+ count++;
+ ptr++;
+ }
+
+ if (count == 0) {
+ if (!already_probed_ide_generic) {
+ already_probed_ide_generic = 1;
+ my_insmod("ide_generic", ANY_DRIVER_TYPE, NULL, 0);
+ return cdrom_prepare();
+ }
+ stg1_error_message("No CDROM device found.");
+ i = ask_insmod(MEDIA_ADAPTERS);
+ if (i == RETURN_BACK)
+ return RETURN_BACK;
+ return cdrom_prepare();
+ }
+
+ if (count == 1) {
+ results = try_with_device(*medias, *medias_models);
+ if (results == RETURN_OK)
+ return RETURN_OK;
+ i = ask_insmod(MEDIA_ADAPTERS);
+ if (i == RETURN_BACK)
+ return RETURN_BACK;
+ return cdrom_prepare();
+ }
+
+ results = ask_from_list_comments("Please choose the CDROM drive to use for the installation.", medias, medias_models, &choice);
+ if (results == RETURN_OK) {
+ char ** model = medias_models;
+ ptr = medias;
+ while (ptr && *ptr && model && *model) {
+ if (!strcmp(*ptr, choice))
+ break;
+ ptr++;
+ model++;
+ }
+ results = try_with_device(choice, *model);
+ } else
+ return results;
+
+ if (results == RETURN_OK)
+ return RETURN_OK;
+ if (results == RETURN_BACK)
+ return cdrom_prepare();
+
+ i = ask_insmod(MEDIA_ADAPTERS);
+ if (i == RETURN_BACK)
+ return RETURN_BACK;
+ return cdrom_prepare();
+}
diff --git a/mdk-stage1/cdrom.h b/mdk-stage1/cdrom.h
new file mode 100644
index 000000000..c9ebc78aa
--- /dev/null
+++ b/mdk-stage1/cdrom.h
@@ -0,0 +1,29 @@
+/*
+ * Guillaume Cottenceau (gc@mandrakesoft.com)
+ *
+ * Copyright 2000 Mandrakesoft
+ *
+ * This software may be freely redistributed under the terms of the GNU
+ * public license.
+ *
+ * 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.
+ *
+ */
+
+/*
+ * Portions from Erik Troan (ewt@redhat.com)
+ *
+ * Copyright 1996 Red Hat Software
+ *
+ */
+
+#ifndef _CDROM_H_
+#define _CDROM_H_
+
+#include "stage1.h"
+
+enum return_type cdrom_prepare(void);
+
+#endif
diff --git a/mdk-stage1/config-stage1.h b/mdk-stage1/config-stage1.h
new file mode 100644
index 000000000..f668a465b
--- /dev/null
+++ b/mdk-stage1/config-stage1.h
@@ -0,0 +1,82 @@
+/*
+ * Guillaume Cottenceau (gc@mandrakesoft.com)
+ *
+ * Copyright 2000 Mandrakesoft
+ *
+ * This software may be freely redistributed under the terms of the GNU
+ * public license.
+ *
+ * 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.
+ *
+ */
+
+#ifndef _CONFIG_STAGE1_H_
+#define _CONFIG_STAGE1_H_
+
+#ifdef _GNU_SOURCE
+# undef _GNU_SOURCE
+#endif
+#define _GNU_SOURCE 1
+
+
+/* If we have more than that amount of memory (in Mbytes), we assume we can load the second stage as a ramdisk */
+#define MEM_LIMIT_DRAKX 68
+/* If we have more than that amount of memory (in Mbytes), we preload the second stage as a ramdisk */
+#define MEM_LIMIT_DRAKX_PRELOAD 100
+
+/* If we have more than that amount of memory (in Mbytes), we assume we can load the rescue as a ramdisk */
+#define MEM_LIMIT_RESCUE 40
+/* If we have more than that amount of memory (in Mbytes), we preload the rescue as a ramdisk */
+#define MEM_LIMIT_RESCUE_PRELOAD 100
+
+#define KA_MAX_RETRY 5
+
+#define LIVE_LOCATION_REL "install/stage2/live/"
+#define COMPRESSED_LOCATION_REL "install/stage2/"
+#define COMPRESSED_STAGE2_NAME "mdkinst.sqfs"
+#define COMPRESSED_RESCUE_NAME "rescue.sqfs"
+#define COMPRESSED_NAME(prefix) (IS_RESCUE ? prefix COMPRESSED_RESCUE_NAME : prefix COMPRESSED_STAGE2_NAME)
+#define COMPRESSED_FILE_REL(prefix) COMPRESSED_NAME(prefix COMPRESSED_LOCATION_REL)
+
+/* the remote media is mounted in MEDIA_LOCATION, and
+ - IMAGE_LOCATION is a symlink image -> image/mdk/mirror/dir
+ - IMAGE_LOCATION is a symlink image -> loop/i586 and iso file is loopback mounted in LOOP_LOCATION
+ */
+#define MEDIA_LOCATION_REL "media"
+#define MEDIA_LOCATION IMAGE_LOCATION_DIR MEDIA_LOCATION_REL
+
+#define LOOP_LOCATION_REL "loop"
+#define LOOP_LOCATION IMAGE_LOCATION_DIR LOOP_LOCATION_REL
+
+#define IMAGE_LOCATION_REL "image"
+#define IMAGE_LOCATION_DIR "/tmp/"
+#define IMAGE_LOCATION IMAGE_LOCATION_DIR IMAGE_LOCATION_REL
+
+#define COMPRESSED_LOCATION IMAGE_LOCATION "/" COMPRESSED_LOCATION_REL
+
+/* - if we use a compressed image : STAGE2_LOCATION is a the mount point
+ - if we use the live: STAGE2_LOCATION is a relative symlink to image/install/stage2/live
+*/
+#define STAGE2_LOCATION "/tmp/stage2"
+
+
+/* user-definable (in Makefile): DISABLE_NETWORK, DISABLE_DISK, DISABLE_CDROM, DISABLE_PCMCIA */
+
+
+/* some factorizing for disabling more features */
+
+#ifdef DISABLE_DISK
+#ifdef DISABLE_CDROM
+#define DISABLE_MEDIAS
+#endif
+#endif
+
+/* path to mirror list for net install */
+#ifndef DISABLE_NETWORK
+#define MIRRORLIST_HOST "api.mandriva.com"
+#define MIRRORLIST_PATH "/mirrors"
+#endif
+
+#endif
diff --git a/mdk-stage1/dhcp.c b/mdk-stage1/dhcp.c
new file mode 100644
index 000000000..fccb400e1
--- /dev/null
+++ b/mdk-stage1/dhcp.c
@@ -0,0 +1,678 @@
+/*
+ * Guillaume Cottenceau (gc@mandrakesoft.com)
+ *
+ * Copyright 2000 Mandrakesoft
+ *
+ * This software may be freely redistributed under the terms of the GNU
+ * public license.
+ *
+ * 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.
+ *
+ */
+
+/*
+ * Portions from Erik Troan (ewt@redhat.com)
+ *
+ * Copyright 1996 Red Hat Software
+ *
+ */
+
+/*
+ * Portions from GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2000 Free Software Foundation, Inc.
+ */
+
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include <arpa/inet.h>
+#include <net/route.h>
+#include <errno.h>
+#include <net/ethernet.h>
+#include <netinet/ip.h>
+#include <netinet/udp.h>
+#include <sys/time.h>
+#include <time.h>
+#include <fcntl.h>
+#include <sys/poll.h>
+
+#include "stage1.h"
+#include "log.h"
+#include "tools.h"
+#include "utils.h"
+#include "network.h"
+#include "frontend.h"
+#include "automatic.h"
+
+#include "dhcp.h"
+
+
+typedef int bp_int32;
+typedef short bp_int16;
+
+#define BOOTP_OPTION_NETMASK 1
+#define BOOTP_OPTION_GATEWAY 3
+#define BOOTP_OPTION_DNS 6
+#define BOOTP_OPTION_HOSTNAME 12
+#define BOOTP_OPTION_DOMAIN 15
+#define BOOTP_OPTION_BROADCAST 28
+
+#define DHCP_OPTION_REQADDR 50
+#define DHCP_OPTION_LEASE 51
+#define DHCP_OPTION_TYPE 53
+#define DHCP_OPTION_SERVER 54
+#define DHCP_OPTION_OPTIONREQ 55
+#define DHCP_OPTION_MAXSIZE 57
+
+#define DHCP_OPTION_CLIENT_IDENTIFIER 61
+
+#define BOOTP_CLIENT_PORT 68
+#define BOOTP_SERVER_PORT 67
+
+#define BOOTP_OPCODE_REQUEST 1
+#define BOOTP_OPCODE_REPLY 2
+
+#define DHCP_TYPE_DISCOVER 1
+#define DHCP_TYPE_OFFER 2
+#define DHCP_TYPE_REQUEST 3
+#define DHCP_TYPE_ACK 5
+#define DHCP_TYPE_RELEASE 7
+
+#define BOOTP_VENDOR_LENGTH 64
+#define DHCP_VENDOR_LENGTH 340
+
+struct bootp_request {
+ char opcode;
+ char hw;
+ char hwlength;
+ char hopcount;
+ bp_int32 id;
+ bp_int16 secs;
+ bp_int16 flags;
+ bp_int32 ciaddr, yiaddr, server_ip, bootp_gw_ip;
+ char hwaddr[16];
+ char servername[64];
+ char bootfile[128];
+ char vendor[DHCP_VENDOR_LENGTH];
+} ;
+
+static const char vendor_cookie[] = { 99, 130, 83, 99, 255 };
+
+
+static unsigned int verify_checksum(void * buf2, int length2)
+{
+ unsigned int csum = 0;
+ unsigned short * sp;
+
+ for (sp = (unsigned short *) buf2; length2 > 0; (length2 -= 2), sp++)
+ csum += *sp;
+
+ while (csum >> 16)
+ csum = (csum & 0xffff) + (csum >> 16);
+
+ return (csum == 0xffff);
+}
+
+
+static int initial_setup_interface(char * device, int s) {
+ struct sockaddr_in * addrp;
+ struct ifreq req;
+ struct rtentry route;
+ int true = 1;
+
+ addrp = (struct sockaddr_in *) &req.ifr_addr;
+
+ strcpy(req.ifr_name, device);
+ addrp->sin_family = AF_INET;
+ addrp->sin_port = 0;
+ memset(&addrp->sin_addr, 0, sizeof(addrp->sin_addr));
+
+ req.ifr_flags = 0; /* take it down */
+ if (ioctl(s, SIOCSIFFLAGS, &req)) {
+ log_perror("SIOCSIFFLAGS (downing)");
+ return -1;
+ }
+
+ addrp->sin_family = AF_INET;
+ addrp->sin_addr.s_addr = htonl(0);
+ if (ioctl(s, SIOCSIFADDR, &req)) {
+ log_perror("SIOCSIFADDR");
+ return -1;
+ }
+
+ req.ifr_flags = IFF_UP | IFF_BROADCAST | IFF_RUNNING;
+ if (ioctl(s, SIOCSIFFLAGS, &req)) {
+ log_perror("SIOCSIFFLAGS (upping)");
+ return -1;
+ }
+
+ memset(&route, 0, sizeof(route));
+ memcpy(&route.rt_gateway, addrp, sizeof(*addrp));
+
+ addrp->sin_family = AF_INET;
+ addrp->sin_port = 0;
+ addrp->sin_addr.s_addr = INADDR_ANY;
+ memcpy(&route.rt_dst, addrp, sizeof(*addrp));
+ memcpy(&route.rt_genmask, addrp, sizeof(*addrp));
+
+ route.rt_dev = device;
+ route.rt_flags = RTF_UP;
+ route.rt_metric = 0;
+
+ if (ioctl(s, SIOCADDRT, &route)) {
+ if (errno != EEXIST) {
+ close(s);
+ log_perror("SIOCADDRT");
+ return -1;
+ }
+ }
+
+ if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &true, sizeof(true))) {
+ close(s);
+ log_perror("setsockopt");
+ return -1;
+ }
+
+ /* I need to sleep a bit in order for kernel to finish init of the
+ network device; this would allow to not send further multiple
+ dhcp requests when only one is needed. */
+ wait_message("Bringing up networking...");
+ sleep(2);
+ remove_wait_message();
+
+ return 0;
+}
+
+
+void set_missing_ip_info(struct interface_info * intf)
+{
+ bp_int32 ipNum = *((bp_int32 *) &intf->ip);
+ bp_int32 nmNum;
+
+ if (intf->netmask.s_addr == 0)
+ inet_aton(guess_netmask(inet_ntoa(intf->ip)), &intf->netmask);
+
+ nmNum = *((bp_int32 *) &intf->netmask);
+
+ if (intf->broadcast.s_addr == 0)
+ *((bp_int32 *) &intf->broadcast) = (ipNum & nmNum) | ~(nmNum);
+
+ if (intf->network.s_addr == 0)
+ *((bp_int32 *) &intf->network) = ipNum & nmNum;
+}
+
+static void parse_reply(struct bootp_request * breq, struct interface_info * intf)
+{
+ unsigned char * chptr;
+ unsigned char option, length;
+
+ if (breq->bootfile && strlen(breq->bootfile) > 0) {
+ if (IS_NETAUTO)
+ add_to_env("KICKSTART", breq->bootfile);
+ else
+ log_message("warning: ignoring `bootfile' DHCP server parameter, since `netauto' boot parameter was not given; reboot with `linux netauto' (and anymore useful boot parameters) if you want `bootfile' to be used as a `auto_inst.cfg.pl' stage2 configuration file");
+ }
+
+ memcpy(&intf->ip, &breq->yiaddr, 4);
+
+ chptr = (unsigned char *) breq->vendor;
+ chptr += 4;
+ while (*chptr != 0xFF && (void *) chptr < (void *) breq->vendor + DHCP_VENDOR_LENGTH) {
+ char tmp_str[500];
+ option = *chptr++;
+ if (!option)
+ continue;
+ length = *chptr++;
+
+ switch (option) {
+ case BOOTP_OPTION_DNS:
+ memcpy(&dns_server, chptr, sizeof(dns_server));
+ log_message("got dns %s", inet_ntoa(dns_server));
+ if (length >= sizeof(dns_server)*2) {
+ memcpy(&dns_server2, chptr+sizeof(dns_server), sizeof(dns_server2));
+ log_message("got dns2 %s", inet_ntoa(dns_server2));
+ }
+ break;
+
+ case BOOTP_OPTION_NETMASK:
+ memcpy(&intf->netmask, chptr, sizeof(intf->netmask));
+ log_message("got netmask %s", inet_ntoa(intf->netmask));
+ break;
+
+ case BOOTP_OPTION_DOMAIN:
+ memcpy(tmp_str, chptr, length);
+ tmp_str[length] = '\0';
+ domain = strdup(tmp_str);
+ log_message("got domain %s", domain);
+ break;
+
+ case BOOTP_OPTION_BROADCAST:
+ memcpy(&intf->broadcast, chptr, sizeof(intf->broadcast));
+ log_message("got broadcast %s", inet_ntoa(intf->broadcast));
+ break;
+
+ case BOOTP_OPTION_GATEWAY:
+ memcpy(&gateway, chptr, sizeof(gateway));
+ log_message("got gateway %s", inet_ntoa(gateway));
+ break;
+
+ }
+
+ chptr += length;
+ }
+
+ set_missing_ip_info(intf);
+}
+
+
+static void init_vendor_codes(struct bootp_request * breq) {
+ memcpy(breq->vendor, vendor_cookie, sizeof(vendor_cookie));
+}
+
+static char gen_hwaddr[16];
+
+static int prepare_request(struct bootp_request * breq, int sock, char * device)
+{
+ struct ifreq req;
+
+ memset(breq, 0, sizeof(*breq));
+
+ breq->opcode = BOOTP_OPCODE_REQUEST;
+
+ strcpy(req.ifr_name, device);
+ if (ioctl(sock, SIOCGIFHWADDR, &req)) {
+ log_perror("SIOCSIFHWADDR");
+ return -1;
+ }
+
+ breq->hw = req.ifr_hwaddr.sa_family;
+ breq->hwlength = IFHWADDRLEN;
+ memcpy(breq->hwaddr, req.ifr_hwaddr.sa_data, IFHWADDRLEN);
+ memcpy(gen_hwaddr, req.ifr_hwaddr.sa_data, IFHWADDRLEN);
+
+ breq->hopcount = 0;
+
+ init_vendor_codes(breq);
+
+ return 0;
+}
+
+static int get_vendor_code(struct bootp_request * bresp, unsigned char option, void * data)
+{
+ unsigned char * chptr;
+ unsigned int length, theOption;
+
+ chptr = (unsigned char*) bresp->vendor + 4;
+ while (*chptr != 0xFF && *chptr != option) {
+ theOption = *chptr++;
+ if (!theOption)
+ continue;
+ length = *chptr++;
+ chptr += length;
+ }
+
+ if (*chptr++ == 0xff)
+ return 1;
+
+ length = *chptr++;
+ memcpy(data, chptr, length);
+
+ return 0;
+}
+
+
+static unsigned long currticks(void)
+{
+ struct timeval tv;
+ unsigned long csecs;
+ unsigned long ticks_per_csec, ticks_per_usec;
+
+ /* Note: 18.2 ticks/sec. */
+
+ gettimeofday (&tv, 0);
+ csecs = tv.tv_sec / 10;
+ ticks_per_csec = csecs * 182;
+ ticks_per_usec = (((tv.tv_sec - csecs * 10) * 1000000 + tv.tv_usec) * 182 / 10000000);
+ return ticks_per_csec + ticks_per_usec;
+}
+
+
+#define BACKOFF_LIMIT 7
+#define TICKS_PER_SEC 18
+#define MAX_ARP_RETRIES 7
+
+static void rfc951_sleep(int exp)
+{
+ static long seed = 0;
+ long q;
+ unsigned long tmo;
+
+ if (exp > BACKOFF_LIMIT)
+ exp = BACKOFF_LIMIT;
+
+ if (!seed)
+ /* Initialize linear congruential generator. */
+ seed = (currticks () + *(long *) &gen_hwaddr + ((short *) gen_hwaddr)[2]);
+
+ /* Simplified version of the LCG given in Bruce Scheier's
+ "Applied Cryptography". */
+ q = seed / 53668;
+ if ((seed = 40014 * (seed - 53668 * q) - 12211 * q) < 0)
+ seed += 2147483563l;
+
+ /* Compute mask. */
+ for (tmo = 63; tmo <= 60 * TICKS_PER_SEC && --exp > 0; tmo = 2 * tmo + 1)
+ ;
+
+ /* Sleep. */
+ log_message("<sleep>");
+
+ for (tmo = (tmo & seed) + currticks (); currticks () < tmo;);
+}
+
+
+static int handle_transaction(int s, struct bootp_request * breq, struct bootp_request * bresp,
+ struct sockaddr_in * server_addr, int dhcp_type)
+{
+ struct pollfd polls;
+ int i, j;
+ int retry = 1;
+ int sin;
+ char eth_packet[ETH_FRAME_LEN];
+ struct iphdr * ip_hdr;
+ struct udphdr * udp_hdr;
+ unsigned char type;
+ unsigned long starttime;
+ int timeout = 1;
+
+ breq->id = starttime = currticks();
+ breq->secs = 0;
+
+ sin = socket(AF_PACKET, SOCK_DGRAM, ntohs(ETH_P_IP));
+ if (sin < 0) {
+ log_perror("af_packet socket");
+ return -1;
+ }
+
+ while (retry <= MAX_ARP_RETRIES) {
+ i = sizeof(*breq);
+
+ if (sendto(s, breq, i, 0, (struct sockaddr *) server_addr, sizeof(*server_addr)) != i) {
+ close(s);
+ log_perror("sendto");
+ return -1;
+ }
+
+ polls.fd = sin;
+ polls.events = POLLIN;
+
+ while (poll(&polls, 1, timeout*1000) == 1) {
+
+ if ((j = recv(sin, eth_packet, sizeof(eth_packet), 0)) == -1) {
+ log_perror("recv");
+ continue;
+ }
+
+ /* We need to do some basic sanity checking of the header */
+ if (j < (signed)(sizeof(*ip_hdr) + sizeof(*udp_hdr)))
+ continue;
+
+ ip_hdr = (void *) eth_packet;
+ if (!verify_checksum(ip_hdr, sizeof(*ip_hdr)))
+ continue;
+
+ if (ntohs(ip_hdr->tot_len) > j)
+ continue;
+
+ j = ntohs(ip_hdr->tot_len);
+
+ if (ip_hdr->protocol != IPPROTO_UDP)
+ continue;
+
+ udp_hdr = (void *) (eth_packet + sizeof(*ip_hdr));
+
+ if (ntohs(udp_hdr->source) != BOOTP_SERVER_PORT)
+ continue;
+
+ if (ntohs(udp_hdr->dest) != BOOTP_CLIENT_PORT)
+ continue;
+ /* Go on with this packet; it looks sane */
+
+ /* Originally copied sizeof (*bresp) - this is a security
+ problem due to a potential underflow of the source
+ buffer. Also, it trusted that the packet was properly
+ 0xFF terminated, which is not true in the case of the
+ DHCP server on Cisco 800 series ISDN router. */
+
+ memset (bresp, 0xFF, sizeof (*bresp));
+ memcpy (bresp, (char *) udp_hdr + sizeof (*udp_hdr), j - sizeof (*ip_hdr) - sizeof (*udp_hdr));
+
+ /* sanity checks */
+ if (bresp->id != breq->id)
+ continue;
+ if (bresp->opcode != BOOTP_OPCODE_REPLY)
+ continue;
+ if (bresp->hwlength != breq->hwlength)
+ continue;
+ if (memcmp(bresp->hwaddr, breq->hwaddr, bresp->hwlength))
+ continue;
+ if (get_vendor_code(bresp, DHCP_OPTION_TYPE, &type) || type != dhcp_type)
+ continue;
+ if (memcmp(bresp->vendor, vendor_cookie, 4))
+ continue;
+ return 0;
+ }
+ rfc951_sleep(retry);
+ breq->secs = htons ((currticks () - starttime) / 20);
+ retry++;
+ timeout *= 2;
+ if (timeout > 5)
+ timeout = 5;
+ }
+
+ return -1;
+}
+
+static void add_vendor_code(struct bootp_request * breq, unsigned char option, unsigned char length, void * data)
+{
+ unsigned char * chptr;
+ int theOption, theLength;
+
+ chptr = (unsigned char*) breq->vendor;
+ chptr += 4;
+ while (*chptr != 0xFF && *chptr != option) {
+ theOption = *chptr++;
+ if (!theOption) continue;
+ theLength = *chptr++;
+ chptr += theLength;
+ }
+
+ *chptr++ = option;
+ *chptr++ = length;
+ memcpy(chptr, data, length);
+ chptr[length] = 0xff;
+}
+
+
+char * dhcp_hostname = NULL;
+char * dhcp_domain = NULL;
+
+enum return_type perform_dhcp(struct interface_info * intf)
+{
+ int s, i;
+ struct sockaddr_in server_addr;
+ struct sockaddr_in client_addr;
+ struct sockaddr_in broadcast_addr;
+ struct bootp_request breq, bresp;
+ unsigned char messageType;
+ unsigned int lease;
+ short aShort;
+ int num_options;
+ char requested_options[50];
+ char * client_id_str, * client_id_hwaddr;
+
+ s = socket(AF_INET, SOCK_DGRAM, 0);
+ if (s < 0) {
+ log_perror("socket");
+ return RETURN_ERROR;
+ }
+
+ {
+ enum return_type results;
+ char * questions[] = { "Host name", "Domain name", NULL };
+ char * questions_auto[] = { "hostname", "domain" };
+ static char ** answers = NULL;
+ char * boulet;
+
+ client_id_str = client_id_hwaddr = NULL;
+
+ results = ask_from_entries_auto("If the DHCP server needs to know you by name; please fill in this information. "
+ "Valid answers are for example: `mybox' for hostname and `mynetwork.com' for "
+ "domain name, for a machine called `mybox.mynetwork.com' on the Internet.",
+ questions, &answers, 32, questions_auto, NULL);
+ if (results == RETURN_OK)
+ {
+ dhcp_hostname = answers[0];
+ if ((boulet = strchr(dhcp_hostname, '.')) != NULL)
+ boulet[0] = '\0';
+ dhcp_domain = answers[1];
+
+ if (*dhcp_hostname && *dhcp_domain) {
+ /* if we have both, then create client id from them */
+ client_id_str = malloc(1 + strlen(dhcp_hostname) + 1 + strlen(dhcp_domain) + 1);
+ client_id_str[0] = '\0';
+ sprintf(client_id_str+1, "%s.%s", dhcp_hostname, dhcp_domain);
+ }
+ }
+ }
+
+ if (initial_setup_interface(intf->device, s) != 0) {
+ close(s);
+ return RETURN_ERROR;
+ }
+
+ if (prepare_request(&breq, s, intf->device) != 0) {
+ close(s);
+ return RETURN_ERROR;
+ }
+
+ messageType = DHCP_TYPE_DISCOVER;
+ add_vendor_code(&breq, DHCP_OPTION_TYPE, 1, &messageType);
+
+ /* add pieces needed to have DDNS/DHCP IP selection based on requested name */
+ if (dhcp_hostname && *dhcp_hostname) { /* pick client id form based on absence or presence of domain name */
+ if (*dhcp_domain) /* alternate style <hostname>.<domainname> */
+ add_vendor_code(&breq, DHCP_OPTION_CLIENT_IDENTIFIER, strlen(client_id_str+1)+1, client_id_str);
+ else { /* usual style (aka windows / dhcpcd) */
+ /* but put MAC in form required for client identifier first */
+ client_id_hwaddr = malloc(IFHWADDRLEN+2);
+ /* (from pump-0.8.22/dhcp.c)
+ * Microsoft uses a client identifier field of the 802.3 address with a
+ * pre-byte of a "1". In order to re-use the DHCP address that they set
+ * for this interface, we have to mimic their identifier.
+ */
+ client_id_hwaddr[0] = 1; /* set flag for ethernet */
+ memcpy(client_id_hwaddr+1, gen_hwaddr, IFHWADDRLEN);
+ add_vendor_code(&breq, DHCP_OPTION_CLIENT_IDENTIFIER, IFHWADDRLEN+1, client_id_hwaddr);
+ }
+ /* this is the one that the dhcp server really wants for DDNS updates */
+ add_vendor_code(&breq, BOOTP_OPTION_HOSTNAME, strlen(dhcp_hostname), dhcp_hostname);
+ log_message("DHCP: telling server to use name = %s", dhcp_hostname);
+ }
+
+ memset(&client_addr.sin_addr, 0, sizeof(&client_addr.sin_addr));
+ client_addr.sin_family = AF_INET;
+ client_addr.sin_port = htons(BOOTP_CLIENT_PORT); /* bootp client */
+
+ if (bind(s, (struct sockaddr *) &client_addr, sizeof(client_addr))) {
+ log_perror("bind");
+ return RETURN_ERROR;
+ }
+
+ broadcast_addr.sin_family = AF_INET;
+ broadcast_addr.sin_port = htons(BOOTP_SERVER_PORT); /* bootp server */
+ memset(&broadcast_addr.sin_addr, 0xff, sizeof(broadcast_addr.sin_addr)); /* broadcast */
+
+ log_message("DHCP: sending DISCOVER");
+
+ wait_message("Sending DHCP request...");
+ i = handle_transaction(s, &breq, &bresp, &broadcast_addr, DHCP_TYPE_OFFER);
+ remove_wait_message();
+
+ if (i != 0) {
+ stg1_error_message("No DHCP reply received.");
+ close(s);
+ return RETURN_ERROR;
+ }
+
+ server_addr.sin_family = AF_INET;
+ server_addr.sin_port = htons(BOOTP_SERVER_PORT); /* bootp server */
+ if (get_vendor_code(&bresp, DHCP_OPTION_SERVER, &server_addr.sin_addr)) {
+ close(s);
+ log_message("DHCPOFFER didn't include server address");
+ return RETURN_ERROR;
+ }
+
+ init_vendor_codes(&breq);
+ messageType = DHCP_TYPE_REQUEST;
+ add_vendor_code(&breq, DHCP_OPTION_TYPE, 1, &messageType);
+ add_vendor_code(&breq, DHCP_OPTION_SERVER, 4, &server_addr.sin_addr);
+ add_vendor_code(&breq, DHCP_OPTION_REQADDR, 4, &bresp.yiaddr);
+
+ /* if used the first time, then have to use it again */
+ if (dhcp_hostname && *dhcp_hostname) { /* add pieces needed to have DDNS/DHCP IP selection based on requested name */
+ if (dhcp_domain && *dhcp_domain) /* alternate style */
+ add_vendor_code(&breq, DHCP_OPTION_CLIENT_IDENTIFIER, strlen(client_id_str+1)+1, client_id_str);
+ else /* usual style (aka windows / dhcpcd) */
+ add_vendor_code(&breq, DHCP_OPTION_CLIENT_IDENTIFIER, IFHWADDRLEN+1, client_id_hwaddr);
+ /* this is the one that the dhcp server really wants for DDNS updates */
+ add_vendor_code(&breq, BOOTP_OPTION_HOSTNAME, strlen(dhcp_hostname), dhcp_hostname);
+ }
+
+ aShort = ntohs(sizeof(struct bootp_request));
+ add_vendor_code(&breq, DHCP_OPTION_MAXSIZE, 2, &aShort);
+
+ num_options = 0;
+ requested_options[num_options++] = BOOTP_OPTION_NETMASK;
+ requested_options[num_options++] = BOOTP_OPTION_GATEWAY;
+ requested_options[num_options++] = BOOTP_OPTION_DNS;
+ requested_options[num_options++] = BOOTP_OPTION_DOMAIN;
+ requested_options[num_options++] = BOOTP_OPTION_BROADCAST;
+ add_vendor_code(&breq, DHCP_OPTION_OPTIONREQ, num_options, requested_options);
+
+ /* request a lease of 1 hour */
+ i = htonl(60 * 60);
+ add_vendor_code(&breq, DHCP_OPTION_LEASE, 4, &i);
+
+ log_message("DHCP: sending REQUEST");
+
+ i = handle_transaction(s, &breq, &bresp, &broadcast_addr, DHCP_TYPE_ACK);
+
+ if (i != 0) {
+ close(s);
+ return RETURN_ERROR;
+ }
+
+ if (get_vendor_code(&bresp, DHCP_OPTION_LEASE, &lease)) {
+ log_message("failed to get lease time\n");
+ return RETURN_ERROR;
+ }
+ lease = ntohl(lease);
+
+ close(s);
+
+ intf->netmask.s_addr = 0;
+ intf->broadcast.s_addr = 0;
+ intf->network.s_addr = 0;
+
+ parse_reply(&bresp, intf);
+
+ return RETURN_OK;
+}
diff --git a/mdk-stage1/dhcp.h b/mdk-stage1/dhcp.h
new file mode 100644
index 000000000..d1ad8ae9e
--- /dev/null
+++ b/mdk-stage1/dhcp.h
@@ -0,0 +1,37 @@
+/*
+ * Guillaume Cottenceau (gc@mandrakesoft.com)
+ *
+ * Copyright 2000 Mandrakesoft
+ *
+ * View the homepage: http://us.mandrakesoft.com/~gc/html/stage1.html
+ *
+ *
+ * This software may be freely redistributed under the terms of the GNU
+ * public license.
+ *
+ * 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.
+ *
+ */
+
+/*
+ * Portions from GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2000 Free Software Foundation, Inc.
+ *
+ * Itself based on etherboot-4.6.4 by Martin Renters.
+ *
+ */
+
+#ifndef _DHCP_H_
+#define _DHCP_H_
+
+#include "stage1.h"
+#include "network.h"
+
+enum return_type perform_dhcp(struct interface_info * intf);
+
+extern char * dhcp_hostname;
+extern char * dhcp_domain;
+
+#endif
diff --git a/mdk-stage1/directory.c b/mdk-stage1/directory.c
new file mode 100644
index 000000000..21d9fc1a1
--- /dev/null
+++ b/mdk-stage1/directory.c
@@ -0,0 +1,169 @@
+/*
+ * Guillaume Cottenceau (gc@mandrakesoft.com)
+ * Olivier Blin (oblin@mandrakesoft.com)
+ *
+ * Copyright 2000 Mandrakesoft
+ *
+ * This software may be freely redistributed under the terms of the GNU
+ * public license.
+ *
+ * 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.
+ *
+ */
+
+/*
+ * Portions from Erik Troan (ewt@redhat.com)
+ *
+ * Copyright 1996 Red Hat Software
+ *
+ */
+
+#include <unistd.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <libgen.h>
+#include "stage1.h"
+#include "frontend.h"
+#include "log.h"
+#include "tools.h"
+#include "utils.h"
+#include "lomount.h"
+
+char * extract_list_directory(char * direct)
+{
+ char ** full = list_directory(direct);
+ char tmp[20000] = "";
+ int i;
+ for (i=0; i<50 ; i++) {
+ if (!full || !*full)
+ break;
+ strcat(tmp, *full);
+ strcat(tmp, "\n");
+ full++;
+ }
+ return strdup(tmp);
+}
+
+static void choose_iso_in_directory(char *directory, char *location_full)
+{
+ char **file;
+ char *stage2_isos[100] = { "Use directory as a mirror tree", "-----" };
+ int stage2_iso_number = 2;
+
+ log_message("\"%s\" exists and is a directory, looking for iso files", directory);
+
+ for (file = list_directory(directory); *file; file++) {
+ char isofile[500];
+ char * loopdev = NULL;
+
+ if (strstr(*file, ".iso") != *file + strlen(*file) - 4)
+ /* file doesn't end in .iso, skipping */
+ continue;
+
+ strcpy(isofile, directory);
+ strcat(isofile, "/");
+ strcat(isofile, *file);
+
+ if (lomount(isofile, LOOP_LOCATION, &loopdev, 0)) {
+ log_message("unable to mount iso file \"%s\", skipping", isofile);
+ continue;
+ }
+ symlink(LOOP_LOCATION_REL "/" ARCH, IMAGE_LOCATION);
+
+ if (image_has_stage2()) {
+ log_message("stage2 installer found in ISO image \"%s\"", isofile);
+ stage2_isos[stage2_iso_number++] = strdup(*file);
+ } else {
+ log_message("ISO image \"%s\" doesn't contain stage2 installer", isofile);
+ }
+
+ unlink(IMAGE_LOCATION);
+ umount(LOOP_LOCATION);
+ del_loop(loopdev);
+ }
+
+ stage2_isos[stage2_iso_number] = NULL;
+
+ if (stage2_iso_number > 2) {
+ enum return_type results;
+ do {
+ results = ask_from_list("Please choose the ISO image to be used to install the "
+ DISTRIB_NAME " Distribution.",
+ stage2_isos, file);
+ if (results == RETURN_BACK) {
+ return;
+ } else if (results == RETURN_OK) {
+ if (!strcmp(*file, stage2_isos[0])) {
+ /* use directory as a mirror tree */
+ continue;
+ } else if (!strcmp(*file, stage2_isos[1])) {
+ /* the separator has been selected */
+ results = RETURN_ERROR;
+ continue;
+ } else {
+ /* use selected ISO image */
+ strcat(location_full, "/");
+ strcat(location_full, *file);
+ log_message("installer will use ISO image \"%s\"", location_full);
+ }
+ }
+ } while (results == RETURN_ERROR);
+ } else {
+ log_message("no ISO image found in \"%s\" directory", location_full);
+ }
+}
+
+
+enum return_type try_with_directory(char *directory, char *method_live, char *method_iso) {
+ char location_full[500];
+ char * loopdev = NULL;
+ struct stat statbuf;
+ enum return_type ret = RETURN_OK;
+
+ unlink(IMAGE_LOCATION);
+ strcpy(location_full, directory);
+
+ if (!stat(directory, &statbuf) && S_ISDIR(statbuf.st_mode)) {
+ choose_iso_in_directory(directory, location_full);
+ }
+
+ loopdev = NULL;
+ if (!stat(location_full, &statbuf) && !S_ISDIR(statbuf.st_mode)) {
+ log_message("%s exists and is not a directory, assuming this is an ISO image", location_full);
+ if (lomount(location_full, LOOP_LOCATION, &loopdev, 0)) {
+ stg1_error_message("Could not mount file %s as an ISO image of the " DISTRIB_NAME " Distribution.", location_full);
+ return RETURN_ERROR;
+ }
+ symlink(LOOP_LOCATION_REL "/" ARCH, IMAGE_LOCATION);
+ add_to_env("ISOPATH", location_full);
+ add_to_env("METHOD", method_iso);
+ } else {
+ create_IMAGE_LOCATION(location_full);
+ add_to_env("METHOD", method_live);
+ }
+
+ if (access(IMAGE_LOCATION "/" COMPRESSED_LOCATION_REL, R_OK)) {
+ stg1_error_message("I can't find the " DISTRIB_NAME " Distribution in the specified directory. "
+ "(I need the subdirectory " COMPRESSED_LOCATION_REL ")\n"
+ "Here's a short extract of the files in the directory:\n"
+ "%s", extract_list_directory(IMAGE_LOCATION));
+ ret = RETURN_BACK;
+ } else if (may_load_compressed_image() != RETURN_OK) {
+ stg1_error_message("Could not load program into memory.");
+ ret = RETURN_ERROR;
+ }
+
+ if (ret == RETURN_OK)
+ log_message("found the " DISTRIB_NAME " Installation, good news!");
+
+ if (!KEEP_MOUNTED || ret != RETURN_OK) {
+ /* in rescue mode, we don't need the media anymore */
+ umount(LOOP_LOCATION);
+ del_loop(loopdev);
+ }
+
+ return ret;
+}
diff --git a/mdk-stage1/directory.h b/mdk-stage1/directory.h
new file mode 100644
index 000000000..eb744520b
--- /dev/null
+++ b/mdk-stage1/directory.h
@@ -0,0 +1,29 @@
+/*
+ * Guillaume Cottenceau (gc@mandrakesoft.com)
+ * Olivier Blin (oblin@mandrakesoft.com)
+ *
+ * Copyright 2000 Mandrakesoft
+ *
+ * This software may be freely redistributed under the terms of the GNU
+ * public license.
+ *
+ * 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.
+ *
+ */
+
+/*
+ * Portions from Erik Troan (ewt@redhat.com)
+ *
+ * Copyright 1996 Red Hat Software
+ *
+ */
+
+#ifndef _DIRECTORY_H_
+#define _DIRECTORY_H_
+
+char * extract_list_directory(char * direct);
+enum return_type try_with_directory(char *location_full, char *method_live, char *method_iso);
+
+#endif
diff --git a/mdk-stage1/disk.c b/mdk-stage1/disk.c
new file mode 100644
index 000000000..acdc1efaf
--- /dev/null
+++ b/mdk-stage1/disk.c
@@ -0,0 +1,225 @@
+/*
+ * Guillaume Cottenceau (gc@mandrakesoft.com)
+ *
+ * Copyright 2000 Mandrakesoft
+ *
+ * This software may be freely redistributed under the terms of the GNU
+ * public license.
+ *
+ * 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.
+ *
+ */
+
+/*
+ * Portions from Erik Troan (ewt@redhat.com)
+ *
+ * Copyright 1996 Red Hat Software
+ *
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <libgen.h>
+#include "stage1.h"
+#include "frontend.h"
+#include "modules.h"
+#include "probing.h"
+#include "log.h"
+#include "tools.h"
+#include "utils.h"
+#include "mount.h"
+#include "automatic.h"
+#include "directory.h"
+#include "partition.h"
+
+#include "disk.h"
+
+static enum return_type try_automatic_with_partition(char *dev) {
+ enum return_type results;
+ int mounted;
+ wait_message("Trying to access " DISTRIB_NAME " disk (partition %s)", dev);
+ mounted = !try_mount(dev, MEDIA_LOCATION);
+ remove_wait_message();
+ if (mounted && !access(MEDIA_LOCATION "/" COMPRESSED_LOCATION_REL, R_OK)) {
+ results = try_with_directory(MEDIA_LOCATION, "disk", "disk-iso");
+ if (results == RETURN_OK) {
+ if (!KEEP_MOUNTED)
+ umount(MEDIA_LOCATION);
+ return RETURN_OK;
+ }
+ }
+ if (mounted)
+ umount(MEDIA_LOCATION);
+ return RETURN_ERROR;
+}
+
+static enum return_type try_automatic_with_disk(char *disk, char *model) {
+ char * parts[50];
+ char * parts_comments[50];
+ enum return_type results;
+ char **dev;
+ wait_message("Trying to access " DISTRIB_NAME " disk (drive %s)", model);
+ if (list_partitions(disk, parts, parts_comments)) {
+ stg1_error_message("Could not read partitions information.");
+ return RETURN_ERROR;
+ }
+ remove_wait_message();
+ dev = parts;
+ while (dev && *dev) {
+ results = try_automatic_with_partition(*dev);
+ if (results == RETURN_OK) {
+ return RETURN_OK;
+ }
+ dev++;
+ }
+ return RETURN_ERROR;
+}
+
+static enum return_type try_automatic(char ** medias, char ** medias_models)
+{
+ char ** model = medias_models;
+ char ** ptr = medias;
+ while (ptr && *ptr) {
+ enum return_type results;
+ results = try_automatic_with_disk(*ptr, *model);
+ if (results == RETURN_OK)
+ return RETURN_OK;
+ ptr++;
+ model++;
+ }
+ return RETURN_ERROR;
+}
+
+static enum return_type try_with_device(char *dev_name)
+{
+ char * questions_location[] = { "Directory or ISO images directory or ISO image", NULL };
+ char * questions_location_auto[] = { "directory", NULL };
+ static char ** answers_location = NULL;
+ char location_full[500];
+
+ char * parts[50];
+ char * parts_comments[50];
+ enum return_type results;
+ char * choice;
+
+ if (list_partitions(dev_name, parts, parts_comments)) {
+ stg1_error_message("Could not read partitions information.");
+ return RETURN_ERROR;
+ }
+
+ /* uglyness to allow auto starting with devfs */
+ if (!IS_AUTOMATIC || streq((choice = get_auto_value("partition")), "")) {
+ if (parts[0] == NULL) {
+ stg1_error_message("No partition found.");
+ return RETURN_ERROR;
+ }
+
+ results = ask_from_list_comments_auto("Please select the partition containing the copy of the "
+ DISTRIB_NAME " Distribution install source.",
+ parts, parts_comments, &choice, "partition", parts);
+ if (results != RETURN_OK)
+ return results;
+ }
+
+ /* in testing mode, assume the partition is already mounted on MEDIA_LOCATION */
+ if (!IS_TESTING && try_mount(choice, MEDIA_LOCATION)) {
+ stg1_error_message("I can't find a valid filesystem (tried: ext2, vfat, ntfs, reiserfs). "
+ "Make sure the partition has been cleanly unmounted.");
+ return try_with_device(dev_name);
+ }
+
+ ask_dir:
+ if (ask_from_entries_auto("Please enter the directory (or ISO image file) containing the "
+ DISTRIB_NAME " Distribution install source.",
+ questions_location, &answers_location, 24, questions_location_auto, NULL) != RETURN_OK) {
+ umount(MEDIA_LOCATION);
+ return try_with_device(dev_name);
+ }
+
+ strcpy(location_full, MEDIA_LOCATION);
+ strcat(location_full, "/");
+ strcat(location_full, answers_location[0]);
+
+ if (access(location_full, R_OK)) {
+ char * path = strdup(answers_location[0]);
+ stg1_error_message("Directory or ISO image file could not be found on partition.\n"
+ "Here's a short extract of the files in the directory %s:\n"
+ "%s", dirname(path), extract_list_directory(dirname(location_full)));
+ free(path);
+ goto ask_dir;
+ }
+
+ results = try_with_directory(location_full, "disk", "disk-iso");
+ if (results != RETURN_OK) {
+ goto ask_dir;
+ }
+
+ if (!KEEP_MOUNTED)
+ umount(MEDIA_LOCATION);
+
+ return RETURN_OK;
+}
+
+enum return_type disk_prepare(void)
+{
+ char ** medias, ** medias_models;
+ char * choice;
+ int i;
+ enum return_type results;
+ static int already_probed_ide_generic = 0;
+
+ int count = get_disks(&medias, &medias_models);
+
+ if (IS_AUTOMATIC) {
+ results = try_automatic(medias, medias_models);
+ if (results != RETURN_ERROR)
+ return results;
+ unset_automatic();
+ }
+
+ if (count == 0) {
+ if (!already_probed_ide_generic) {
+ already_probed_ide_generic = 1;
+ my_insmod("ide_generic", ANY_DRIVER_TYPE, NULL, 0);
+ return disk_prepare();
+ }
+ stg1_error_message("No DISK drive found.");
+ i = ask_insmod(MEDIA_ADAPTERS);
+ if (i == RETURN_BACK)
+ return RETURN_BACK;
+ return disk_prepare();
+ }
+
+ if (count == 1) {
+ results = try_with_device(*medias);
+ if (results != RETURN_ERROR)
+ return results;
+ i = ask_insmod(MEDIA_ADAPTERS);
+ if (i == RETURN_BACK)
+ return RETURN_BACK;
+ return disk_prepare();
+ }
+
+ results = ask_from_list_comments_auto("Please select the disk containing the copy of the "
+ DISTRIB_NAME " Distribution install source.",
+ medias, medias_models, &choice, "disk", medias);
+
+ if (results != RETURN_OK)
+ return results;
+
+ results = try_with_device(choice);
+ if (results != RETURN_ERROR)
+ return results;
+ i = ask_insmod(MEDIA_ADAPTERS);
+ if (i == RETURN_BACK)
+ return RETURN_BACK;
+ return disk_prepare();
+}
diff --git a/mdk-stage1/disk.h b/mdk-stage1/disk.h
new file mode 100644
index 000000000..fae890894
--- /dev/null
+++ b/mdk-stage1/disk.h
@@ -0,0 +1,27 @@
+/*
+ * Guillaume Cottenceau (gc@mandrakesoft.com)
+ *
+ * Copyright 2000 Mandrakesoft
+ *
+ * This software may be freely redistributed under the terms of the GNU
+ * public license.
+ *
+ * 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.
+ *
+ */
+
+/*
+ * Portions from Erik Troan (ewt@redhat.com)
+ *
+ * Copyright 1996 Red Hat Software
+ *
+ */
+
+#ifndef _DISK_H_
+#define _DISK_H_
+
+enum return_type disk_prepare(void);
+
+#endif
diff --git a/mdk-stage1/dns.c b/mdk-stage1/dns.c
new file mode 100644
index 000000000..1d7d2d6c8
--- /dev/null
+++ b/mdk-stage1/dns.c
@@ -0,0 +1,224 @@
+/*
+ * Guillaume Cottenceau (gc@mandrakesoft.com)
+ *
+ * Copyright 2000 Mandrakesoft
+ *
+ * This software may be freely redistributed under the terms of the GNU
+ * public license.
+ *
+ * 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.
+ *
+ */
+
+/*
+ * Portions from Erik Troan (ewt@redhat.com)
+ *
+ * Copyright 1996 Red Hat Software
+ *
+ */
+
+#include <stdlib.h>
+
+// dietlibc can do hostname lookup, whereas glibc can't when linked statically :-(
+
+#if defined(__dietlibc__)
+
+#include <unistd.h>
+#include <string.h>
+#include <stdio.h>
+#include <netdb.h>
+#include <sys/socket.h>
+#include <resolv.h>
+
+#include "network.h"
+#include "log.h"
+
+#include "dns.h"
+
+int mygethostbyname(char * name, struct in_addr * addr)
+{
+ struct hostent * h;
+
+ /* prevent from timeouts */
+ if (_res.nscount == 0)
+ return -1;
+
+ h = gethostbyname(name);
+
+ if (!h && domain) {
+ // gethostbyname from dietlibc doesn't support domain handling
+ char fully_qualified[500];
+ sprintf(fully_qualified, "%s.%s", name, domain);
+ h = gethostbyname(fully_qualified);
+ }
+
+ if (h && h->h_addr_list && (h->h_addr_list)[0]) {
+ memcpy(addr, (h->h_addr_list)[0], sizeof(*addr));
+ log_message("is-at: %s", inet_ntoa(*addr));
+ return 0;
+ }
+
+ log_message("unknown host %s", name);
+ return -1;
+}
+
+char * mygethostbyaddr(char * ipnum)
+{
+ struct in_addr in;
+ struct hostent * host;
+
+ /* prevent from timeouts */
+ if (_res.nscount == 0)
+ return NULL;
+
+ if (!inet_aton(ipnum, &in))
+ return NULL;
+ host = gethostbyaddr(&(in.s_addr), sizeof(in.s_addr) /* INADDRSZ */, AF_INET);
+ if (host && host->h_name)
+ return host->h_name;
+ return NULL;
+}
+
+#elif defined(__GLIBC__)
+
+#include <alloca.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <resolv.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "log.h"
+
+#include "dns.h"
+
+/* This is dumb, but glibc doesn't like to do hostname lookups w/o libc.so */
+
+union dns_response {
+ HEADER hdr;
+ u_char buf[PACKETSZ];
+} ;
+
+static int do_query(char * query, int queryType, char ** domainName, struct in_addr * ipNum)
+{
+ int len, ancount, type;
+ u_char * data, * end;
+ char name[MAXDNAME];
+ union dns_response response;
+
+#ifdef __sparc__
+ /* from jj: */
+ /* We have to wait till ethernet negotiation is done */
+ _res.retry = 3;
+#else
+ _res.retry = 2;
+#endif
+
+
+ len = res_search(query, C_IN, queryType, (void *) &response, sizeof(response));
+ if (len <= 0)
+ return -1;
+
+ if (ntohs(response.hdr.rcode) != NOERROR)
+ return -1;
+
+ ancount = ntohs(response.hdr.ancount);
+ if (ancount < 1)
+ return -1;
+
+ data = response.buf + sizeof(HEADER);
+ end = response.buf + len;
+
+ /* skip the question */
+ data += dn_skipname(data, end) + QFIXEDSZ;
+
+ /* parse the answer(s) */
+ while (--ancount >= 0 && data < end) {
+
+ /* skip the domain name portion of the RR record */
+ data += dn_skipname(data, end);
+
+ /* get RR information */
+ GETSHORT(type, data);
+ data += INT16SZ; /* skipp class */
+ data += INT32SZ; /* skipp TTL */
+ GETSHORT(len, data);
+
+ if (type == T_PTR) {
+ /* we got a pointer */
+ len = dn_expand(response.buf, end, data, name, sizeof(name));
+ if (len <= 0) return -1;
+ if (queryType == T_PTR && domainName) {
+ /* we wanted a pointer */
+ *domainName = malloc(strlen(name) + 1);
+ strcpy(*domainName, name);
+ return 0;
+ }
+ } else if (type == T_A) {
+ /* we got an address */
+ if (queryType == T_A && ipNum) {
+ /* we wanted an address */
+ memcpy(ipNum, data, sizeof(*ipNum));
+ return 0;
+ }
+ }
+
+ /* move ahead to next RR */
+ data += len;
+ }
+
+ return -1;
+}
+
+char * mygethostbyaddr(char * ipnum) {
+ int rc;
+ char * result;
+ char * strbuf;
+ char * chptr;
+ char * splits[4];
+ int i;
+
+ _res.retry = 1;
+
+ strbuf = alloca(strlen(ipnum) + 1);
+ strcpy(strbuf, ipnum);
+
+ ipnum = alloca(strlen(strbuf) + 20);
+
+ for (i = 0; i < 4; i++) {
+ chptr = strbuf;
+ while (*chptr && *chptr != '.')
+ chptr++;
+ *chptr = '\0';
+
+ if (chptr - strbuf > 3) return NULL;
+ splits[i] = strbuf;
+ strbuf = chptr + 1;
+ }
+
+ sprintf(ipnum, "%s.%s.%s.%s.in-addr.arpa", splits[3], splits[2], splits[1], splits[0]);
+
+ rc = do_query(ipnum, T_PTR, &result, NULL);
+
+ if (rc)
+ return NULL;
+ else
+ return result;
+}
+
+int mygethostbyname(char * name, struct in_addr * addr) {
+ int rc = do_query(name, T_A, NULL, addr);
+ if (!rc)
+ log_message("is-at %s", inet_ntoa(*addr));
+ return rc;
+}
+
+#else
+
+#error "Unsupported C library"
+
+#endif
diff --git a/mdk-stage1/dns.h b/mdk-stage1/dns.h
new file mode 100644
index 000000000..21d0c63ac
--- /dev/null
+++ b/mdk-stage1/dns.h
@@ -0,0 +1,30 @@
+/*
+ * Guillaume Cottenceau (gc@mandrakesoft.com)
+ *
+ * Copyright 2000 Mandrakesoft
+ *
+ * This software may be freely redistributed under the terms of the GNU
+ * public license.
+ *
+ * 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.
+ *
+ */
+
+/*
+ * Portions from Erik Troan (ewt@redhat.com)
+ *
+ * Copyright 1996 Red Hat Software
+ *
+ */
+
+#ifndef H_DNS
+#define H_DNS
+
+#include <netinet/in.h>
+
+int mygethostbyname(char * name, struct in_addr * addr);
+char * mygethostbyaddr(char * ipnum);
+
+#endif
diff --git a/mdk-stage1/doc/HACKING b/mdk-stage1/doc/HACKING
new file mode 100644
index 000000000..d196c8010
--- /dev/null
+++ b/mdk-stage1/doc/HACKING
@@ -0,0 +1,31 @@
+If you have to boot pretty often, you'll appreciate to speed the things up
+a little.
+
+Here's what we use: the GRUB feature to boot from the network using the
+DHCP protocol and the TFTP protocol.
+
+Here's the "menu.lst" to do that:
+
+-=-=--
+
+timeout 0
+
+title linux
+dhcp
+tftpserver 192.168.1.17
+kernel (nd)/tftpboot/gc/vmlinuz ramdisk=32000 vga=788
+initrd (nd)/tftpboot/gc/network.rdz
+
+-=-=--
+
+
+The option "tftpserver" is used to override the tftpserver address given
+as an answer by the DHCP server. That way, you'll not need to bother your
+system administrator to modify his dhcp server configuration.
+
+The directory /tftpboot seems to be the only one defaultly accepted by the
+server, and its subdirs.
+
+
+Of course, your GRUB needs to be compiled with the specific code for your
+network card; use ./configure --help in the GRUB build dir for more infos.
diff --git a/mdk-stage1/doc/README b/mdk-stage1/doc/README
new file mode 100644
index 000000000..6a1d92bf9
--- /dev/null
+++ b/mdk-stage1/doc/README
@@ -0,0 +1,185 @@
+-------------------------------------------------------
+* Stage1 of the Mandrakelinux installation program *
+-------------------------------------------------------
+
+
+[ Author ]
+
+ Guillaume Cottenceau (gc at mandrakesoft.com)
+
+
+[ Copyright ]
+
+ Copyright 2000, 2001, 2002 Mandrakesoft
+
+ Partially inspired by Redhat stuff (install from 5.x and 7.x) copyright
+ Red Hat Software, and Debian stuff (boot-floppies) copyright by their
+ respective holders.
+
+
+[ Licence ]
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+ *** WARNING! ***
+
+ This General Public License does not permit incorporating any part
+ of this program as a library into proprietary programs.
+
+
+[ Online ]
+
+ http://people.mandrakesoft.com/~gc/html/stage1.html
+
+
+[ Purpose ]
+
+ This code will take the control of the computer after that Linux
+ kernel booted properly, and will try to run the main installer
+ (also known as "stage 2") from a series of different media
+ including harddrive, cdrom, and network.
+
+ Use the source, Luke.
+
+
+
+
+ -=-=-- Okay, now, more details --=-=-
+
+
+ [ Installing Mandrakelinux ]
+
+Per default, just insert your Mandrakelinux Installation CD into your
+CDROM tray, be sure your system BIOS is configured to boot on your CDROM,
+and that's all.
+
+If you have multiple CDROM drives and the installer can't autodetect in
+which CDROM drive is the disc, it may ask you to choose the correct drive,
+between your CDROM drives.
+
+Also, if you want to install from an SCSI CDROM, the installer should
+detect your SCSI adapter; if it fails you may have to select the right
+driver and/or supply additional parameters.
+
+
+ [ Position of the problem ]
+
+The need for alternate installation methods come with more specific
+hardware configuration and/or need for frequent updates of the Installer
+software.
+
+All of these methods will require to use a special boot disk. The method
+is to download it and then to copy it "physically" to a floppy with the
+command:
+
+# dd if=<boot-disk> of=/dev/fd0
+
+Our boot disks are called "cdrom.img", "network.img", etc.
+
+
+ [ Installation from CDROM ]
+
+The first situation you may encounter is an old BIOS which does not permit
+you to boot from your CDROM drive.
+
+In that case, you'll need to use the "cdrom.img" image file. The steps are
+the same as with CDROM boot, and everything should be automatic.
+
+
+ [ Installation from DISK ]
+
+If you like trying occasionnally our development version, the Cooker, one
+of the easiest way is to grab a local copy of the Distribution on one of
+your local hard drives, and to install from that location.
+
+At present time, you can install from IDE or SCSI drives, from Linux
+(ext2), Windows (vfat) or Reiserfs partition.
+
+In that case, you'll need to use the "hd.img" image file. The dialogs will
+ask you to choose the DISK drive to use to install from, then the
+partition on which you copied the Distribution, then the location
+(directory) in which you copied the Distribution.
+
+
+ [ Installation from NETWORK ]
+
+For convenience, you can also install from a NFS volume, from a FTP
+server, or from a HTTP server. NFS installs are maybe the fastest
+and most convenient possible, so if you need to do frequent and/or
+multiple installs, you may like this option.
+
+In that case, you'll need to use the "network.img" image file. If you have
+PCI network card(s), you'll probably have to only setup your network
+options. If not, you'll have to choose the appropriate driver(s) and/or
+optional parameters. Supported network configurations include static IP
+allocation and DHCP automatic configuration.
+
+
+ [ Installation from PCMCIA ]
+
+If you want to perform an installation on your laptop that is not based on
+local IDE CDROM or DISK, nor on built-in network card, but on PCMCIA
+extension (probably a network adapter or CDROM drive), you'll need the
+"pcmcia.img" image file.
+
+PCMCIA services should automatically start and be transparent to you.
+Then, you'll follow the instructions according to your preferred
+installation method.
+
+
+ [ Monitoring a stage1 session ]
+
+Linux supports virtual consoles. You can switch between them by issueing
+Ctrl+Alt+Fx key, in which 'x' is the number of the console. Here's console
+occupancy during stage1.
+
+(#1) The user-interface of the stage1 is on the first console. In case of
+newt interaction, it's provided with a neat blue and black color scheme,
+and nice widgets. In case of stdio interaction (cdrom and disk installs),
+it's more basic but still usable :-).
+
+(#2) A shell is provided on second console in some cases (you need to
+compile it with -DSPAWN_SHELL and you need to provide a valid shell in the
+initrd) and of course it's not in, in image files of Mandrakelinux
+releases because it's too much diskspace.
+
+(#3) The log is printed out on the third console. This is the location
+where you can find most valuable information, prefixed by a '*'. See
+"log.h" for calls that print things out to the log.
+
+(#4) The kernel messages are printed on the fourth console. There is a
+process forked very early in the init (the program before the stage1)
+which monitors /proc/kmsg for new kernel messages. Also, syslog stuff (the
+logs commited by the programs) should appear on the /dev/log Unix socket,
+this is also printed on this console.
+
+(#5) Former place for the stderr of insmod calls. It's not used anymore.
+
+(#6) Place where a trivial interactive communication with the stage1 is
+set up if the parameter -DSPAWN_INTERACTIVE is compiled in. Basically, you
+can set switches such as "expert" and "rescue" on the fly with this
+feature. It's implemented with a fork and a Unix pipe.
+
+
+ [ Rescueing a system ]
+
+Since Mandrakelinux 7.1, we provide a rescue system through each of the
+previously described methods. You don't need a special "rescue.img" file.
+Just hit "F1" at boot time, type in "rescue", and follow the first steps
+of the installation according to the method you chose (choose
+disks/partitions for disk method, network parameters for network method,
+etc). Then, you'll end up with a workable system, very useful to rescue a
+damaged system, or do other basic actions.
diff --git a/mdk-stage1/doc/TECH-INFOS b/mdk-stage1/doc/TECH-INFOS
new file mode 100644
index 000000000..67151410e
--- /dev/null
+++ b/mdk-stage1/doc/TECH-INFOS
@@ -0,0 +1,106 @@
+
+| (*) Automatic install
+\----------------------
+
+This feature is used to replace redhat kickstart. It uses the kernel
+parameter "automatic" with keywords separated with commas and colons, on
+the following genres:
+
+ automatic=method:nfs,network:static,ip:192.168.1.24,server:192.168.1.7,directory:/stable/i586
+
+ automatic=method:ftp,network:dhcp,server:ftp.ciril.fr,directory:/pub/linux/mandrake-devel/cooker
+
+ automatic=method:ftp,network:dhcp,server:companyserver,directory:/mdkinst,user:XXX,pass:XXX
+
+ automatic=method:ftp,interface:eth1,network:dhcp,...
+
+ automatic=method:ftp,network:adsl,adsluser:XXX,adslpass:XXX,...
+
+ automatic=method:cdrom
+
+ automatic=method:disk,disk:hdb,partition:hdb7,directory:/cooker
+
+
+The keywords correspond to each "virtual" question answered automatically,
+either from a list or from a free field.
+
+
+Keywords are:
+
+
+`method' <- (nfs,ftp,http,cdrom,disk)
+
+if nfs/ftp/http:
+
+ `network' <- (static,dhcp,adsl)
+
+ if multiple interfaces detected:
+
+ `interface' <- (list-of-detected-interfaces)
+ if "auto":
+ use the first interface with a link beat
+ if "wired":
+ use the first wired interface with a link beat
+ or the first wired interface if none has a link beat
+
+ fi
+
+ if static:
+
+ `ip', `dns', `gateway', `netmask' (free fields)
+
+ elsif adsl:
+
+ `adsluser', `adslpass' (free field)
+
+ fi
+
+ if resolving fails:
+
+ `hostname', `domain' (free fields)
+
+ fi
+
+ `server', `directory' (free fields)
+
+ if ftp:
+
+ `user', `pass' (free fields)
+
+ fi
+
+fi
+
+if disk:
+
+ `disk' <- (list-of-detected-disks)
+
+ `partition' <- (list-of-detected-partitions)
+
+ `directory' (free fields)
+
+fi
+
+
+
+You may use shorter versions of keywords (it helps reducing size of
+commandline), please find each keyword short-alias counterpart in file
+../automatic.c under the identifier named "short_aliases".
+
+This gives for example for:
+
+ automatic=method:nfs,network:static,ip:192.168.1.24,server:192.168.1.7,directory:/stable/i586
+==>
+ automatic=met:nfs,net:static,ip:192.168.1.24,ser:192.168.1.7,dir:/stable/i586
+
+
+
+You may specify a stage2 auto-install file, different from the
+default `auto_inst.cfg.pl' in install/, by filling the
+`bootfile' parameter of your DHCP server response.
+
+Note that if the name ends with `-IP' or `-IP.pl', IP will be
+replaced by the IP address given to the host, normalized to
+hexadecimal (that is, `192.168.100.57' would give 'C0A86439').
+
+
diff --git a/mdk-stage1/doc/UPDATEMODULES b/mdk-stage1/doc/UPDATEMODULES
new file mode 100644
index 000000000..ceef21758
--- /dev/null
+++ b/mdk-stage1/doc/UPDATEMODULES
@@ -0,0 +1,95 @@
+This is the documentation for the "Update Modules" (Update Drivers)
+feature.
+
+This feature aims to propose new modules or replacement modules for the
+install and afterwards. This is useful when there is a firmware update for a
+given driver, an additional driver needed for something, etc.
+
+
+You must use a floppy disk with e2fs filesystem (NOT vfat/windows
+formatted). Use "mke2fs /dev/fd0" on your own box to format a floppy with
+e2fs filesystem.
+
+This disk may contain a number of kernel modules; some of them
+may replace existing modules, some of them may be added.
+This disk must contain a special file, named "to_load", on
+the root (not in a subdirectory). This file will contain a series of
+module names, with optional module options; the program will try to load
+all these modules one after another, using file on the floppy if present,
+else using file within standard module repository ("marfile" on the boot
+floppy). It can contain comments, these are strictly defined by the
+presence of a hash (#) character on column 0 of any line.
+
+This disk may also contain some update or new modules for installed kernels.
+Those modules must be placed in directory <kernel-version>. They must be
+gzipped if the installed kernel modules are gzipped.
+
+You may need to specify the "category" so that new modules are used correctly.
+For example, a scsi module should be put in category disk/scsi so that it is
+put in scsi_hostadapter and initrd.
+
+
+Here's a typical scenario:
+
+
+1. Boot the floppy (or cdrom) with the option "updatemodules"
+
+ (you may do that by pressing F1 then entering "linux updatemodules")
+
+
+2. At the very beginning of the User Interface, you are asked to insert
+ the Update Modules disk. Insert the Update Modules disk and press
+ Enter.
+
+--=----=----=----=----=----=----=----=----=--
+Our example disk contains:
+
+[root@obiwan mnt]# ll floppy/
+total 77
+drwxr-xr-x 2 root root 12288 Jul 26 12:02 lost+found/
+-rw-r--r-- 1 root root 9051 Jul 26 12:43 msdos.ko
+-rw-r--r-- 1 root root 13660 Jul 26 12:04 ppa.ko
+-rw-r--r-- 1 root root 54 Jul 26 12:46 to_load
+-rw-r--r-- 1 root root 32108 Jul 26 12:04 uhci.ko
+-rw-r--r-- 1 root root 6572 Jul 26 12:04 wacom.ko
+drwxr-xr-x 4 root root 4096 Jul 26 12:04 2.6.8.1-20mdk
+drwxr-xr-x 4 root root 4096 Jul 26 12:04 2.6.8.1-20mdksmp
+[root@obiwan mnt]# cat floppy/to_load
+# Update Drivers description file
+3c59x
+# fat is a dep for msdos
+fat
+# updated msdos (handling of 9+4 filenames)
+msdos
+ppa
+# ISA network card needing options
+ne io=0x300 irq=7
+# New module [list_modules: disk/scsi]
+a320raid
+[root@obiwan mnt]# (cd floppy/2.6.8.1-20mdk ; find -type f)
+./kernel/fs/msdos/msdos.ko.gz
+./kernel/drivers/scsi/ppa.ko.gz
+./kernel/drivers/usb/host/uhci-hcd.ko.gz
+./kernel/drivers/usb/input/wacom.ko.gz
+[root@obiwan mnt]#
+--=----=----=----=----=----=----=----=----=--
+
+
+3. The program reads the special file "to_load" and processes the files.
+
+ a- 3c59x loaded from the marfile on the boot floppy
+ b- fat loaded from the marfile on the boot floppy
+ c- msdos loaded from the update modules floppy
+ d- ppa loaded from the update modules floppy
+ e- ne loaded from the marfile on the boot floppy
+
+
+
+!!! Beware !!!, the dependencies are not handled automatically in
+the case of load from the update modules floppy, that's why on
+our example we need to load "fat" from the standard modules
+before "msdos" from the update floppy.
+
+
+4. When system is installed, update floppy is asked again so that update
+modules for the installed kernels can be copied. Then depmod is called.
diff --git a/mdk-stage1/doc/WHY-DIETLIBC b/mdk-stage1/doc/WHY-DIETLIBC
new file mode 100644
index 000000000..e7c526b49
--- /dev/null
+++ b/mdk-stage1/doc/WHY-DIETLIBC
@@ -0,0 +1,50 @@
+(the dietlibc is a replacement for the glibc, which aim is to produce
+smaller statically linked binaries)
+
+
+The use for dietlibc in the stage1 was clear because currently used
+install process on x86 is from a 1.44 Mbytes floppy. On this floppy we
+need to fit the kernel, modules (scsi and network access), and the code to
+do the basic things to load the stage2. The only part on which we could
+progress was the code.
+
+As always, figures demonstrate evidences. Here are the size of the
+binaries used for the cdrom, disk, network and full floppy installs, using
+newt as the UI library:
+
+ - with glibc
+
+-rwxr-xr-x 1 gc gc 569448 May 15 15:29 stage1-cdrom
+-rwxr-xr-x 1 gc gc 572264 May 15 15:29 stage1-disk
+-rwxr-xr-x 1 gc gc 624712 May 15 15:30 stage1-network
+-rwxr-xr-x 1 gc gc 720360 May 15 15:29 stage1-full
+
+ - with dietlibc
+
+-rwxr-xr-x 1 gc gc 169332 May 15 14:26 stage1-cdrom
+-rwxr-xr-x 1 gc gc 172180 May 15 14:26 stage1-disk
+-rwxr-xr-x 1 gc gc 198612 May 15 14:26 stage1-network
+-rwxr-xr-x 1 gc gc 251764 May 15 14:26 stage1-full
+
+
+The `stage1-full' binary has code for many things, most notably: data
+decrunching (bzlib), archive extraction (in-house format), module loading
+(insmod from busybox), PCI detection, ide and scsi handling,
+cdrom/disk/loopback mounting, DHCP client negociation (redhat+grub), NFS
+mounting (util-linux), FTP and HTTP transmission (redhat), pcmcia
+initializing (pcmcia-cs), UI interaction (slang/newt); with use of the
+dietlibc, the binary is only 250 kbytes!
+
+
+Due to the modular coding, it is also possible to choose to not use
+slang/newt as the UI, but a stdio-only UI. In that case, the binaries get
+even smaller:
+
+-rwxr-xr-x 1 gc gc 104500 May 15 15:46 stage1-cdrom*
+-rwxr-xr-x 1 gc gc 107348 May 15 15:46 stage1-disk*
+-rwxr-xr-x 1 gc gc 133972 May 15 15:47 stage1-network*
+-rwxr-xr-x 1 gc gc 187348 May 15 15:46 stage1-full*
+
+
+
+gc [Tue May 15 15:58:34 2001] \ No newline at end of file
diff --git a/mdk-stage1/doc/documented..frontend.h b/mdk-stage1/doc/documented..frontend.h
new file mode 100644
index 000000000..0e666d534
--- /dev/null
+++ b/mdk-stage1/doc/documented..frontend.h
@@ -0,0 +1,69 @@
+/*
+ * Guillaume Cottenceau (gc@mandrakesoft.com)
+ *
+ * Copyright 2000 Mandrakesoft
+ *
+ * This software may be freely redistributed under the terms of the GNU
+ * public license.
+ *
+ * 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.
+ *
+ */
+
+/*
+ * Using high-level UI.
+ *
+ * These functions are frontend-independant: your program won't know each
+ * `frontend' (e.g. each way to grab user input) will be used.
+ *
+ * Then you may link your binary against any `frontend' that implement all
+ * these functions (and possibly necessary libraries).
+ */
+
+
+#ifndef _FRONTEND_H_
+#define _FRONTEND_H_
+
+/* this must be called before anything else */
+void init_frontend(void);
+
+/* this must be called before exit of program */
+void finish_frontend(void);
+
+
+void info_message(char *msg, ...) __attribute__ ((format (printf, 1, 2))); /* (blocks program) */
+
+void error_message(char *msg, ...) __attribute__ ((format (printf, 1, 2))); /* (blocks program) */
+
+/* (doesn't block program)
+ * (this is not necessarily stackable, e.g. only one wait_message at a time) */
+void wait_message(char *msg, ...) __attribute__ ((format (printf, 1, 2)));
+
+/* call this to finish the wait on wait_message */
+void remove_wait_message(void);
+
+/* monitor progression of something (downloading a file, etc)
+ * if size of progression is unknown, use `0' */
+void init_progression(char *msg, int size);
+void update_progression(int current_size);
+void end_progression(void);
+
+enum frontend_return { RETURN_OK, RETURN_BACK, RETURN_ERROR };
+
+/* Yes == RETURN_OK No == RETURN_ERROR Back == RETURN_BACK */
+enum frontend_return ask_yes_no(char *msg);
+
+/* [elems] NULL terminated array of char*
+ * [choice] address of a (unitialized) char* */
+enum frontend_return ask_from_list(char *msg, char ** elems, char ** choice);
+
+enum frontend_return ask_from_list_comments(char *msg, char ** elems, char ** elems_comments, char ** choice);
+
+/* [questions] NULL terminated array of char*
+ * [answers] address of a (unitialized) char**, will contain a non-NULL terminated array of char*
+ * [callback_func] function called at most when the answers change; it can examine the array of char* and assign some new char* */
+enum frontend_return ask_from_entries(char *msg, char ** questions, char *** answers, int entry_size, void (*callback_func)(char ** strings));
+
+#endif
diff --git a/mdk-stage1/frontend-common.c b/mdk-stage1/frontend-common.c
new file mode 100644
index 000000000..6ea2984cd
--- /dev/null
+++ b/mdk-stage1/frontend-common.c
@@ -0,0 +1,64 @@
+/*
+ * Guillaume Cottenceau (gc@mandrakesoft.com)
+ *
+ * Copyright 2000 Mandrakesoft
+ *
+ * This software may be freely redistributed under the terms of the GNU
+ * public license.
+ *
+ * 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.
+ *
+ */
+
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+
+#include <probing.h>
+
+#include "frontend.h"
+
+
+void info_message(char *msg, ...)
+{
+ va_list args;
+ va_start(args, msg);
+ vinfo_message(msg, args);
+ va_end(args);
+}
+
+void wait_message(char *msg, ...)
+{
+ va_list args;
+ va_start(args, msg);
+ vwait_message(msg, args);
+ va_end(args);
+}
+
+void error_message(char *msg, ...)
+{
+ va_list args;
+ va_start(args, msg);
+ verror_message(msg, args);
+ va_end(args);
+}
+
+enum return_type ask_from_list_comments(char *msg, char ** elems, char ** elems_comments, char ** choice)
+{
+ int answer = 0;
+ enum return_type results;
+
+ results = ask_from_list_index(msg, elems, elems_comments, &answer);
+
+ if (results == RETURN_OK)
+ *choice = strdup(elems[answer]);
+
+ return results;
+}
+
+enum return_type ask_from_list(char *msg, char ** elems, char ** choice)
+{
+ return ask_from_list_comments(msg, elems, NULL, choice);
+}
diff --git a/mdk-stage1/frontend.h b/mdk-stage1/frontend.h
new file mode 100644
index 000000000..4c2558b4a
--- /dev/null
+++ b/mdk-stage1/frontend.h
@@ -0,0 +1,68 @@
+/*
+ * Guillaume Cottenceau (gc@mandrakesoft.com)
+ *
+ * Copyright 2000 Mandrakesoft
+ *
+ * This software may be freely redistributed under the terms of the GNU
+ * public license.
+ *
+ * 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.
+ *
+ */
+
+/*
+ * For doc please read doc/documented..frontend.h
+ */
+
+#ifndef _FRONTEND_H_
+#define _FRONTEND_H_
+
+#include <stdarg.h>
+
+/* 'unused' atttribute, gcc specific and just to turn down some warnings. */
+#if defined __GNUC__
+#define UNUSED __attribute__((unused))
+#else
+#define UNUSED
+#endif
+
+enum return_type { RETURN_OK, RETURN_BACK, RETURN_ERROR };
+
+void init_frontend(char * welcome_msg);
+void finish_frontend(void);
+
+void error_message(char *msg, ...) __attribute__ ((format (printf, 1, 2))); /* blocking */
+void info_message(char *msg, ...) __attribute__ ((format (printf, 1, 2))); /* blocking */
+void wait_message(char *msg, ...) __attribute__ ((format (printf, 1, 2))); /* non-blocking */
+void remove_wait_message(void);
+
+void init_progression_raw(char *msg, int size);
+void update_progression_raw(int current_size);
+void end_progression_raw(void);
+
+#ifdef ENABLE_BOOTSPLASH
+void init_progression(char *msg, int size);
+void update_progression(int current_size);
+void end_progression(void);
+#else
+#define init_progression init_progression_raw
+#define update_progression update_progression_raw
+#define end_progression end_progression_raw
+#endif
+
+enum return_type ask_yes_no(char *msg);
+enum return_type ask_from_list_index(char *msg, char ** elems, char ** elems_comments, int *answer);
+enum return_type ask_from_list(char *msg, char ** elems, char ** choice);
+enum return_type ask_from_list_comments(char *msg, char ** elems, char ** elems_comments, char ** choice);
+enum return_type ask_from_entries(char *msg, char ** questions, char *** answers, int entry_size, void (*callback_func)(char ** strings));
+
+void suspend_to_console(void);
+void resume_from_suspend(void);
+
+void verror_message(char *msg, va_list ap);
+void vinfo_message(char *msg, va_list ap);
+void vwait_message(char *msg, va_list ap);
+
+#endif
diff --git a/mdk-stage1/init.c b/mdk-stage1/init.c
new file mode 100644
index 000000000..51fef09b4
--- /dev/null
+++ b/mdk-stage1/init.c
@@ -0,0 +1,565 @@
+/*
+ * Guillaume Cottenceau (gc@mandrakesoft.com)
+ *
+ * Copyright 2000 Mandrakesoft
+ *
+ * This software may be freely redistributed under the terms of the GNU
+ * public license.
+ *
+ * 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.
+ *
+ */
+
+/*
+ * Portions from Erik Troan (ewt@redhat.com)
+ *
+ * Copyright 1996 Red Hat Software
+ *
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/mount.h>
+#include <linux/un.h>
+#include <errno.h>
+#include <signal.h>
+#include <sys/resource.h>
+#include <sys/wait.h>
+#include <linux/unistd.h>
+#include <sys/select.h>
+#include <sys/ioctl.h>
+
+#include <sys/syscall.h>
+#define syslog(...) syscall(__NR_syslog, __VA_ARGS__)
+#define reboot(...) syscall(__NR_reboot, __VA_ARGS__)
+
+#include "config-stage1.h"
+#include <linux/cdrom.h>
+
+#if defined(__powerpc__)
+#define TIOCSCTTY 0x540E
+#endif
+
+
+#define BINARY "/sbin/stage1"
+#define BINARY_STAGE2 "/usr/bin/runinstall2"
+
+
+char * env[] = {
+ "PATH=/usr/bin:/bin:/sbin:/usr/sbin:/mnt/sbin:/mnt/usr/sbin:/mnt/bin:/mnt/usr/bin",
+ "LD_LIBRARY_PATH=/lib:/usr/lib:/mnt/lib:/mnt/usr/lib:/usr/X11R6/lib:/mnt/usr/X11R6/lib"
+#if defined(__x86_64__) || defined(__ppc64__)
+ ":/lib64:/usr/lib64:/usr/X11R6/lib64:/mnt/lib64:/mnt/usr/lib64:/mnt/usr/X11R6/lib64"
+#endif
+ ,
+ "HOME=/",
+ "TERM=linux",
+ "TERMINFO=/etc/terminfo",
+ NULL
+};
+
+
+/*
+ * this needs to handle the following cases:
+ *
+ * 1) run from a CD root filesystem
+ * 2) run from a read only nfs rooted filesystem
+ * 3) run from a floppy
+ * 4) run from a floppy that's been loaded into a ramdisk
+ *
+ */
+
+int testing = 0;
+int klog_pid;
+
+
+void fatal_error(char *msg)
+{
+ printf("FATAL ERROR IN INIT: %s\n\nI can't recover from this, please reboot manually and send bugreport.\n", msg);
+ select(0, NULL, NULL, NULL, NULL);
+}
+
+void print_error(char *msg)
+{
+ printf("E: %s\n", msg);
+}
+
+void print_warning(char *msg)
+{
+ printf("W: %s\n", msg);
+}
+
+void print_int_init(int fd, int i)
+{
+ char buf[10];
+ char * chptr = buf + 9;
+ int j = 0;
+
+ if (i < 0)
+ {
+ write(1, "-", 1);
+ i = -1 * i;
+ }
+
+ while (i)
+ {
+ *chptr-- = '0' + (i % 10);
+ j++;
+ i = i / 10;
+ }
+
+ write(fd, chptr + 1, j);
+}
+
+void print_str_init(int fd, char * string)
+{
+ write(fd, string, strlen(string));
+}
+
+/* fork to:
+ * (1) watch /proc/kmsg and copy the stuff to /dev/tty4
+ * (2) listens to /dev/log and copy also this stuff (log from programs)
+ */
+void doklog()
+{
+ fd_set readset, unixs;
+ int in, out, i;
+ int log;
+ socklen_t s;
+ int sock = -1;
+ struct sockaddr_un sockaddr;
+ char buf[1024];
+ int readfd;
+
+ /* open kernel message logger */
+ in = open("/proc/kmsg", O_RDONLY,0);
+ if (in < 0) {
+ print_error("could not open /proc/kmsg");
+ return;
+ }
+
+ mkdir("/tmp", 0755);
+ if ((log = open("/tmp/syslog", O_WRONLY | O_CREAT | O_APPEND, 0644)) < 0) {
+ print_error("error opening /tmp/syslog");
+ sleep(5);
+ return;
+ }
+
+ if ((klog_pid = fork())) {
+ close(in);
+ close(log);
+ return;
+ } else {
+ close(0);
+ close(1);
+ close(2);
+ }
+
+ out = open("/dev/tty4", O_WRONLY, 0);
+ if (out < 0)
+ print_warning("couldn't open tty for syslog -- still using /tmp/syslog\n");
+
+ /* now open the syslog socket */
+// ############# LINUX 2.4 /dev/log IS BUGGED! --> apparently the syslogs can't reach me, and it's full up after a while
+// sockaddr.sun_family = AF_UNIX;
+// strncpy(sockaddr.sun_path, "/dev/log", UNIX_PATH_MAX);
+// sock = socket(AF_UNIX, SOCK_STREAM, 0);
+// if (sock < 0) {
+// printf("error creating socket: %d\n", errno);
+// sleep(5);
+// }
+//
+// print_str_init(log, "] got socket\n");
+// if (bind(sock, (struct sockaddr *) &sockaddr, sizeof(sockaddr.sun_family) + strlen(sockaddr.sun_path))) {
+// print_str_init(log, "] bind error: ");
+// print_int_init(log, errno);
+// print_str_init(log, "\n");
+// sleep(// }
+//
+// print_str_init(log, "] bound socket\n");
+// chmod("/dev/log", 0666);
+// if (listen(sock, 5)) {
+// print_str_init(log, "] listen error: ");
+// print_int_init(log, errno);
+// print_str_init(log, "\n");
+// sleep(5);
+// }
+
+ /* disable on-console syslog output */
+ syslog(8, NULL, 1);
+
+ print_str_init(log, "] kernel/system logger ok\n");
+ FD_ZERO(&unixs);
+ while (1) {
+ memcpy(&readset, &unixs, sizeof(unixs));
+
+ if (sock >= 0)
+ FD_SET(sock, &readset);
+ FD_SET(in, &readset);
+
+ i = select(20, &readset, NULL, NULL, NULL);
+ if (i <= 0)
+ continue;
+
+ /* has /proc/kmsg things to tell us? */
+ if (FD_ISSET(in, &readset)) {
+ i = read(in, buf, sizeof(buf));
+ if (i > 0) {
+ if (out >= 0)
+ write(out, buf, i);
+ write(log, buf, i);
+ }
+ }
+
+ /* examine some fd's in the hope to find some syslog outputs from programs */
+ for (readfd = 0; readfd < 20; ++readfd) {
+ if (FD_ISSET(readfd, &readset) && FD_ISSET(readfd, &unixs)) {
+ i = read(readfd, buf, sizeof(buf));
+ if (i > 0) {
+ /* grep out the output of RPM telling that it installed/removed some packages */
+ if (!strstr(buf, "mdk installed") && !strstr(buf, "mdk removed")) {
+ if (out >= 0)
+ write(out, buf, i);
+ write(log, buf, i);
+ }
+ } else if (i == 0) {
+ /* socket closed */
+ close(readfd);
+ FD_CLR(readfd, &unixs);
+ }
+ }
+ }
+
+ /* the socket has moved, new stuff to do */
+ if (sock >= 0 && FD_ISSET(sock, &readset)) {
+ s = sizeof(sockaddr);
+ readfd = accept(sock, (struct sockaddr *) &sockaddr, &s);
+ if (readfd < 0) {
+ char * msg_error = "] error in accept\n";
+ if (out >= 0)
+ write(out, msg_error, strlen(msg_error));
+ write(log, msg_error, strlen(msg_error));
+ close(sock);
+ sock = -1;
+ }
+ else
+ FD_SET(readfd, &unixs);
+ }
+ }
+}
+
+
+#define LOOP_CLR_FD 0x4C01
+
+void del_loops(void)
+{
+ char loopdev[] = "/dev/loop0";
+ char chloopdev[] = "/dev/chloop0";
+ int i;
+ for (i=0; i<8; i++) {
+ int fd;
+ loopdev[9] = '0' + i;
+ fd = open(loopdev, O_RDONLY, 0);
+ if (fd > 0) {
+ if (!ioctl(fd, LOOP_CLR_FD, 0))
+ printf("\t%s\n", loopdev);
+ close(fd);
+ }
+ chloopdev[11] = '0' + i;
+ fd = open(chloopdev, O_RDONLY, 0);
+ if (fd > 0) {
+ if (!ioctl(fd, LOOP_CLR_FD, 0))
+ printf("\t%s\n", chloopdev);
+ close(fd);
+ }
+ }
+}
+
+struct filesystem
+{
+ char * dev;
+ char * name;
+ char * fs;
+ int mounted;
+};
+
+char* strcat(register char* s,register const char* t)
+{
+ char *dest=s;
+ s+=strlen(s);
+ for (;;) {
+ if (!(*s = *t)) break; ++s; ++t;
+ }
+ return dest;
+}
+
+/* attempt to unmount all filesystems in /proc/mounts */
+void unmount_filesystems(void)
+{
+ int fd, size;
+ char buf[65535]; /* this should be big enough */
+ char *p;
+ struct filesystem fs[500];
+ int numfs = 0;
+ int i, nb;
+ int disallow_eject = 0;
+
+ printf("unmounting filesystems...\n");
+
+ fd = open("/proc/mounts", O_RDONLY, 0);
+ if (fd < 1) {
+ print_error("failed to open /proc/mounts");
+ sleep(2);
+ return;
+ }
+
+ size = read(fd, buf, sizeof(buf) - 1);
+ buf[size] = '\0';
+
+ close(fd);
+
+ p = buf;
+ while (*p) {
+ fs[numfs].mounted = 1;
+ fs[numfs].dev = p;
+ while (*p != ' ') p++;
+ *p++ = '\0';
+ fs[numfs].name = p;
+ while (*p != ' ') p++;
+ *p++ = '\0';
+ fs[numfs].fs = p;
+ while (*p != ' ') p++;
+ *p++ = '\0';
+ while (*p != '\n') p++;
+ p++;
+ if (!strcmp(fs[numfs].fs, "nfs"))
+ disallow_eject = 1;
+ if (strcmp(fs[numfs].name, "/")
+ && !strstr(fs[numfs].dev, "ram")
+ && strcmp(fs[numfs].name, "/dev")
+ && strcmp(fs[numfs].name, "/sys")
+ && strncmp(fs[numfs].name, "/proc", 5))
+ numfs++;
+ }
+
+ /* Pixel's ultra-optimized sorting algorithm:
+ multiple passes trying to umount everything until nothing moves
+ anymore (a.k.a holy shotgun method) */
+ do {
+ nb = 0;
+ for (i = 0; i < numfs; i++) {
+ /*printf("trying with %s\n", fs[i].name);*/
+ del_loops();
+ if (fs[i].mounted && umount(fs[i].name) == 0) {
+ printf("\t%s\n", fs[i].name);
+ fs[i].mounted = 0;
+ nb++;
+ }
+ }
+ } while (nb);
+
+ for (i = nb = 0; i < numfs; i++)
+ if (fs[i].mounted) {
+ printf("\tumount failed: %s\n", fs[i].name);
+ if (strcmp(fs[i].fs, "ext3") == 0) nb++; /* don't count not-ext3 umount failed */
+ }
+
+
+ if (nb) {
+ printf("failed to umount some filesystems\n");
+ select(0, NULL, NULL, NULL, NULL);
+ }
+}
+
+#define BMAGIC_HARD 0x89ABCDEF
+#define BMAGIC_SOFT 0
+#define BMAGIC_REBOOT 0x01234567
+#define BMAGIC_HALT 0xCDEF0123
+#define BMAGIC_POWEROFF 0x4321FEDC
+int reboot_magic = BMAGIC_REBOOT;
+
+int in_reboot(void)
+{
+ int fd;
+ if ((fd = open("/var/run/rebootctl", O_RDONLY, 0)) > 0) {
+ char buf[100];
+ int i = read(fd, buf, sizeof(buf));
+ close(fd);
+ if (strstr(buf, "halt"))
+ reboot_magic = BMAGIC_POWEROFF;
+ return i > 0;
+ }
+ return 0;
+}
+
+int exit_value_proceed = 66;
+int exit_value_restart = 0x35;
+
+int main(int argc, char **argv)
+{
+ pid_t installpid, childpid;
+ int wait_status;
+ int fd;
+ int counter = 0;
+ int abnormal_termination = 0;
+
+ if (argc > 1 && argv[1][0] >= '0' && argv[1][0] <= '9') {
+ printf("This is no normal init, sorry.\n"
+ "Call `reboot' or `halt' directly.\n");
+ return 0;
+ }
+
+ if (!testing) {
+ /* turn off screen blanking */
+ printf("\033[9;0]");
+ printf("\033[8]");
+ }
+ else
+ printf("*** TESTING MODE *** (pid is %d)\n", getpid());
+
+
+ if (!testing) {
+ mkdir("/proc", 0755);
+ if (mount("/proc", "/proc", "proc", 0, NULL))
+ fatal_error("Unable to mount proc filesystem");
+ mkdir("/sys", 0755);
+ if (mount("none", "/sys", "sysfs", 0, NULL))
+ fatal_error("Unable to mount sysfs filesystem");
+ }
+
+
+ /* ignore Control-C and keyboard stop signals */
+ signal(SIGINT, SIG_IGN);
+ signal(SIGTSTP, SIG_IGN);
+
+ if (!testing) {
+ fd = open("/dev/console", O_RDWR, 0);
+ if (fd < 0)
+ fatal_error("failed to open /dev/console");
+
+ dup2(fd, 0);
+ dup2(fd, 1);
+ dup2(fd, 2);
+ close(fd);
+ }
+
+
+ /* I set me up as session leader (probably not necessary?) */
+ setsid();
+// if (ioctl(0, TIOCSCTTY, NULL))
+// print_error("could not set new controlling tty");
+
+ if (!testing) {
+ char my_hostname[] = "localhost";
+ sethostname(my_hostname, sizeof(my_hostname));
+ /* the default domainname (as of 2.0.35) is "(none)", which confuses
+ glibc */
+ setdomainname("", 0);
+ }
+
+ if (!testing)
+ doklog();
+
+ /* Go into normal init mode - keep going, and then do a orderly shutdown
+ when:
+
+ 1) install exits
+ 2) we receive a SIGHUP
+ */
+
+ do {
+ if (counter == 1) {
+ printf("proceeding, please wait...\n");
+ }
+
+ if (!(installpid = fork())) {
+ /* child */
+ char * child_argv[2];
+ child_argv[0] = counter == 0 ? BINARY : BINARY_STAGE2;
+ child_argv[1] = NULL;
+
+ execve(child_argv[0], child_argv, env);
+ printf("error in exec of %s :-( [%d]\n", child_argv[0], errno);
+ return 0;
+ }
+
+ do {
+ childpid = wait4(-1, &wait_status, 0, NULL);
+ } while (childpid != installpid);
+
+ counter++;
+ } while (WIFEXITED(wait_status) && WEXITSTATUS(wait_status) == exit_value_restart);
+
+ /* allow Ctrl Alt Del to reboot */
+ reboot(0xfee1dead, 672274793, BMAGIC_HARD);
+
+ if (in_reboot()) {
+ // any exitcode is valid if we're in_reboot
+ } else if (WIFEXITED(wait_status) && WEXITSTATUS(wait_status) == exit_value_proceed) {
+ kill(klog_pid, 9);
+ printf("proceeding, please wait...\n");
+
+ {
+ char * child_argv[2] = { "/sbin/init", NULL };
+ execve(child_argv[0], child_argv, env);
+ }
+ fatal_error("failed to exec /sbin/init");
+ } else if (!WIFEXITED(wait_status) || WEXITSTATUS(wait_status) != 0) {
+ printf("exited abnormally :-( ");
+ if (WIFSIGNALED(wait_status))
+ printf("-- received signal %d", WTERMSIG(wait_status));
+ printf("\n");
+ abnormal_termination = 1;
+ }
+
+ if (!abnormal_termination) {
+ int i;
+ for (i=0; i<50; i++)
+ printf("\n"); /* cleanup startkde messages */
+ }
+
+ if (testing)
+ return 0;
+
+ sync(); sync();
+ sleep(2);
+
+ printf("sending termination signals...");
+ kill(-1, 15);
+ sleep(2);
+ printf("done\n");
+
+ printf("sending kill signals...");
+ kill(-1, 9);
+ sleep(2);
+ printf("done\n");
+
+ unmount_filesystems();
+
+ sync(); sync();
+
+ if (!abnormal_termination) {
+ if (reboot_magic == BMAGIC_REBOOT) {
+#ifdef DEBUG
+ printf("automatic reboot in 10 seconds\n");
+ sleep(10);
+#endif
+ reboot(0xfee1dead, 672274793, reboot_magic);
+ } else {
+ printf("you may safely poweroff your computer now\n");
+ }
+ } else {
+ printf("you may safely reboot or halt your system\n");
+ }
+
+ select(0, NULL, NULL, NULL, NULL);
+ return 0;
+}
diff --git a/mdk-stage1/ka.c b/mdk-stage1/ka.c
new file mode 100644
index 000000000..7d8325084
--- /dev/null
+++ b/mdk-stage1/ka.c
@@ -0,0 +1,193 @@
+/*
+ * Copyright 2005 Mandrakesoft
+ *
+ * This software may be freely redistributed under the terms of the GNU
+ * public license.
+ *
+ * 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.
+ *
+ */
+
+#include "ka.h"
+#include <sys/mount.h>
+#include "mount.h"
+#include <sys/wait.h>
+#include <dirent.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+
+#include "config-stage1.h"
+#include "frontend.h"
+#include "log.h"
+#include "tools.h"
+
+struct in_addr next_server = { 0 };
+
+#if 0
+static void save_stuff_for_rescue(void)
+{
+ copy_file("/etc/resolv.conf", STAGE2_LOCATION "/etc/resolv.conf", NULL);
+}
+#endif
+
+static void my_pause(void) {
+ unsigned char t;
+ fflush(stdout);
+ read(0, &t, 1);
+}
+
+static enum return_type ka_wait_for_stage2(int count)
+{
+ char * ramdisk = "/dev/ram3"; /* warning, verify that this file exists in the initrd*/
+ char * ka_launch[] = { "/ka/ka-d-client", "-w","-s","getstage2","-e","(cd /tmp/stage2; tar --extract --read-full-records --same-permissions --numeric-owner --sparse --file - )", NULL }; /* The command line for ka_launch */
+ char * mkfs_launch[] = { "/sbin/mke2fs", ramdisk, NULL}; /* The mkfs command for formating the ramdisk */
+
+ log_message("KA: Preparing to receive stage 2....");
+ int pida, wait_status;
+
+ if (!(pida = fork())) { /* Forking current process for running mkfs */
+ close(1);
+ close(2);
+ execv(mkfs_launch[0], mkfs_launch); /* Formating the ramdisk */
+ printf("KA: Can't execute %s\n<press Enter>\n", mkfs_launch[0]);
+ my_pause();
+ return KAERR_CANTFORK;
+ }
+ while (wait4(-1, &wait_status, 0, NULL) != pida) {}; /* Waiting the end of mkfs */
+
+ if (my_mount(ramdisk, STAGE2_LOCATION, "ext2", 1)) {/* Trying to mount the ramdisk */
+ return RETURN_ERROR;
+ }
+
+ log_message("KA: Waiting for stage 2....");
+ wait_message("Waiting for rescue from KA server (Try %d/%d)", count, KA_MAX_RETRY);
+ pid_t pid; /* Process ID of the child process */
+ pid_t wpid; /* Process ID from wait() */
+ int status; /* Exit status from wait() */
+
+ pid = fork();
+ if ( pid == -1 ) {
+ fprintf(stderr, "%s: Failed to fork()\n", strerror(errno));
+ exit(13);
+ } else if ( pid == 0 ) {
+ // close(2);
+ execv(ka_launch[0], ka_launch);
+ } else {
+ // wpid = wait(&status); /* Child's exit status */
+ wpid = wait4(-1, &status, 0, NULL);
+ if ( wpid == -1 ) {
+ fprintf(stderr,"%s: wait()\n", strerror(errno));
+ return RETURN_ERROR;
+ } else if ( wpid != pid )
+ abort();
+ else {
+ if ( WIFEXITED(status) ) {
+ printf("Exited: $? = %d\n", WEXITSTATUS(status));
+ } else if ( WIFSIGNALED(status) ) {
+ printf("Signal: %d%s\n", WTERMSIG(status), WCOREDUMP(status) ? " with core file." : "");
+ }
+ }
+ }
+
+ remove_wait_message();
+ return RETURN_OK;
+ // if (!(pid = fork())) { /* Froking current process for running ka-deploy (client side) */
+ // close(1); /* Closing stdout */
+ // close(2); /* Closing stderr */
+ // execve(ka_launch[0], ka_launch,grab_env()); /* Running ka-deploy (client side) */
+ // printf("KA: Can't execute %s\n<press Enter>\n", ka_launch[0]);
+ // log_message("KA: Can't execute %s\n<press Enter>\n", ka_launch[0]);
+ // my_pause();
+ // return KAERR_CANTFORK;
+ //}
+
+ //while (wait4(-1, &wait_status, 0, NULL) != pid) {}; /* Waiting the end of duplication */
+ // log_message("kalaunch ret %d\n", WIFEXITED(wait_status));
+ // remove_wait_message();
+ //sleep(100000);
+ // return RETURN_OK;
+}
+
+enum return_type perform_ka(void) {
+ enum return_type results;
+ int server_failure = 1; /* Number of time we've failed to find a ka server */
+ FILE *f = fopen ("/ka/tftpserver","w");
+
+ if (f != NULL) {
+ /* Writing the NEXT_SERVER value of the DHCP Request in the /ka/tftpserver file */
+ fprintf(f,"%s\n",inet_ntoa(next_server));
+ fclose(f);
+ }
+
+ log_message("KA: Trying to retrieve stage2 from server");
+ log_message("KA: ka_wait_for_stage2");
+ do {
+ /* We are trying to get a valid stage 2 (rescue) */
+ results=ka_wait_for_stage2(server_failure);
+ if (results != RETURN_OK) {
+ return results;
+ } else {
+ /* Trying to open STAGE2_LOCATION/ka directory */
+ char dir[255] = STAGE2_LOCATION;
+ strcat(dir,"/ka");
+ DIR *dp = opendir(dir);
+
+ /* Does the STAGE2_LOCATION/ka directory exists ? = Does the rescue with ka well downloaded ?*/
+ if (!dp) {
+ log_message("KA: Server not found !");
+ /* Be sure that the STAGE2_LOCATION isn't mounted after receiving a wrong rescue */
+ if (umount (STAGE2_LOCATION)) {
+ log_perror("KA: Unable to umount STAGE2");
+ }
+ int cpt;
+
+ if (server_failure++ == KA_MAX_RETRY){
+ /* if the KA server can't be reach KA_MAX_RETRY times */
+ char * reboot_launch[] = { "/sbin/reboot", NULL};
+ for (cpt=5; cpt>0; cpt--) {
+ wait_message("!!! Can't reach a valid KA server !!! (Rebooting in %d sec)",cpt);
+ sleep (1);
+ }
+ /* Rebooting the computer to avoid infinite loop on ka mode */
+ execv(reboot_launch[0], reboot_launch);
+ }
+
+ for (cpt=5; cpt>0; cpt--) {
+ wait_message("KA server not found ! (Try %d/%d in %d sec)",server_failure,KA_MAX_RETRY,cpt);
+ log_message("Ka not found %d/%d", server_failure,KA_MAX_RETRY);
+ sleep (1);
+ }
+ remove_wait_message();
+ /* We should try another time*/
+ results=RETURN_BACK;
+ continue;
+ }
+
+ if (dp) {
+ log_message("KA: Stage 2 downloaded successfully");
+ closedir(dp); /* Closing the /ka directory */
+ server_failure=1; /* Resetting server_failure */
+ results = RETURN_OK;
+ }
+ }
+
+ log_message("KA: Preparing chroot");
+ return RETURN_OK;
+
+ // if (IS_RESCUE) { /* if we are in rescue mode */
+ // save_stuff_for_rescue(); /* Saving resolve.conf */
+ // if (umount (STAGE2_LOCATION)) { /* Unmounting STAGE2 elseif kernel can't mount it ! */
+ // log_perror("KA: Unable to umount STAGE2");
+ // return RETURN_ERROR;
+ // }
+ // }
+ } while (results == RETURN_BACK);
+
+ // method_name = strdup("ka");
+ return RETURN_OK;
+}
diff --git a/mdk-stage1/ka.h b/mdk-stage1/ka.h
new file mode 100644
index 000000000..3c083af4f
--- /dev/null
+++ b/mdk-stage1/ka.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2005 Mandrakesoft
+ *
+ * This software may be freely redistributed under the terms of the GNU
+ * public license.
+ *
+ * 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.
+ *
+ */
+
+#ifndef _KA_H_
+#define _KA_H_
+
+#define KAERR_CANTFORK -20
+
+enum return_type perform_ka(void);
+
+#endif
diff --git a/mdk-stage1/log.c b/mdk-stage1/log.c
new file mode 100644
index 000000000..a8406f6b2
--- /dev/null
+++ b/mdk-stage1/log.c
@@ -0,0 +1,94 @@
+/*
+ * Guillaume Cottenceau (gc@mandrakesoft.com)
+ *
+ * Copyright 2000 Mandrakesoft
+ *
+ * This software may be freely redistributed under the terms of the GNU
+ * public license.
+ *
+ * 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.
+ *
+ */
+
+/*
+ * Portions from Erik Troan (ewt@redhat.com)
+ *
+ * Copyright 1996 Red Hat Software
+ *
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <errno.h>
+#include "stage1.h"
+
+#include "log.h"
+
+static FILE * logtty = NULL;
+static FILE * logfile = NULL;
+
+
+void vlog_message(const char * s, va_list args)
+{
+ va_list args_copy;
+ va_copy(args_copy, args);
+
+ if (logfile) {
+ fprintf(logfile, "* ");
+ vfprintf(logfile, s, args);
+ fprintf(logfile, "\n");
+ fflush(logfile);
+ }
+ if (logtty) {
+ fprintf(logtty, "* ");
+ vfprintf(logtty, s, args_copy);
+ fprintf(logtty, "\n");
+ fflush(logtty);
+ }
+
+ va_end(args_copy);
+}
+
+
+void log_message(const char * s, ...)
+{
+ va_list args;
+ va_start(args, s);
+ vlog_message(s, args);
+ va_end(args);
+
+ return;
+}
+
+void log_perror(const char *msg)
+{
+ log_message("%s: %s", msg, strerror(errno));
+}
+
+
+void open_log(void)
+{
+ if (!IS_TESTING) {
+ logtty = fopen("/dev/tty3", "w");
+ logfile = fopen("/tmp/stage1.log", "w");
+ }
+ else
+ logfile = fopen("debug.log", "w");
+}
+
+void close_log(void)
+{
+ if (logfile) {
+ log_message("stage1: disconnecting life support systems");
+ fclose(logfile);
+ if (logtty)
+ fclose(logtty);
+ }
+}
diff --git a/mdk-stage1/log.h b/mdk-stage1/log.h
new file mode 100644
index 000000000..6a30fea8f
--- /dev/null
+++ b/mdk-stage1/log.h
@@ -0,0 +1,34 @@
+/*
+ * Guillaume Cottenceau (gc@mandrakesoft.com)
+ *
+ * Copyright 2000 Mandrakesoft
+ *
+ * This software may be freely redistributed under the terms of the GNU
+ * public license.
+ *
+ * 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.
+ *
+ */
+
+/*
+ * Portions from Erik Troan (ewt@redhat.com)
+ *
+ * Copyright 1996 Red Hat Software
+ *
+ */
+
+
+#ifndef _LOG_H_
+#define _LOG_H_
+
+#include <stdarg.h>
+
+void log_message(const char * s, ...) __attribute__ ((format (printf, 1, 2)));
+void vlog_message(const char * s, va_list args);
+void log_perror(const char *msg);
+void open_log(void);
+void close_log(void);
+
+#endif
diff --git a/mdk-stage1/lomount.c b/mdk-stage1/lomount.c
new file mode 100644
index 000000000..2f80ec71c
--- /dev/null
+++ b/mdk-stage1/lomount.c
@@ -0,0 +1,194 @@
+/*
+ * Guillaume Cottenceau (gc@mandrakesoft.com)
+ *
+ * Copyright 2000 Mandrakesoft
+ *
+ * This software may be freely redistributed under the terms of the GNU
+ * public license.
+ *
+ * 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.
+ *
+ */
+
+/* This code comes from util-linux-2.10n (mount/lomount.c)
+ * (this is a simplified version of this code)
+ */
+
+#include <sys/types.h>
+#include <sys/mount.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "stage1.h"
+#include "frontend.h"
+#include "log.h"
+#include "mount.h"
+#include "modules.h"
+
+#include "lomount.h"
+
+
+#define LO_NAME_SIZE 64
+#define LO_KEY_SIZE 32
+
+struct loop_info
+{
+ int lo_number; /* ioctl r/o */
+ dev_t lo_device; /* ioctl r/o */
+ unsigned long lo_inode; /* ioctl r/o */
+ dev_t lo_rdevice; /* ioctl r/o */
+ int lo_offset;
+ int lo_encrypt_type;
+ int lo_encrypt_key_size; /* ioctl w/o */
+ int lo_flags; /* ioctl r/o */
+ char lo_name[LO_NAME_SIZE];
+ unsigned char lo_encrypt_key[LO_KEY_SIZE]; /* ioctl w/o */
+ unsigned long lo_init[2];
+ char reserved[4];
+};
+
+#define LOOP_SET_FD 0x4C00
+#define LOOP_CLR_FD 0x4C01
+#define LOOP_SET_STATUS 0x4C02
+#define LOOP_GET_STATUS 0x4C03
+
+int
+set_loop (const char *device, const char *file)
+{
+ struct loop_info loopinfo;
+ int fd, ffd, mode;
+
+ mode = O_RDONLY;
+
+ if ((ffd = open (file, mode)) < 0)
+ return 1;
+
+ if ((fd = open (device, mode)) < 0) {
+ close(ffd);
+ return 1;
+ }
+
+ memset(&loopinfo, 0, sizeof (loopinfo));
+ strncpy(loopinfo.lo_name, file, LO_NAME_SIZE);
+ loopinfo.lo_name[LO_NAME_SIZE - 1] = 0;
+ loopinfo.lo_offset = 0;
+
+#ifdef MCL_FUTURE
+ /*
+ * Oh-oh, sensitive data coming up. Better lock into memory to prevent
+ * passwd etc being swapped out and left somewhere on disk.
+ */
+
+ if(mlockall(MCL_CURRENT|MCL_FUTURE)) {
+ log_message("CRITICAL Couldn't lock into memory! %s (memlock)", strerror(errno));
+ return 1;
+ }
+#endif
+
+ if (ioctl(fd, LOOP_SET_FD, ffd) < 0) {
+ close(fd);
+ close(ffd);
+ return 1;
+ }
+
+ if (ioctl(fd, LOOP_SET_STATUS, &loopinfo) < 0) {
+ (void) ioctl (fd, LOOP_CLR_FD, 0);
+ close(fd);
+ close(ffd);
+ return 1;
+ }
+
+ close(fd);
+ close(ffd);
+ return 0;
+}
+
+
+char* find_free_loop()
+{
+ struct loop_info loopinfo;
+ int i;
+ for (i=0; i<256; i++) {
+ int fd;
+ char ldev[100];
+ sprintf(ldev, "/dev/loop%d", i);
+ ensure_dev_exists(ldev);
+ fd = open(ldev, O_RDONLY);
+ if (!ioctl(fd, LOOP_GET_STATUS, &loopinfo)) {
+ close(fd);
+ continue;
+ }
+ if (errno == ENXIO) {
+ log_message("%s is available", ldev);
+ close(fd);
+ return strdup(ldev);
+ } else {
+ log_perror("LOOP_GET_STATUS(unexpected error)");
+ close(fd);
+ continue;
+ }
+ }
+ return NULL;
+}
+
+void
+del_loop(char * loopdev)
+{
+ int fd;
+
+ if (!loopdev)
+ return;
+
+ if ((fd = open (loopdev, O_RDONLY)) < 0)
+ return;
+
+ if (ioctl (fd, LOOP_CLR_FD, 0) < 0)
+ return;
+
+ close (fd);
+}
+
+int
+lomount(char *loopfile, char *where, char **dev, int compressed)
+{
+
+ long int flag;
+ char * loopdev;
+
+ flag = MS_MGC_VAL;
+ flag |= MS_RDONLY;
+
+ my_insmod("loop", ANY_DRIVER_TYPE, "max_loop=256", 1);
+ if (compressed) {
+ my_insmod("squashfs", ANY_DRIVER_TYPE, NULL, 1);
+ }
+
+ if (!(loopdev = find_free_loop())) {
+ log_message("could not find a free loop");
+ return 1;
+ }
+ if (dev)
+ *dev = loopdev;
+
+ if (set_loop(loopdev, loopfile)) {
+ log_message("set_loop failed on %s (%s)", loopdev, strerror(errno));
+ return 1;
+ }
+
+ if (my_mount(loopdev, where, compressed ? "squashfs" : "iso9660", 0)) {
+ del_loop(loopdev);
+ return 1;
+ }
+
+ log_message("lomount succeeded for %s on %s", loopfile, where);
+ return 0;
+}
+
+
diff --git a/mdk-stage1/lomount.h b/mdk-stage1/lomount.h
new file mode 100644
index 000000000..4115507f2
--- /dev/null
+++ b/mdk-stage1/lomount.h
@@ -0,0 +1,21 @@
+/*
+ * Guillaume Cottenceau (gc@mandrakesoft.com)
+ *
+ * Copyright 2000 Mandrakesoft
+ *
+ * This software may be freely redistributed under the terms of the GNU
+ * public license.
+ *
+ * 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.
+ *
+ */
+
+#ifndef LOMOUNT_H
+#define LOMOUNT_H
+
+int lomount(char *loopfile, char *where, char **loopdev, int compressed);
+void del_loop(char *loopdev);
+
+#endif
diff --git a/mdk-stage1/modules.c b/mdk-stage1/modules.c
new file mode 100644
index 000000000..53bc87d4c
--- /dev/null
+++ b/mdk-stage1/modules.c
@@ -0,0 +1,478 @@
+/*
+ * Guillaume Cottenceau (gc@mandrakesoft.com)
+ *
+ * Copyright 2000 Mandrakesoft
+ *
+ * This software may be freely redistributed under the terms of the GNU
+ * public license.
+ *
+ * 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.
+ *
+ */
+
+/*
+ * (1) calculate dependencies
+ * (2) unarchive relevant modules
+ * (3) insmod them
+ */
+
+#include "stage1.h"
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mount.h>
+#include <fcntl.h>
+#include <libgen.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <sys/utsname.h>
+#include "log.h"
+#include "utils.h"
+#include "frontend.h"
+#include "mount.h"
+#include "zlibsupport.h"
+
+#include "modules.h"
+
+#define FIRMWARE_TIMEOUT_FILE "/sys/class/firmware/timeout"
+#define FIRMWARE_TIMEOUT_VALUE "1"
+
+static char modules_directory[100];
+static struct module_deps_elem * modules_deps = NULL;
+static struct module_descr_elem * modules_descr = NULL;
+
+extern long init_module(void *, unsigned long, const char *);
+
+
+static const char *moderror(int err)
+{
+ switch (err) {
+ case ENOEXEC:
+ return "Invalid module format";
+ case ENOENT:
+ return "Unknown symbol in module";
+ case ESRCH:
+ return "Module has wrong symbol version";
+ case EINVAL:
+ return "Invalid parameters";
+ default:
+ return strerror(err);
+ }
+}
+
+int insmod_local_file(char * path, char * options)
+{
+ void *file;
+ unsigned long len;
+ int rc;
+
+ if (IS_TESTING)
+ return 0;
+
+ file = grab_file(path, &len);
+
+ if (!file) {
+ log_perror(asprintf_("\terror reading %s", path));
+ return -1;
+ }
+
+ rc = init_module(file, len, options ? options : "");
+ if (rc)
+ log_message("\terror: %s", moderror(errno));
+ return rc;
+}
+
+static char *kernel_module_extension(void)
+{
+ return ".ko.gz";
+}
+
+
+static char *filename2modname(char * filename) {
+ char *modname, *p;
+
+ modname = strdup(basename(filename));
+ if (strstr(modname, kernel_module_extension())) {
+ modname[strlen(modname)-strlen(kernel_module_extension())] = '\0'; /* remove trailing .ko.gz */
+ }
+
+ p = modname;
+ while (p && *p) {
+ if (*p == '-')
+ *p = '_';
+ p++;
+ }
+
+ return modname;
+}
+
+static void find_modules_directory(void)
+{
+ struct utsname kernel_uname;
+ char * prefix = "/lib/modules";
+ char * release;
+ if (uname(&kernel_uname)) {
+ fatal_error("uname failed");
+ }
+ release = kernel_uname.release;
+ sprintf(modules_directory , "%s/%s", prefix, release);
+}
+
+static int load_modules_dependencies(void)
+{
+ char * deps_file = asprintf_("%s/%s", modules_directory, "modules.dep");
+ char * buf, * ptr, * start, * end;
+ struct stat s;
+ int line, i;
+
+ log_message("loading modules dependencies");
+ buf = cat_file(deps_file, &s);
+ if (!buf)
+ return -1;
+ line = line_counts(buf);
+ modules_deps = malloc(sizeof(*modules_deps) * (line+1));
+
+ start = buf;
+ line = 0;
+ while (start < (buf+s.st_size) && *start) {
+ char * tmp_deps[50];
+
+ end = strchr(start, '\n');
+ *end = '\0';
+
+ ptr = strchr(start, ':');
+ if (!ptr) {
+ start = end + 1;
+ continue;
+ }
+ *ptr = '\0';
+ ptr++;
+
+ while (*ptr && (*ptr == ' ')) ptr++;
+
+ /* sort of a good line */
+ modules_deps[line].filename = strdup(start);
+ modules_deps[line].modname = filename2modname(start);
+
+ start = ptr;
+ i = 0;
+ while (start && *start) {
+ ptr = strchr(start, ' ');
+ if (ptr) *ptr = '\0';
+ tmp_deps[i++] = filename2modname(start);
+ if (ptr)
+ start = ptr + 1;
+ else
+ start = NULL;
+ while (start && *start && *start == ' ')
+ start++;
+ }
+ tmp_deps[i++] = NULL;
+
+ modules_deps[line].deps = memdup(tmp_deps, sizeof(char *) * i);
+
+ line++;
+ start = end + 1;
+ }
+ modules_deps[line].modname = NULL;
+
+ free(buf);
+
+ return 0;
+}
+
+
+static int load_modules_descriptions(void)
+{
+ char * descr_file = asprintf_("%s/%s", modules_directory, "modules.description");
+ char * buf, * ptr, * start, * end;
+ struct stat s;
+ int line;
+
+ log_message("loading modules descriptions");
+
+ buf = cat_file(descr_file, &s);
+ if (!buf)
+ return -1;
+ line = line_counts(buf);
+ modules_descr = malloc(sizeof(*modules_descr) * (line+1));
+
+ start = buf;
+ line = 0;
+ while (start < (buf+s.st_size) && *start) {
+ end = strchr(start, '\n');
+ *end = '\0';
+
+ ptr = strchr(start, '\t');
+ if (!ptr) {
+ start = end + 1;
+ continue;
+ }
+ *ptr = '\0';
+ ptr++;
+
+ modules_descr[line].modname = filename2modname(start);
+ modules_descr[line].description = strndup(ptr, 50);
+
+ line++;
+ start = end + 1;
+ }
+ modules_descr[line].modname = NULL;
+
+ free(buf);
+
+ return 0;
+}
+
+void init_firmware_timeout(void)
+{
+ int fd = open(FIRMWARE_TIMEOUT_FILE, O_WRONLY|O_TRUNC, 0666);
+ if (!fd) {
+ log_message("warning, unable to set firmware timeout");
+ return;
+ }
+ write(fd, FIRMWARE_TIMEOUT_VALUE, strlen(FIRMWARE_TIMEOUT_VALUE));
+ close(fd);
+}
+
+void init_modules_insmoding(void)
+{
+ find_modules_directory();
+ if (load_modules_dependencies()) {
+ fatal_error("warning, error initing modules stuff, modules loading disabled");
+ }
+ if (load_modules_descriptions()) {
+ log_message("warning, error initing modules stuff, modules loading disabled");
+ }
+}
+
+
+static void add_modules_conf(char * str)
+{
+ static char data[5000] = "";
+ char * target = "/tmp/modules.conf";
+ int fd;
+
+ if (strlen(data) + strlen(str) >= sizeof(data))
+ return;
+
+ strcat(data, str);
+ strcat(data, "\n");
+
+ fd = open(target, O_CREAT|O_WRONLY|O_TRUNC, 00660);
+
+ if (fd == -1) {
+ log_perror(str);
+ return;
+ }
+
+ if (write(fd, data, strlen(data) + 1) != (ssize_t) (strlen(data) + 1))
+ log_perror(str);
+
+ close(fd);
+}
+
+
+int module_already_present(const char * name)
+{
+ FILE * f;
+ int answ = 0;
+
+ if ((f = fopen("/proc/modules", "rb"))) {
+ while (1) {
+ char buf[500];
+ if (!fgets(buf, sizeof(buf), f)) break;
+ if (!strncmp(name, buf, strlen(name)) && buf[strlen(name)] == ' ')
+ answ = 1;
+ }
+ fclose(f);
+ }
+ return answ;
+}
+
+
+#ifndef ENABLE_NETWORK_STANDALONE
+static enum insmod_return insmod_with_deps(const char * mod_name, char * options, int allow_modules_floppy)
+{
+ struct module_deps_elem * dep;
+ const char * filename;
+
+ dep = modules_deps;
+ while (dep && dep->modname && strcmp(dep->modname, mod_name)) dep++;
+
+ if (dep && dep->modname && dep->deps) {
+ char ** one_dep;
+ one_dep = dep->deps;
+ while (*one_dep) {
+ /* here, we can fail but we don't care, if the error is
+ * important, the desired module will fail also */
+ insmod_with_deps(*one_dep, NULL, allow_modules_floppy);
+ one_dep++;
+ }
+ }
+
+ if (dep && dep->filename) {
+ filename = dep->filename;
+ } else {
+ log_message("warning: unable to get module filename for %s", mod_name);
+ filename = mod_name;
+ }
+
+ if (module_already_present(mod_name))
+ return INSMOD_OK;
+
+ log_message("needs %s", filename);
+ {
+ return insmod_local_file((char *) filename, options);
+ }
+}
+#endif
+
+
+#ifndef DISABLE_NETWORK
+enum insmod_return my_insmod(const char * mod_name, enum driver_type type, char * options, int allow_modules_floppy)
+#else
+enum insmod_return my_insmod(const char * mod_name, enum driver_type type __attribute__ ((unused)), char * options, int allow_modules_floppy)
+#endif
+{
+ int i;
+#ifndef DISABLE_NETWORK
+ char ** net_devices = NULL; /* fucking compiler */
+#endif
+
+ if (module_already_present(mod_name))
+ return INSMOD_OK;
+
+ log_message("have to insmod %s", mod_name);
+
+#ifndef DISABLE_NETWORK
+ if (type == NETWORK_DEVICES)
+ net_devices = get_net_devices();
+#endif
+
+#ifdef ENABLE_NETWORK_STANDALONE
+ {
+ char *cmd = options ? asprintf_("/sbin/modprobe %s %s", mod_name, options) :
+ asprintf_("/sbin/modprobe %s", mod_name);
+ log_message("running %s", cmd);
+ i = system(cmd);
+ }
+#else
+ i = insmod_with_deps(mod_name, options, allow_modules_floppy);
+#endif
+ if (i == 0) {
+ log_message("\tsucceeded %s", mod_name);
+#ifndef DISABLE_NETWORK
+ if (type == NETWORK_DEVICES) {
+ char ** new_net_devices = get_net_devices();
+ while (new_net_devices && *new_net_devices) {
+ char alias[500];
+ char ** ptr = net_devices;
+ while (ptr && *ptr) {
+ if (!strcmp(*new_net_devices, *ptr))
+ goto already_present;
+ ptr++;
+ }
+ sprintf(alias, "alias %s %s", *new_net_devices, mod_name);
+ add_modules_conf(alias);
+ log_message("NET: %s", alias);
+ net_discovered_interface(*new_net_devices);
+
+ already_present:
+ new_net_devices++;
+ }
+ }
+#endif
+ } else
+ log_message("warning, insmod failed (%s %s) (%d)", mod_name, options, i);
+
+ return i;
+
+}
+
+static enum return_type insmod_with_options(char * mod, enum driver_type type)
+{
+ char * questions[] = { "Options", NULL };
+ static char ** answers = NULL;
+ enum return_type results;
+ char options[500] = "options ";
+
+ results = ask_from_entries("Please enter the parameters to give to the kernel:", questions, &answers, 24, NULL);
+ if (results != RETURN_OK)
+ return results;
+
+ strcat(options, mod);
+ strcat(options, " ");
+ strcat(options, answers[0]); // because my_insmod will eventually modify the string
+
+ if (my_insmod(mod, type, answers[0], 1) != INSMOD_OK) {
+ stg1_error_message("Insmod failed.");
+ return RETURN_ERROR;
+ }
+
+ add_modules_conf(options);
+
+ return RETURN_OK;
+}
+
+enum return_type ask_insmod(enum driver_type type)
+{
+ enum return_type results;
+ char * choice;
+ char ** dlist = list_directory(modules_directory);
+ char ** modules = alloca(sizeof(char *) * (string_array_length(dlist) + 1));
+ char ** descrs = alloca(sizeof(char *) * (string_array_length(dlist) + 1));
+ char ** p_dlist = dlist;
+ char ** p_modules = modules;
+ char ** p_descrs = descrs;
+
+ unset_automatic(); /* we are in a fallback mode */
+
+ while (p_dlist && *p_dlist) {
+ struct module_descr_elem * descr;
+
+ if (!strstr(*p_dlist, kernel_module_extension())) {
+ p_dlist++;
+ continue;
+ }
+ *p_modules = *p_dlist;
+ *p_descrs = NULL;
+ (*p_modules)[strlen(*p_modules)-strlen(kernel_module_extension())] = '\0'; /* remove trailing .ko.gz */
+
+ descr = modules_descr;
+ while (descr && descr->modname && strcmp(descr->modname, *p_modules)) descr++;
+ if (descr)
+ *p_descrs = descr->description;
+
+ p_dlist++;
+ p_modules++;
+ p_descrs++;
+ }
+ *p_modules = NULL;
+ *p_descrs = NULL;
+
+ if (modules && *modules) {
+ char * mytype;
+ char msg[200];
+ if (type == MEDIA_ADAPTERS)
+ mytype = "MEDIA";
+ else if (type == NETWORK_DEVICES)
+ mytype = "NET";
+ else
+ return RETURN_ERROR;
+
+ snprintf(msg, sizeof(msg), "Which driver should I try to gain %s access?", mytype);
+ results = ask_from_list_comments(msg, modules, descrs, &choice);
+ if (results == RETURN_OK)
+ return insmod_with_options(choice, type);
+ else
+ return results;
+ } else {
+ return RETURN_BACK;
+ }
+}
diff --git a/mdk-stage1/modules.h b/mdk-stage1/modules.h
new file mode 100644
index 000000000..8a57b9e41
--- /dev/null
+++ b/mdk-stage1/modules.h
@@ -0,0 +1,43 @@
+/*
+ * Guillaume Cottenceau (gc@mandrakesoft.com)
+ *
+ * Copyright 2000 Mandrakesoft
+ *
+ * This software may be freely redistributed under the terms of the GNU
+ * public license.
+ *
+ * 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.
+ *
+ */
+
+#ifndef _MODULES_H_
+#define _MODULES_H_
+
+#include "stage1.h"
+#include "probing.h"
+
+enum insmod_return { INSMOD_OK, INSMOD_FAILED, INSMOD_FAILED_FILE_NOT_FOUND };
+
+void init_modules_insmoding(void);
+void init_firmware_timeout(void);
+int insmod_local_file(char * path, char * options);
+enum insmod_return my_insmod(const char * mod_name, enum driver_type type, char * options, int allow_modules_floppy);
+enum return_type ask_insmod(enum driver_type);
+int module_already_present(const char * name);
+
+struct module_deps_elem {
+ char * modname;
+ char * filename;
+ char ** deps;
+};
+
+struct module_descr_elem {
+ char * modname;
+ char * description;
+};
+
+extern int disable_modules;
+
+#endif
diff --git a/mdk-stage1/mount.c b/mdk-stage1/mount.c
new file mode 100644
index 000000000..23e8465d4
--- /dev/null
+++ b/mdk-stage1/mount.c
@@ -0,0 +1,239 @@
+/*
+ * Guillaume Cottenceau (gc@mandrakesoft.com)
+ *
+ * Copyright 2000 Mandrakesoft
+ *
+ * This software may be freely redistributed under the terms of the GNU
+ * public license.
+ *
+ * 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.
+ *
+ */
+
+/*
+ * Portions from Erik Troan (ewt@redhat.com)
+ *
+ * Copyright 1996 Red Hat Software
+ *
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdio.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include "log.h"
+#include "utils.h"
+#include "modules.h"
+
+#include "mount.h"
+
+
+
+/* WARNING: this won't work if the argument is not /dev/ based */
+int ensure_dev_exists(const char * dev)
+{
+ int major, minor;
+ int type = S_IFBLK; /* my default type is block. don't forget to change for chars */
+ const char * name;
+ struct stat buf;
+ char * ptr;
+
+ name = &dev[5]; /* we really need that dev be passed as /dev/something.. */
+
+ if (!stat(dev, &buf))
+ return 0; /* if the file already exists, we assume it's correct */
+
+ if (ptr_begins_static_str(name, "sd")) {
+ /* SCSI disks */
+ major = 8;
+ minor = (name[2] - 'a') << 4;
+ if (name[3] && name[4])
+ minor += 10 + (name[4] - '0');
+ else if (name[3])
+ minor += (name[3] - '0');
+ } else if (ptr_begins_static_str(name, "hd")) {
+ /* IDE disks/cd's */
+ if (name[2] == 'a')
+ major = 3, minor = 0;
+ else if (name[2] == 'b')
+ major = 3, minor = 64;
+ else if (name[2] == 'c')
+ major = 22, minor = 0;
+ else if (name[2] == 'd')
+ major = 22, minor = 64;
+ else if (name[2] == 'e')
+ major = 33, minor = 0;
+ else if (name[2] == 'f')
+ major = 33, minor = 64;
+ else if (name[2] == 'g')
+ major = 34, minor = 0;
+ else if (name[2] == 'h')
+ major = 34, minor = 64;
+ else if (name[2] == 'i')
+ major = 56, minor = 0;
+ else if (name[2] == 'j')
+ major = 56, minor = 64;
+ else if (name[2] == 'k')
+ major = 57, minor = 0;
+ else if (name[2] == 'l')
+ major = 57, minor = 64;
+ else if (name[2] == 'm')
+ major = 88, minor = 0;
+ else if (name[2] == 'n')
+ major = 88, minor = 64;
+ else if (name[2] == 'o')
+ major = 89, minor = 0;
+ else if (name[2] == 'p')
+ major = 89, minor = 64;
+ else if (name[2] == 'q')
+ major = 90, minor = 0;
+ else if (name[2] == 'r')
+ major = 90, minor = 64;
+ else if (name[2] == 's')
+ major = 91, minor = 0;
+ else if (name[2] == 't')
+ major = 91, minor = 64;
+ else
+ return -1;
+
+ if (name[3] && name[4])
+ minor += 10 + (name[4] - '0');
+ else if (name[3])
+ minor += (name[3] - '0');
+ } else if (ptr_begins_static_str(name , "sr")) {
+ /* SCSI cd's */
+ major = 11;
+ minor = name[2] - '0';
+ } else if (ptr_begins_static_str(name, "ida/") ||
+ ptr_begins_static_str(name, "cciss/")) {
+ /* Compaq Smart Array "ida/c0d0{p1}" */
+ ptr = strchr(name, '/');
+ mkdir("/dev/ida", 0755);
+ mkdir("/dev/cciss", 0755);
+ major = ptr_begins_static_str(name, "ida/") ? 72 : 104 + charstar_to_int(ptr+2);
+ ptr = strchr(ptr, 'd');
+ minor = 16 * charstar_to_int(ptr+1);
+ ptr = strchr(ptr, 'p');
+ minor += charstar_to_int(ptr+1);
+ } else if (ptr_begins_static_str(name, "rd/")) {
+ /* DAC960 "rd/cXdXXpX" */
+ mkdir("/dev/rd", 0755);
+ major = 48 + charstar_to_int(name+4);
+ ptr = strchr(name+4, 'd');
+ minor = 8 * charstar_to_int(ptr+1);
+ ptr = strchr(ptr, 'p');
+ minor += charstar_to_int(ptr+1);
+ } else if (ptr_begins_static_str(name, "loop")) {
+ major = 7;
+ minor = name[4] - '0';
+ } else if (ptr_begins_static_str(name, "chloop")) {
+ major = 100;
+ minor = name[6] - '0';
+ } else {
+ log_message("I don't know how to create device %s, please post bugreport to me!", dev);
+ return -1;
+ }
+
+ if (mknod(dev, type | 0600, makedev(major, minor))) {
+ log_perror(dev);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+/* mounts, creating the device if needed+possible */
+int my_mount(char *dev, char *location, char *fs, int force_rw)
+{
+ unsigned long flags = MS_MGC_VAL | (force_rw ? 0 : MS_RDONLY);
+ char * opts = NULL;
+ struct stat buf;
+ int rc;
+
+ if (strcmp(fs, "nfs")) {
+ rc = ensure_dev_exists(dev);
+ if (rc != 0) {
+ log_message("could not create required device file");
+ return -1;
+ }
+ }
+
+ log_message("mounting %s on %s as type %s", dev, location, fs);
+
+ if (stat(location, &buf)) {
+ if (mkdir(location, 0755)) {
+ log_perror("could not create location dir");
+ return -1;
+ }
+ } else if (!S_ISDIR(buf.st_mode)) {
+ log_message("not a dir %s, will unlink and mkdir", location);
+ if (unlink(location)) {
+ log_perror("could not unlink");
+ return -1;
+ }
+ if (mkdir(location, 0755)) {
+ log_perror("could not create location dir");
+ return -1;
+ }
+ }
+
+ if (!strcmp(fs, "supermount")) {
+ my_insmod("supermount", ANY_DRIVER_TYPE, NULL, 1);
+ my_insmod("isofs", ANY_DRIVER_TYPE, NULL, 1);
+ opts = alloca(500);
+ sprintf(opts, "dev=%s,fs=iso9660,tray_lock=always", dev);
+ dev = "none";
+ }
+
+#ifndef DISABLE_MEDIAS
+ if (!strcmp(fs, "vfat")) {
+ my_insmod("nls_cp437", ANY_DRIVER_TYPE, NULL, 1);
+ my_insmod("nls_iso8859_1", ANY_DRIVER_TYPE, NULL, 1);
+ my_insmod("vfat", ANY_DRIVER_TYPE, NULL, 1);
+ opts = "check=relaxed";
+ }
+
+ if (!strcmp(fs, "ntfs")) {
+ my_insmod("ntfs", ANY_DRIVER_TYPE, NULL, 1);
+ }
+
+ if (!strcmp(fs, "reiserfs"))
+ my_insmod("reiserfs", ANY_DRIVER_TYPE, NULL, 1);
+
+ if (!strcmp(fs, "jfs"))
+ my_insmod("jfs", ANY_DRIVER_TYPE, NULL, 1);
+
+ if (!strcmp(fs, "xfs"))
+ my_insmod("xfs", ANY_DRIVER_TYPE, NULL, 1);
+
+ if (!strcmp(fs, "ext4"))
+ my_insmod("ext4", ANY_DRIVER_TYPE, NULL, 1);
+
+#endif
+ if (!strcmp(fs, "iso9660"))
+ my_insmod("isofs", ANY_DRIVER_TYPE, NULL, 1);
+
+#ifndef DISABLE_NETWORK
+ if (!strcmp(fs, "nfs")) {
+ my_insmod("nfs", ANY_DRIVER_TYPE, NULL, 1);
+ log_message("preparing nfsmount for %s", dev);
+ rc = nfsmount_prepare(dev, &opts);
+ if (rc != 0)
+ return rc;
+ }
+#endif
+
+ rc = mount(dev, location, fs, flags, opts);
+ if (rc != 0) {
+ log_perror("mount failed");
+ rmdir(location);
+ }
+
+ return rc;
+}
diff --git a/mdk-stage1/mount.h b/mdk-stage1/mount.h
new file mode 100644
index 000000000..4a4317182
--- /dev/null
+++ b/mdk-stage1/mount.h
@@ -0,0 +1,32 @@
+/*
+ * Guillaume Cottenceau (gc@mandrakesoft.com)
+ *
+ * Copyright 2000 Mandrakesoft
+ *
+ * This software may be freely redistributed under the terms of the GNU
+ * public license.
+ *
+ * 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.
+ *
+ */
+
+/*
+ * Portions from Erik Troan (ewt@redhat.com)
+ *
+ * Copyright 1996 Red Hat Software
+ *
+ */
+
+#ifndef _MOUNT_H_
+#define _MOUNT_H_
+
+#ifndef DISABLE_NETWORK
+#include "nfsmount.h"
+#endif
+
+int my_mount(char *dev, char *location, char *fs, int force_rw);
+int ensure_dev_exists(const char * dev);
+
+#endif
diff --git a/mdk-stage1/mount_rpcgen.h b/mdk-stage1/mount_rpcgen.h
new file mode 100644
index 000000000..d70ccaf9d
--- /dev/null
+++ b/mdk-stage1/mount_rpcgen.h
@@ -0,0 +1,208 @@
+/*
+ * Please do not edit this file.
+ * It was generated using rpcgen.
+ */
+
+#ifndef _MOUNT_H_RPCGEN
+#define _MOUNT_H_RPCGEN
+
+#include <rpc/rpc.h>
+
+#define MNTPATHLEN 1024
+#define MNTNAMLEN 255
+#define FHSIZE 32
+
+typedef char fhandle[FHSIZE];
+#ifdef __cplusplus
+extern "C" bool_t xdr_fhandle(XDR *, fhandle);
+#elif __STDC__
+extern bool_t xdr_fhandle(XDR *, fhandle);
+#else /* Old Style C */
+bool_t xdr_fhandle();
+#endif /* Old Style C */
+
+
+struct fhstatus {
+ u_int fhs_status;
+ union {
+ fhandle fhs_fhandle;
+ } fhstatus_u;
+};
+typedef struct fhstatus fhstatus;
+#ifdef __cplusplus
+extern "C" bool_t xdr_fhstatus(XDR *, fhstatus*);
+#elif __STDC__
+extern bool_t xdr_fhstatus(XDR *, fhstatus*);
+#else /* Old Style C */
+bool_t xdr_fhstatus();
+#endif /* Old Style C */
+
+
+typedef char *dirpath;
+#ifdef __cplusplus
+extern "C" bool_t xdr_dirpath(XDR *, dirpath*);
+#elif __STDC__
+extern bool_t xdr_dirpath(XDR *, dirpath*);
+#else /* Old Style C */
+bool_t xdr_dirpath();
+#endif /* Old Style C */
+
+
+typedef char *name;
+#ifdef __cplusplus
+extern "C" bool_t xdr_name(XDR *, name*);
+#elif __STDC__
+extern bool_t xdr_name(XDR *, name*);
+#else /* Old Style C */
+bool_t xdr_name();
+#endif /* Old Style C */
+
+
+typedef struct mountbody *mountlist;
+#ifdef __cplusplus
+extern "C" bool_t xdr_mountlist(XDR *, mountlist*);
+#elif __STDC__
+extern bool_t xdr_mountlist(XDR *, mountlist*);
+#else /* Old Style C */
+bool_t xdr_mountlist();
+#endif /* Old Style C */
+
+
+struct mountbody {
+ name ml_hostname;
+ dirpath ml_directory;
+ mountlist ml_next;
+};
+typedef struct mountbody mountbody;
+#ifdef __cplusplus
+extern "C" bool_t xdr_mountbody(XDR *, mountbody*);
+#elif __STDC__
+extern bool_t xdr_mountbody(XDR *, mountbody*);
+#else /* Old Style C */
+bool_t xdr_mountbody();
+#endif /* Old Style C */
+
+
+typedef struct groupnode *groups;
+#ifdef __cplusplus
+extern "C" bool_t xdr_groups(XDR *, groups*);
+#elif __STDC__
+extern bool_t xdr_groups(XDR *, groups*);
+#else /* Old Style C */
+bool_t xdr_groups();
+#endif /* Old Style C */
+
+
+struct groupnode {
+ name gr_name;
+ groups gr_next;
+};
+typedef struct groupnode groupnode;
+#ifdef __cplusplus
+extern "C" bool_t xdr_groupnode(XDR *, groupnode*);
+#elif __STDC__
+extern bool_t xdr_groupnode(XDR *, groupnode*);
+#else /* Old Style C */
+bool_t xdr_groupnode();
+#endif /* Old Style C */
+
+
+typedef struct exportnode *exports;
+#ifdef __cplusplus
+extern "C" bool_t xdr_exports(XDR *, exports*);
+#elif __STDC__
+extern bool_t xdr_exports(XDR *, exports*);
+#else /* Old Style C */
+bool_t xdr_exports();
+#endif /* Old Style C */
+
+
+struct exportnode {
+ dirpath ex_dir;
+ groups ex_groups;
+ exports ex_next;
+};
+typedef struct exportnode exportnode;
+#ifdef __cplusplus
+extern "C" bool_t xdr_exportnode(XDR *, exportnode*);
+#elif __STDC__
+extern bool_t xdr_exportnode(XDR *, exportnode*);
+#else /* Old Style C */
+bool_t xdr_exportnode();
+#endif /* Old Style C */
+
+
+#define MOUNTPROG ((u_long)100005)
+#define MOUNTVERS ((u_long)1)
+
+#ifdef __cplusplus
+#define MOUNTPROC_NULL ((u_long)0)
+extern "C" void * mountproc_null_1(void *, CLIENT *);
+extern "C" void * mountproc_null_1_svc(void *, struct svc_req *);
+#define MOUNTPROC_MNT ((u_long)1)
+extern "C" fhstatus * mountproc_mnt_1(dirpath *, CLIENT *);
+extern "C" fhstatus * mountproc_mnt_1_svc(dirpath *, struct svc_req *);
+#define MOUNTPROC_DUMP ((u_long)2)
+extern "C" mountlist * mountproc_dump_1(void *, CLIENT *);
+extern "C" mountlist * mountproc_dump_1_svc(void *, struct svc_req *);
+#define MOUNTPROC_UMNT ((u_long)3)
+extern "C" void * mountproc_umnt_1(dirpath *, CLIENT *);
+extern "C" void * mountproc_umnt_1_svc(dirpath *, struct svc_req *);
+#define MOUNTPROC_UMNTALL ((u_long)4)
+extern "C" void * mountproc_umntall_1(void *, CLIENT *);
+extern "C" void * mountproc_umntall_1_svc(void *, struct svc_req *);
+#define MOUNTPROC_EXPORT ((u_long)5)
+extern "C" exports * mountproc_export_1(void *, CLIENT *);
+extern "C" exports * mountproc_export_1_svc(void *, struct svc_req *);
+#define MOUNTPROC_EXPORTALL ((u_long)6)
+extern "C" exports * mountproc_exportall_1(void *, CLIENT *);
+extern "C" exports * mountproc_exportall_1_svc(void *, struct svc_req *);
+
+#elif __STDC__
+#define MOUNTPROC_NULL ((u_long)0)
+extern void * mountproc_null_1(void *, CLIENT *);
+extern void * mountproc_null_1_svc(void *, struct svc_req *);
+#define MOUNTPROC_MNT ((u_long)1)
+extern fhstatus * mountproc_mnt_1(dirpath *, CLIENT *);
+extern fhstatus * mountproc_mnt_1_svc(dirpath *, struct svc_req *);
+#define MOUNTPROC_DUMP ((u_long)2)
+extern mountlist * mountproc_dump_1(void *, CLIENT *);
+extern mountlist * mountproc_dump_1_svc(void *, struct svc_req *);
+#define MOUNTPROC_UMNT ((u_long)3)
+extern void * mountproc_umnt_1(dirpath *, CLIENT *);
+extern void * mountproc_umnt_1_svc(dirpath *, struct svc_req *);
+#define MOUNTPROC_UMNTALL ((u_long)4)
+extern void * mountproc_umntall_1(void *, CLIENT *);
+extern void * mountproc_umntall_1_svc(void *, struct svc_req *);
+#define MOUNTPROC_EXPORT ((u_long)5)
+extern exports * mountproc_export_1(void *, CLIENT *);
+extern exports * mountproc_export_1_svc(void *, struct svc_req *);
+#define MOUNTPROC_EXPORTALL ((u_long)6)
+extern exports * mountproc_exportall_1(void *, CLIENT *);
+extern exports * mountproc_exportall_1_svc(void *, struct svc_req *);
+
+#else /* Old Style C */
+#define MOUNTPROC_NULL ((u_long)0)
+extern void * mountproc_null_1();
+extern void * mountproc_null_1_svc();
+#define MOUNTPROC_MNT ((u_long)1)
+extern fhstatus * mountproc_mnt_1();
+extern fhstatus * mountproc_mnt_1_svc();
+#define MOUNTPROC_DUMP ((u_long)2)
+extern mountlist * mountproc_dump_1();
+extern mountlist * mountproc_dump_1_svc();
+#define MOUNTPROC_UMNT ((u_long)3)
+extern void * mountproc_umnt_1();
+extern void * mountproc_umnt_1_svc();
+#define MOUNTPROC_UMNTALL ((u_long)4)
+extern void * mountproc_umntall_1();
+extern void * mountproc_umntall_1_svc();
+#define MOUNTPROC_EXPORT ((u_long)5)
+extern exports * mountproc_export_1();
+extern exports * mountproc_export_1_svc();
+#define MOUNTPROC_EXPORTALL ((u_long)6)
+extern exports * mountproc_exportall_1();
+extern exports * mountproc_exportall_1_svc();
+#endif /* Old Style C */
+
+#endif /* !_MOUNT_H_RPCGEN */
diff --git a/mdk-stage1/network.c b/mdk-stage1/network.c
new file mode 100644
index 000000000..163bafe5c
--- /dev/null
+++ b/mdk-stage1/network.c
@@ -0,0 +1,1209 @@
+/*
+ * Guillaume Cottenceau (gc@mandrakesoft.com)
+ *
+ * Copyright 2000 Mandrakesoft
+ *
+ * This software may be freely redistributed under the terms of the GNU
+ * public license.
+ *
+ * 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.
+ *
+ */
+
+/*
+ * Portions from Erik Troan (ewt@redhat.com)
+ *
+ * Copyright 1996 Red Hat Software
+ *
+ */
+
+#include "stage1.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <arpa/inet.h>
+#include <net/route.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <stdio.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <sys/utsname.h>
+
+#include "frontend.h"
+#include "modules.h"
+#include "probing.h"
+#include "log.h"
+#include "tools.h"
+#include "utils.h"
+#include "mount.h"
+#include "automatic.h"
+#include "dhcp.h"
+#include "adsl.h"
+#include "url.h"
+#include "dns.h"
+
+#include "network.h"
+#include "directory.h"
+#include "wireless.h"
+
+#ifndef DISABLE_KA
+#include "ka.h"
+#endif
+
+static void error_message_net(void) /* reduce code size */
+{
+ stg1_error_message("Could not configure network.");
+}
+
+
+int configure_net_device(struct interface_info * intf)
+{
+ struct ifreq req;
+ struct rtentry route;
+ int s;
+ struct sockaddr_in addr;
+ struct in_addr ia;
+ char ip[20], nm[20], nw[20], bc[20];
+
+ addr.sin_family = AF_INET;
+ addr.sin_port = 0;
+
+ memcpy(&ia, &intf->ip, sizeof(intf->ip));
+ strcpy(ip, inet_ntoa(ia));
+
+ memcpy(&ia, &intf->netmask, sizeof(intf->netmask));
+ strcpy(nm, inet_ntoa(ia));
+
+ memcpy(&ia, &intf->broadcast, sizeof(intf->broadcast));
+ strcpy(bc, inet_ntoa(ia));
+
+ memcpy(&ia, &intf->network, sizeof(intf->network));
+ strcpy(nw, inet_ntoa(ia));
+
+ log_message("configuring device %s ip: %s nm: %s nw: %s bc: %s", intf->device, ip, nm, nw, bc);
+
+ if (IS_TESTING)
+ return 0;
+
+ s = socket(AF_INET, SOCK_DGRAM, 0);
+ if (s < 0) {
+ log_perror("socket");
+ error_message_net();
+ return 1;
+ }
+
+ strcpy(req.ifr_name, intf->device);
+
+ if (intf->is_up == 1) {
+ log_message("interface already up, downing before reconfigure");
+
+ req.ifr_flags = 0;
+ if (ioctl(s, SIOCSIFFLAGS, &req)) {
+ close(s);
+ log_perror("SIOCSIFFLAGS (downing)");
+ error_message_net();
+ return 1;
+ }
+ }
+
+ /* sets IP address */
+ addr.sin_port = 0;
+ memcpy(&addr.sin_addr, &intf->ip, sizeof(intf->ip));
+ memcpy(&req.ifr_addr, &addr, sizeof(addr));
+ if (ioctl(s, SIOCSIFADDR, &req)) {
+ close(s);
+ log_perror("SIOCSIFADDR");
+ error_message_net();
+ return 1;
+ }
+
+ /* sets broadcast */
+ memcpy(&addr.sin_addr, &intf->broadcast, sizeof(intf->broadcast));
+ memcpy(&req.ifr_broadaddr, &addr, sizeof(addr));
+ if (ioctl(s, SIOCSIFBRDADDR, &req)) {
+ close(s);
+ log_perror("SIOCSIFBRDADDR");
+ error_message_net();
+ return 1;
+ }
+
+ /* sets netmask */
+ memcpy(&addr.sin_addr, &intf->netmask, sizeof(intf->netmask));
+ memcpy(&req.ifr_netmask, &addr, sizeof(addr));
+ if (ioctl(s, SIOCSIFNETMASK, &req)) {
+ close(s);
+ log_perror("SIOCSIFNETMASK");
+ error_message_net();
+ return 1;
+ }
+
+ if (intf->is_ptp)
+ req.ifr_flags = IFF_UP | IFF_RUNNING | IFF_POINTOPOINT | IFF_NOARP;
+ else
+ req.ifr_flags = IFF_UP | IFF_RUNNING | IFF_BROADCAST;
+
+ /* brings up networking! */
+ if (ioctl(s, SIOCSIFFLAGS, &req)) {
+ close(s);
+ log_perror("SIOCSIFFLAGS (upping)");
+ error_message_net();
+ return 1;
+ }
+
+ memset(&route, 0, sizeof(route));
+ route.rt_dev = intf->device;
+ route.rt_flags = RTF_UP;
+
+ memcpy(&addr.sin_addr, &intf->network, sizeof(intf->network));
+ memcpy(&route.rt_dst, &addr, sizeof(addr));
+
+ memcpy(&addr.sin_addr, &intf->netmask, sizeof(intf->netmask));
+ memcpy(&route.rt_genmask, &addr, sizeof(addr));
+
+ /* adds route */
+ if (ioctl(s, SIOCADDRT, &route)) {
+ close(s);
+ log_perror("SIOCADDRT");
+ error_message_net();
+ return 1;
+ }
+
+ close(s);
+
+ intf->is_up = 1;
+
+ if (intf->boot_proto != BOOTPROTO_DHCP && !streq(intf->device, "lo")) {
+ /* I need to sleep a bit in order for kernel to finish
+ init of the network device; if not, first sendto() for
+ gethostbyaddr will get an EINVAL. */
+ wait_message("Bringing up networking...");
+ sleep(2);
+ remove_wait_message();
+ }
+
+ return 0;
+}
+
+/* host network informations */
+char * hostname = NULL;
+char * domain = NULL;
+struct in_addr gateway = { 0 };
+struct in_addr dns_server = { 0 };
+struct in_addr dns_server2 = { 0 };
+
+static int add_default_route(void)
+{
+ int s;
+ struct rtentry route;
+ struct sockaddr_in addr;
+
+ if (IS_TESTING)
+ return 0;
+
+ if (gateway.s_addr == 0) {
+ log_message("no gateway provided, can't add default route");
+ return 0;
+ }
+
+ s = socket(AF_INET, SOCK_DGRAM, 0);
+ if (s < 0) {
+ close(s);
+ log_perror("socket");
+ error_message_net();
+ return 1;
+ }
+
+ memset(&route, 0, sizeof(route));
+
+ addr.sin_family = AF_INET;
+ addr.sin_port = 0;
+ addr.sin_addr = gateway;
+ memcpy(&route.rt_gateway, &addr, sizeof(addr));
+
+ addr.sin_addr.s_addr = INADDR_ANY;
+ memcpy(&route.rt_dst, &addr, sizeof(addr));
+ memcpy(&route.rt_genmask, &addr, sizeof(addr));
+
+ route.rt_flags = RTF_UP | RTF_GATEWAY;
+ route.rt_metric = 0;
+
+ if (ioctl(s, SIOCADDRT, &route)) {
+ close(s);
+ log_perror("SIOCADDRT");
+ error_message_net();
+ return 1;
+ }
+
+ close(s);
+
+ return 0;
+}
+
+
+static int write_resolvconf(void)
+{
+ char * filename = "/etc/resolv.conf";
+ FILE * f;
+
+ if (dns_server.s_addr == 0) {
+ log_message("resolvconf needs a dns server");
+ return -1;
+ }
+
+ f = fopen(filename, "w");
+ if (!f) {
+ log_perror(filename);
+ return -1;
+ }
+
+ if (domain)
+ fprintf(f, "search %s\n", domain); /* we can live without the domain search (user will have to enter fully-qualified names) */
+ fprintf(f, "nameserver %s\n", inet_ntoa(dns_server));
+ if (dns_server2.s_addr != 0)
+ fprintf(f, "nameserver %s\n", inet_ntoa(dns_server2));
+
+ fclose(f);
+ res_init(); /* reinit the resolver so DNS changes take affect */
+
+ return 0;
+}
+
+
+static int save_netinfo(struct interface_info * intf)
+{
+ char * file_network = "/tmp/network";
+ char file_intf[500];
+ FILE * f;
+
+ f = fopen(file_network, "w");
+ if (!f) {
+ log_perror(file_network);
+ return -1;
+ }
+
+ fprintf(f, "NETWORKING=yes\n");
+ fprintf(f, "FORWARD_IPV4=false\n");
+
+ if (hostname && !intf->boot_proto == BOOTPROTO_DHCP)
+ fprintf(f, "HOSTNAME=%s\n", hostname);
+ if (gateway.s_addr != 0)
+ fprintf(f, "GATEWAY=%s\n", inet_ntoa(gateway));
+
+ fclose(f);
+
+
+ strcpy(file_intf, "/tmp/ifcfg-");
+ strcat(file_intf, intf->device);
+
+ f = fopen(file_intf, "w");
+ if (!f) {
+ log_perror(file_intf);
+ return -1;
+ }
+
+ fprintf(f, "DEVICE=%s\n", intf->device);
+
+ if (intf->boot_proto == BOOTPROTO_DHCP) {
+ fprintf(f, "BOOTPROTO=dhcp\n");
+ if (dhcp_hostname && !streq(dhcp_hostname, ""))
+ fprintf(f, "DHCP_HOSTNAME=%s\n", dhcp_hostname);
+ } else if (intf->boot_proto == BOOTPROTO_STATIC) {
+ fprintf(f, "BOOTPROTO=static\n");
+ fprintf(f, "IPADDR=%s\n", inet_ntoa(intf->ip));
+ fprintf(f, "NETMASK=%s\n", inet_ntoa(intf->netmask));
+ fprintf(f, "NETWORK=%s\n", inet_ntoa(intf->network));
+ fprintf(f, "BROADCAST=%s\n", inet_ntoa(intf->broadcast));
+ if (domain)
+ fprintf(f, "DOMAIN=%s\n", domain);
+ if (dns_server.s_addr != 0)
+ fprintf(f, "DNS1=%s\n", inet_ntoa(dns_server));
+ if (dns_server2.s_addr != 0)
+ fprintf(f, "DNS2=%s\n", inet_ntoa(dns_server2));
+ } else if (intf->boot_proto == BOOTPROTO_ADSL_PPPOE) {
+ fprintf(f, "BOOTPROTO=adsl_pppoe\n");
+ fprintf(f, "USER=%s\n", intf->user);
+ fprintf(f, "PASS=%s\n", intf->pass);
+ fprintf(f, "ACNAME=%s\n", intf->acname);
+ }
+
+ fclose(f);
+
+ return 0;
+}
+
+
+char * guess_netmask(char * ip_addr)
+{
+ struct in_addr addr;
+ unsigned long int tmp;
+
+ if (streq(ip_addr, "") || !inet_aton(ip_addr, &addr))
+ return "";
+
+ log_message("guessing netmask");
+
+ tmp = ntohl(addr.s_addr);
+
+ if (((tmp & 0xFF000000) >> 24) <= 127)
+ return "255.0.0.0";
+ else if (((tmp & 0xFF000000) >> 24) <= 191)
+ return "255.255.0.0";
+ else
+ return "255.255.255.0";
+}
+
+
+char * guess_domain_from_hostname(char *hostname)
+{
+ char *domain = strchr(strdup(hostname), '.');
+ if (!domain || domain[1] == '\0') {
+ log_message("unable to guess domain from hostname: %s", hostname);
+ return NULL;
+ }
+ return domain + 1; /* skip '.' */
+}
+
+
+static void static_ip_callback(char ** strings)
+{
+ struct in_addr addr;
+
+ static int done = 0;
+ if (done)
+ return;
+ if (streq(strings[0], "") || !inet_aton(strings[0], &addr))
+ return;
+ done = 1;
+
+ if (!strcmp(strings[1], "")) {
+ char * ptr;
+ strings[1] = strdup(strings[0]);
+ ptr = strrchr(strings[1], '.');
+ if (ptr)
+ *(ptr+1) = '\0';
+ }
+
+ if (!strcmp(strings[2], ""))
+ strings[2] = strdup(strings[1]);
+
+ if (!strcmp(strings[3], ""))
+ strings[3] = strdup(guess_netmask(strings[0]));
+}
+
+
+static enum return_type setup_network_interface(struct interface_info * intf)
+{
+ enum return_type results;
+ char * bootprotos[] = { "DHCP", "Static", "ADSL", NULL };
+ char * bootprotos_auto[] = { "dhcp", "static", "adsl" };
+ char * choice;
+
+ results = ask_from_list_auto("Please select your network connection type.", bootprotos, &choice, "network", bootprotos_auto);
+ if (results != RETURN_OK)
+ return results;
+
+ if (!strcmp(choice, "Static")) {
+ char * questions[] = { "IP of this machine", "IP of DNS", "IP of default gateway", "Netmask", NULL };
+ char * questions_auto[] = { "ip", "dns", "gateway", "netmask" };
+ static char ** answers = NULL;
+ struct in_addr addr;
+
+ results = ask_from_entries_auto("Please enter the network information. (leave netmask blank for Internet standard)",
+ questions, &answers, 16, questions_auto, static_ip_callback);
+ if (results != RETURN_OK)
+ return setup_network_interface(intf);
+
+ if (streq(answers[0], "") || !inet_aton(answers[0], &addr)) {
+ stg1_error_message("Invalid IP address.");
+ return setup_network_interface(intf);
+ }
+ memcpy(&intf->ip, &addr, sizeof(addr));
+
+ if (!inet_aton(answers[1], &dns_server)) {
+ log_message("invalid DNS");
+ dns_server.s_addr = 0; /* keep an understandable state */
+ }
+
+ if (streq(answers[0], answers[1])) {
+ log_message("IP and DNS are the same, guess you don't want a DNS, disabling it");
+ dns_server.s_addr = 0; /* keep an understandable state */
+ }
+
+ if (!inet_aton(answers[2], &gateway)) {
+ log_message("invalid gateway");
+ gateway.s_addr = 0; /* keep an understandable state */
+ }
+
+ if ((streq(answers[3], "") && inet_aton(guess_netmask(answers[0]), &addr))
+ || inet_aton(answers[3], &addr))
+ memcpy(&intf->netmask, &addr, sizeof(addr));
+ else {
+ stg1_error_message("Invalid netmask.");
+ return setup_network_interface(intf);
+ }
+
+ *((uint32_t *) &intf->broadcast) = (*((uint32_t *) &intf->ip) &
+ *((uint32_t *) &intf->netmask)) | ~(*((uint32_t *) &intf->netmask));
+
+ inet_aton("255.255.255.255", &addr);
+ if (!memcmp(&addr, &intf->netmask, sizeof(addr))) {
+ log_message("netmask is 255.255.255.255 -> point to point device");
+ intf->network = gateway;
+ intf->is_ptp = 1;
+ } else {
+ *((uint32_t *) &intf->network) = *((uint32_t *) &intf->ip) & *((uint32_t *) &intf->netmask);
+ intf->is_ptp = 0;
+ }
+ intf->boot_proto = BOOTPROTO_STATIC;
+
+ if (configure_net_device(intf))
+ return RETURN_ERROR;
+
+ } else if (streq(choice, "DHCP")) {
+ results = perform_dhcp(intf);
+
+ if (results == RETURN_BACK)
+ return setup_network_interface(intf);
+ if (results == RETURN_ERROR)
+ return results;
+ intf->boot_proto = BOOTPROTO_DHCP;
+
+ if (configure_net_device(intf))
+ return RETURN_ERROR;
+
+ } else if (streq(choice, "ADSL")) {
+ results = perform_adsl(intf);
+
+ if (results == RETURN_BACK)
+ return setup_network_interface(intf);
+ if (results == RETURN_ERROR)
+ return results;
+ } else
+ return RETURN_ERROR;
+
+ return add_default_route();
+}
+
+
+static enum return_type configure_network(struct interface_info * intf)
+{
+ char * dnshostname;
+
+ if (hostname && domain)
+ return RETURN_OK;
+
+ dnshostname = mygethostbyaddr(inet_ntoa(intf->ip));
+
+ if (dnshostname) {
+ if (intf->boot_proto == BOOTPROTO_STATIC)
+ hostname = strdup(dnshostname);
+ domain = guess_domain_from_hostname(dnshostname);
+ if (domain) {
+ log_message("got hostname and domain from dns entry, %s and %s", dnshostname, domain);
+ return RETURN_OK;
+ }
+ } else
+ log_message("reverse name lookup on self failed");
+
+ if (domain)
+ return RETURN_OK;
+
+ dnshostname = NULL;
+ if (dns_server.s_addr != 0) {
+ wait_message("Trying to resolve dns...");
+ dnshostname = mygethostbyaddr(inet_ntoa(dns_server));
+ remove_wait_message();
+ if (dnshostname) {
+ log_message("got DNS fullname, %s", dnshostname);
+ domain = guess_domain_from_hostname(dnshostname);
+ } else
+ log_message("reverse name lookup on DNS failed");
+ } else
+ log_message("no DNS, unable to guess domain");
+
+ if (domain) {
+ log_message("got domain from DNS fullname, %s", domain);
+ } else {
+ enum return_type results;
+ char * questions[] = { "Host name", "Domain name", NULL };
+ char * questions_auto[] = { "hostname", "domain" };
+ static char ** answers = NULL;
+ char * boulet;
+
+ if (dhcp_hostname || dhcp_domain) {
+ answers = (char **) malloc(sizeof(questions));
+ answers[0] = strdup(dhcp_hostname);
+ answers[1] = strdup(dhcp_domain);
+ }
+
+ if (!dhcp_hostname || !dhcp_domain) {
+ results = ask_from_entries_auto("I could not guess hostname and domain name; please fill in this information. "
+ "Valid answers are for example: `mybox' for hostname and `mynetwork.com' for "
+ "domain name, for a machine called `mybox.mynetwork.com' on the Internet.",
+ questions, &answers, 32, questions_auto, NULL);
+ if (results != RETURN_OK)
+ return results;
+ }
+
+ hostname = answers[0];
+ if ((boulet = strchr(hostname, '.')) != NULL)
+ boulet[0] = '\0';
+ domain = answers[1];
+ }
+
+ log_message("using hostname %s", hostname);
+ log_message("using domain %s", domain);
+
+ return RETURN_OK;
+}
+
+
+static enum return_type bringup_networking(struct interface_info * intf)
+{
+ static struct interface_info loopback;
+ enum return_type results;
+
+ my_insmod("af_packet", ANY_DRIVER_TYPE, NULL, 1);
+
+ do {
+ results = configure_wireless(intf->device);
+ } while (results == RETURN_ERROR);
+
+ if (results == RETURN_BACK)
+ return RETURN_BACK;
+
+ do {
+ results = setup_network_interface(intf);
+ if (results != RETURN_OK)
+ return results;
+ write_resolvconf();
+ results = configure_network(intf);
+ } while (results == RETURN_ERROR);
+
+ if (results == RETURN_BACK)
+ return bringup_networking(intf);
+
+ write_resolvconf(); /* maybe we have now domain to write also */
+
+ if (loopback.is_up == 0) {
+ int rc;
+ strcpy(loopback.device, "lo");
+ loopback.is_ptp = 0;
+ loopback.is_up = 0;
+ loopback.ip.s_addr = htonl(0x7f000001);
+ loopback.netmask.s_addr = htonl(0xff000000);
+ loopback.broadcast.s_addr = htonl(0x7fffffff);
+ loopback.network.s_addr = htonl(0x7f000000);
+ rc = configure_net_device(&loopback);
+ if (rc)
+ return RETURN_ERROR;
+ }
+
+ return RETURN_OK;
+}
+
+
+static char * auto_select_up_intf(int detection_mode)
+{
+#define SIOCETHTOOL 0x8946
+#define ETHTOOL_GLINK 0x0000000a /* Get link status (ethtool_value) */
+
+ struct ethtool_value {
+ uint32_t cmd;
+ uint32_t data;
+ };
+
+ char ** interfaces, ** ptr;
+ interfaces = get_net_devices();
+
+ int s;
+ s = socket(AF_INET, SOCK_DGRAM, 0);
+ if (s < 0) {
+ return NULL;
+ }
+
+ ptr = interfaces;
+ while (ptr && *ptr) {
+ if (detection_mode != AUTO_DETECTION_WIRED || !wireless_is_aware(s, *interfaces)) {
+ struct ifreq ifr;
+ struct ethtool_value edata;
+ strncpy(ifr.ifr_name, *ptr, IFNAMSIZ);
+ edata.cmd = ETHTOOL_GLINK;
+ ifr.ifr_data = (caddr_t)&edata;
+ if (ioctl(s, SIOCETHTOOL, &ifr) == 0 && edata.data) {
+ close(s);
+ log_message("NETWORK: choosing interface %s (link beat detected)", *ptr);
+ return *ptr;
+ }
+ }
+ ptr++;
+ }
+
+ log_message("NETWORK: no interface has a link beat");
+
+ if (detection_mode == AUTO_DETECTION_WIRED) {
+ ptr = interfaces;
+ while (ptr && *ptr) {
+ if (!wireless_is_aware(s, *interfaces)) {
+ close(s);
+ log_message("NETWORK: choosing interface %s (wired interface)", *ptr);
+ return *ptr;
+ }
+ ptr++;
+ }
+ log_message("NETWORK: no interface is wired");
+ }
+
+ close(s);
+
+ return NULL;
+}
+
+
+static char * interface_select(void)
+{
+ char ** interfaces, ** ptr;
+ char * descriptions[50];
+ char * choice;
+ int i, count = 0;
+ enum return_type results;
+
+ interfaces = get_net_devices();
+
+ ptr = interfaces;
+ while (ptr && *ptr) {
+ count++;
+ ptr++;
+ }
+
+ if (count == 0) {
+ stg1_error_message("No NET device found.\n"
+ "Hint: if you're using a Laptop, note that PCMCIA Network adapters are now supported either with `pcmcia.img' or `network.img', please try both these bootdisks.");
+ i = ask_insmod(NETWORK_DEVICES);
+ if (i == RETURN_BACK)
+ return NULL;
+ return interface_select();
+ }
+
+ if (count == 1)
+ return *interfaces;
+
+ /* this can't be done in ask_from_list_comments_auto because "auto" and "wired" are not in the interfaces list */
+ if (IS_AUTOMATIC) {
+ enum auto_detection_type auto_detect = AUTO_DETECTION_NONE;
+ if (streq(get_auto_value("interface"), "auto"))
+ auto_detect = AUTO_DETECTION_ALL;
+ else if (streq(get_auto_value("interface"), "wired"))
+ auto_detect = AUTO_DETECTION_WIRED;
+ if (auto_detect != AUTO_DETECTION_NONE) {
+ choice = auto_select_up_intf(auto_detect);
+ if (choice)
+ return choice;
+ }
+ }
+
+ i = 0;
+ while (interfaces[i]) {
+ descriptions[i] = get_net_intf_description(interfaces[i]);
+ i++;
+ }
+
+ results = ask_from_list_comments_auto("Please choose the NET device to use for the installation.",
+ interfaces, descriptions, &choice, "interface", interfaces);
+
+ if (results != RETURN_OK)
+ return NULL;
+
+ return choice;
+}
+
+static enum return_type get_http_proxy(char **http_proxy_host, char **http_proxy_port)
+{
+ char *questions[] = { "HTTP proxy host", "HTTP proxy port", NULL };
+ char *questions_auto[] = { "proxy_host", "proxy_port", NULL };
+ static char ** answers = NULL;
+ enum return_type results;
+
+ results = ask_from_entries_auto("Please enter HTTP proxy host and port if you need it, else leave them blank or cancel.",
+ questions, &answers, 40, questions_auto, NULL);
+ if (results == RETURN_OK) {
+ *http_proxy_host = answers[0];
+ *http_proxy_port = answers[1];
+ } else {
+ *http_proxy_host = NULL;
+ *http_proxy_port = NULL;
+ }
+
+ return results;
+}
+
+
+static int url_split(const char *url, const char *protocol, char **host, char **path)
+{
+ char *protocol_sep, *host_sep;
+
+ protocol_sep = strstr(url, "://");
+ if (!protocol_sep) {
+ log_message("NETWORK: no protocol in \"%s\"", url);
+ return -1;
+ }
+
+ if (strncmp(protocol, url, protocol_sep - url))
+ return -1;
+
+ url = protocol_sep + 3;
+ host_sep = strchr(url, '/');
+ if (!host_sep || host_sep == url) {
+ log_message("NETWORK: no hostname in \"%s\"", url);
+ return -1;
+ }
+
+ *host = strndup(url, host_sep - url);
+ *path = strdup(host_sep);
+
+ return 0;
+}
+
+#define MIRRORLIST_MAX_ITEMS 500
+typedef char *mirrorlist_t[2][MIRRORLIST_MAX_ITEMS+1];
+
+static enum return_type get_mirrorlist(mirrorlist_t mirrorlist, int start, char *version, const char *protocol, char *http_proxy_host, char *http_proxy_port) {
+ int fd, size, line_pos = 0;
+ char path[1024];
+ char line[1024];
+ char type[100] = DISTRIB_TYPE;
+ int mirror_idx = start;
+
+ int use_http_proxy = http_proxy_host && http_proxy_port && !streq(http_proxy_host, "") && !streq(http_proxy_port, "");
+ lowercase(type);
+ snprintf(path, sizeof(path), "%s/%s.%s.%s.list", MIRRORLIST_PATH, type, version, ARCH);
+
+ fd = http_download_file(MIRRORLIST_HOST, path, &size, use_http_proxy ? "http" : NULL, http_proxy_host, http_proxy_port);
+ if (fd < 0) {
+ log_message("HTTP: unable to get mirrors list from %s (%s)", MIRRORLIST_HOST, path);
+ return RETURN_ERROR;
+ }
+
+ while (read(fd, line + line_pos, 1) > 0) {
+ if (line[line_pos] == '\n') {
+ char *url;
+ line[line_pos] = '\0';
+ line_pos = 0;
+
+ /* skip medium if it does not look like a distrib path */
+ if (!strstr(line, ",type=distrib,"))
+ continue;
+
+ url = strstr(line, ",url=");
+ if (!url)
+ continue;
+ url += 5;
+
+ if (url_split(url, protocol, &mirrorlist[0][mirror_idx], &mirrorlist[1][mirror_idx]) < 0)
+ continue;
+
+ mirror_idx++;
+ } else {
+ line_pos++;
+ }
+
+ if (mirror_idx >= MIRRORLIST_MAX_ITEMS)
+ break;
+ }
+ close(fd);
+
+ mirrorlist[0][mirror_idx] = NULL;
+ mirrorlist[1][mirror_idx] = NULL;
+
+ return RETURN_OK;
+}
+
+static int choose_mirror_from_host_list(mirrorlist_t mirrorlist, char **selected_host, char **filepath)
+{
+ enum return_type results;
+ int mirror_idx = 0;
+
+ do {
+ results = ask_from_list_index("Please select a mirror from the list below.",
+ mirrorlist[0], NULL, &mirror_idx);
+
+ if (results == RETURN_BACK) {
+ return RETURN_ERROR;
+ } else if (results == RETURN_OK) {
+ if (mirror_idx == 0) {
+ /* enter the mirror manually */
+ return RETURN_OK;
+ }
+ *selected_host = strdup(mirrorlist[0][mirror_idx]);
+ *filepath = strdup(mirrorlist[1][mirror_idx]);
+ return RETURN_OK;
+ }
+ } while (results == RETURN_ERROR);
+
+ return RETURN_ERROR;
+}
+
+
+static int choose_mirror_from_list(char *http_proxy_host, char *http_proxy_port, const char *protocol, char **selected_host, char **filepath)
+{
+ enum return_type results;
+ char *versions[] = { "Specify the mirror manually", DISTRIB_VERSION, NULL };
+ char *version = DISTRIB_VERSION;
+
+ do {
+ results = ask_from_list("Please select a medium from the list below.", versions, &version);
+
+ if (results == RETURN_BACK) {
+ return RETURN_BACK;
+ } else if (results == RETURN_OK) {
+ if (!strcmp(version, versions[0])) {
+ /* enter the mirror manually */
+ return RETURN_OK;
+ } else {
+ /* a medium has been selected */
+ mirrorlist_t mirrorlist;
+ mirrorlist[0][0] = "Specify the mirror manually";
+ mirrorlist[1][0] = NULL;
+
+ results = get_mirrorlist(mirrorlist, 1, version, protocol, http_proxy_host, http_proxy_port);
+ if (results == RETURN_ERROR)
+ return RETURN_ERROR;
+
+ results = choose_mirror_from_host_list(mirrorlist, selected_host, filepath);
+ }
+ }
+ } while (results == RETURN_ERROR);
+
+ return results;
+}
+
+
+/* -=-=-- */
+
+
+enum return_type intf_select_and_up()
+{
+ static struct interface_info intf[20];
+ static int num_interfaces = 0;
+ struct interface_info * sel_intf = NULL;
+ int i;
+ enum return_type results;
+ char * iface = interface_select();
+
+ if (iface == NULL)
+ return RETURN_BACK;
+
+ for (i = 0; i < num_interfaces ; i++)
+ if (!strcmp(intf[i].device, iface))
+ sel_intf = &(intf[i]);
+
+ if (sel_intf == NULL) {
+ sel_intf = &(intf[num_interfaces]);
+ strcpy(sel_intf->device, iface);
+ sel_intf->is_up = 0;
+ num_interfaces++;
+ }
+
+ results = bringup_networking(sel_intf);
+
+ if (results == RETURN_OK)
+ save_netinfo(sel_intf);
+
+ return results;
+}
+
+
+
+enum return_type nfs_prepare(void)
+{
+ char * questions[] = { "NFS server name", DISTRIB_NAME " directory", NULL };
+ char * questions_auto[] = { "server", "directory", NULL };
+ static char ** answers = NULL;
+ char * nfsmount_location;
+ enum return_type results = intf_select_and_up(NULL, NULL);
+
+ if (results != RETURN_OK)
+ return results;
+
+ do {
+ results = ask_from_entries_auto("Please enter the name or IP address of your NFS server, "
+ "and the directory containing the " DISTRIB_NAME " Distribution.",
+ questions, &answers, 40, questions_auto, NULL);
+ if (results != RETURN_OK || streq(answers[0], "")) {
+ unset_automatic(); /* we are in a fallback mode */
+ return nfs_prepare();
+ }
+
+ nfsmount_location = malloc(strlen(answers[0]) + strlen(answers[1]) + 2);
+ strcpy(nfsmount_location, answers[0]);
+ strcat(nfsmount_location, ":");
+ strcat(nfsmount_location, answers[1]);
+
+ if (my_mount(nfsmount_location, MEDIA_LOCATION, "nfs", 0) == -1) {
+ stg1_error_message("I can't mount the directory from the NFS server.");
+ results = RETURN_BACK;
+ continue;
+ }
+ free(nfsmount_location); nfsmount_location = NULL;
+
+ results = try_with_directory(MEDIA_LOCATION, "nfs", "nfs-iso");
+ if (results != RETURN_OK)
+ umount(MEDIA_LOCATION);
+ if (results == RETURN_ERROR)
+ return RETURN_ERROR;
+ }
+ while (results == RETURN_BACK);
+
+ return RETURN_OK;
+}
+
+
+enum return_type ftp_prepare(void)
+{
+ char * questions[] = { "FTP server", DISTRIB_NAME " directory", "Login", "Password", NULL };
+ char * questions_auto[] = { "server", "directory", "user", "pass", NULL };
+ static char ** answers = NULL;
+ enum return_type results;
+ struct utsname kernel_uname;
+ char *http_proxy_host, *http_proxy_port;
+ int use_http_proxy;
+
+ if (!ramdisk_possible()) {
+ stg1_error_message("FTP install needs more than %d Mbytes of memory (detected %d Mbytes). You may want to try an NFS install.",
+ MEM_LIMIT_DRAKX, total_memory());
+ return RETURN_ERROR;
+ }
+
+ results = intf_select_and_up();
+
+ if (results != RETURN_OK)
+ return results;
+
+ get_http_proxy(&http_proxy_host, &http_proxy_port);
+ use_http_proxy = http_proxy_host && http_proxy_port && !streq(http_proxy_host, "") && !streq(http_proxy_port, "");
+
+ uname(&kernel_uname);
+
+ do {
+ char location_full[500];
+ int ftp_serv_response = -1;
+ int fd, size;
+ char ftp_hostname[500];
+
+ if (!IS_AUTOMATIC) {
+ if (answers == NULL)
+ answers = (char **) malloc(sizeof(questions));
+
+ results = choose_mirror_from_list(http_proxy_host, http_proxy_port, "ftp", &answers[0], &answers[1]);
+
+ if (results == RETURN_BACK)
+ return ftp_prepare();
+
+ if (use_http_proxy) {
+ results = ask_yes_no("Do you want to use this HTTP proxy for FTP connections too ?");
+
+ if (results == RETURN_BACK)
+ return ftp_prepare();
+
+ use_http_proxy = results == RETURN_OK;
+ }
+ }
+
+ results = ask_from_entries_auto("Please enter the name or IP address of the FTP server, "
+ "the directory containing the " DISTRIB_NAME " Distribution, "
+ "and the login/pass if necessary (leave login blank for anonymous). ",
+ questions, &answers, 40, questions_auto, NULL);
+ if (results != RETURN_OK || streq(answers[0], "")) {
+ unset_automatic(); /* we are in a fallback mode */
+ return ftp_prepare();
+ }
+
+ strcpy(location_full, answers[1][0] == '/' ? "" : "/");
+ strcat(location_full, answers[1]);
+
+ if (use_http_proxy) {
+ log_message("FTP: don't connect to %s directly, will use proxy", answers[0]);
+ } else {
+ log_message("FTP: trying to connect to %s", answers[0]);
+ ftp_serv_response = ftp_open_connection(answers[0], answers[2], answers[3], "");
+ if (ftp_serv_response < 0) {
+ log_message("FTP: error connect %d", ftp_serv_response);
+ if (ftp_serv_response == FTPERR_BAD_HOSTNAME)
+ stg1_error_message("Error: bad hostname.");
+ else if (ftp_serv_response == FTPERR_FAILED_CONNECT)
+ stg1_error_message("Error: failed to connect to remote host.");
+ else
+ stg1_error_message("Error: couldn't connect.");
+ results = RETURN_BACK;
+ continue;
+ }
+ }
+
+ strcat(location_full, COMPRESSED_FILE_REL("/"));
+
+ log_message("FTP: trying to retrieve %s", location_full);
+
+ if (use_http_proxy) {
+ if (strcmp(answers[2], "")) {
+ strcpy(ftp_hostname, answers[2]); /* user name */
+ strcat(ftp_hostname, ":");
+ strcat(ftp_hostname, answers[3]); /* password */
+ strcat(ftp_hostname, "@");
+ } else {
+ strcpy(ftp_hostname, "");
+ }
+ strcat(ftp_hostname, answers[0]);
+ fd = http_download_file(ftp_hostname, location_full, &size, "ftp", http_proxy_host, http_proxy_port);
+ } else {
+ fd = ftp_start_download(ftp_serv_response, location_full, &size);
+ }
+
+ if (fd < 0) {
+ char *msg = str_ftp_error(fd);
+ log_message("FTP: error get %d for remote file %s", fd, location_full);
+ stg1_error_message("Error: %s.", msg ? msg : "couldn't retrieve Installation program");
+ results = RETURN_BACK;
+ continue;
+ }
+
+ log_message("FTP: size of download %d bytes", size);
+
+ results = load_compressed_fd(fd, size);
+ if (results == RETURN_OK) {
+ if (!use_http_proxy)
+ ftp_end_data_command(ftp_serv_response);
+ } else {
+ unset_automatic(); /* we are in a fallback mode */
+ return results;
+ }
+
+ if (use_http_proxy) {
+ add_to_env("METHOD", "http");
+ sprintf(location_full, "ftp://%s%s", ftp_hostname, answers[1]);
+ add_to_env("URLPREFIX", location_full);
+ add_to_env("PROXY", http_proxy_host);
+ add_to_env("PROXYPORT", http_proxy_port);
+ } else {
+ add_to_env("METHOD", "ftp");
+ add_to_env("HOST", answers[0]);
+ add_to_env("PREFIX", answers[1]);
+ if (!streq(answers[2], "")) {
+ add_to_env("LOGIN", answers[2]);
+ add_to_env("PASSWORD", answers[3]);
+ }
+ }
+ }
+ while (results == RETURN_BACK);
+
+ return RETURN_OK;
+}
+
+enum return_type http_prepare(void)
+{
+ char * questions[] = { "HTTP server", DISTRIB_NAME " directory", NULL };
+ char * questions_auto[] = { "server", "directory", NULL };
+ static char ** answers = NULL;
+ enum return_type results;
+ char *http_proxy_host, *http_proxy_port;
+
+ if (!ramdisk_possible()) {
+ stg1_error_message("HTTP install needs more than %d Mbytes of memory (detected %d Mbytes). You may want to try an NFS install.",
+ MEM_LIMIT_DRAKX, total_memory());
+ return RETURN_ERROR;
+ }
+
+ results = intf_select_and_up();
+
+ if (results != RETURN_OK)
+ return results;
+
+ get_http_proxy(&http_proxy_host, &http_proxy_port);
+
+ do {
+ char location_full[500];
+ int fd, size;
+ int use_http_proxy;
+
+ if (!IS_AUTOMATIC) {
+ if (answers == NULL)
+ answers = (char **) malloc(sizeof(questions));
+
+ results = choose_mirror_from_list(http_proxy_host, http_proxy_port, "http", &answers[0], &answers[1]);
+
+ if (results == RETURN_BACK)
+ return ftp_prepare();
+ }
+
+ results = ask_from_entries_auto("Please enter the name or IP address of the HTTP server, "
+ "and the directory containing the " DISTRIB_NAME " Distribution.",
+ questions, &answers, 40, questions_auto, NULL);
+ if (results != RETURN_OK || streq(answers[0], "")) {
+ unset_automatic(); /* we are in a fallback mode */
+ return http_prepare();
+ }
+
+ strcpy(location_full, answers[1][0] == '/' ? "" : "/");
+ strcat(location_full, answers[1]);
+ strcat(location_full, COMPRESSED_FILE_REL("/"));
+
+ log_message("HTTP: trying to retrieve %s from %s", location_full, answers[0]);
+
+ use_http_proxy = http_proxy_host && http_proxy_port && !streq(http_proxy_host, "") && !streq(http_proxy_port, "");
+
+ fd = http_download_file(answers[0], location_full, &size, use_http_proxy ? "http" : NULL, http_proxy_host, http_proxy_port);
+ if (fd < 0) {
+ log_message("HTTP: error %d", fd);
+ if (fd == FTPERR_FAILED_CONNECT)
+ stg1_error_message("Error: couldn't connect to server.");
+ else
+ stg1_error_message("Error: couldn't get file (%s).", location_full);
+ results = RETURN_BACK;
+ continue;
+ }
+
+ log_message("HTTP: size of download %d bytes", size);
+
+ if (load_compressed_fd(fd, size) != RETURN_OK) {
+ unset_automatic(); /* we are in a fallback mode */
+ return RETURN_ERROR;
+ }
+
+ add_to_env("METHOD", "http");
+ sprintf(location_full, "http://%s%s%s", answers[0], answers[1][0] == '/' ? "" : "/", answers[1]);
+ add_to_env("URLPREFIX", location_full);
+ if (!streq(http_proxy_host, ""))
+ add_to_env("PROXY", http_proxy_host);
+ if (!streq(http_proxy_port, ""))
+ add_to_env("PROXYPORT", http_proxy_port);
+ }
+ while (results == RETURN_BACK);
+
+ return RETURN_OK;
+
+}
+
+#ifndef DISABLE_KA
+enum return_type ka_prepare(void)
+{
+ enum return_type results;
+
+ if (!ramdisk_possible()) {
+ stg1_error_message("KA install needs more than %d Mbytes of memory (detected %d Mbytes).",
+ MEM_LIMIT_DRAKX, total_memory());
+ return RETURN_ERROR;
+ }
+
+ results = intf_select_and_up();
+
+ if (results != RETURN_OK)
+ return results;
+
+ return perform_ka();
+}
+#endif
diff --git a/mdk-stage1/network.h b/mdk-stage1/network.h
new file mode 100644
index 000000000..3d2d94871
--- /dev/null
+++ b/mdk-stage1/network.h
@@ -0,0 +1,66 @@
+/*
+ * Guillaume Cottenceau (gc@mandrakesoft.com)
+ *
+ * Copyright 2000 Mandrakesoft
+ *
+ * This software may be freely redistributed under the terms of the GNU
+ * public license.
+ *
+ * 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.
+ *
+ */
+
+/*
+ * Portions from Erik Troan (ewt@redhat.com)
+ *
+ * Copyright 1996 Red Hat Software
+ *
+ */
+
+#ifndef _NETWORK_H_
+#define _NETWORK_H_
+
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <arpa/inet.h>
+
+enum return_type intf_select_and_up();
+
+enum return_type nfs_prepare(void);
+enum return_type ftp_prepare(void);
+enum return_type http_prepare(void);
+#ifndef DISABLE_KA
+enum return_type ka_prepare(void);
+#endif
+
+
+enum boot_proto_type { BOOTPROTO_STATIC, BOOTPROTO_DHCP, BOOTPROTO_ADSL_PPPOE };
+enum auto_detection_type { AUTO_DETECTION_NONE, AUTO_DETECTION_ALL, AUTO_DETECTION_WIRED };
+
+/* all of these in_addr things are in network byte order! */
+struct interface_info {
+ char device[10];
+ int is_ptp, is_up;
+ struct in_addr ip, netmask, broadcast, network;
+ enum boot_proto_type boot_proto;
+ char *user, *pass, *acname; /* for ADSL connection */
+};
+
+
+/* these are to be used only by dhcp.c */
+
+char * guess_netmask(char * ip_addr);
+
+int configure_net_device(struct interface_info * intf);
+
+extern char * hostname;
+extern char * domain;
+extern struct in_addr gateway;
+extern struct in_addr dns_server;
+extern struct in_addr dns_server2;
+
+
+
+#endif
diff --git a/mdk-stage1/newt-frontend.c b/mdk-stage1/newt-frontend.c
new file mode 100644
index 000000000..4520c9a7e
--- /dev/null
+++ b/mdk-stage1/newt-frontend.c
@@ -0,0 +1,388 @@
+/*
+ * Guillaume Cottenceau (gc@mandrakesoft.com)
+ *
+ * Copyright 2000 Mandrakesoft
+ *
+ * This software may be freely redistributed under the terms of the GNU
+ * public license.
+ *
+ * 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.
+ *
+ */
+
+/*
+ * Portions from Erik Troan (ewt@redhat.com)
+ *
+ * Copyright 1996 Red Hat Software
+ *
+ */
+
+
+/*
+ * Each different frontend must implement all functions defined in frontend.h
+ */
+
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <sys/time.h>
+#include "newt/newt.h"
+
+#include <probing.h>
+
+#include "frontend.h"
+
+void init_frontend(char * welcome_msg)
+{
+ int i;
+ for (i=0; i<38; i++) printf("\n");
+ newtInit();
+ newtCls();
+
+ if (welcome_msg[0]) {
+ char *msg;
+ int cols, rows;
+ newtGetScreenSize(&cols, &rows);
+ asprintf(&msg, " %-*s", cols - 1, welcome_msg);
+ newtDrawRootText(0, 0, msg);
+ free(msg);
+ newtPushHelpLine(" <Alt-F1> for here, <Alt-F3> to see the logs, <Alt-F4> for kernel msg");
+ }
+ newtRefresh();
+}
+
+
+void finish_frontend(void)
+{
+ newtFinished();
+}
+
+
+void verror_message(char *msg, va_list ap)
+{
+ newtWinMessagev("Error", "Ok", msg, ap);
+}
+
+void vinfo_message(char *msg, va_list ap)
+{
+ newtWinMessagev("Notice", "Ok", msg, ap);
+}
+
+
+void vwait_message(char *msg, va_list ap)
+{
+ int width, height;
+ char * title = "Please wait...";
+ newtComponent c, f;
+ newtGrid grid;
+ char * buf = NULL;
+ char * flowed;
+ int size = 0;
+ int i = 0;
+
+ do {
+ size += 1000;
+ if (buf) free(buf);
+ buf = malloc(size);
+ i = vsnprintf(buf, size, msg, ap);
+ } while (i >= size || i == -1);
+
+ flowed = newtReflowText(buf, 60, 5, 5, &width, &height);
+
+ c = newtTextbox(-1, -1, width, height, NEWT_TEXTBOX_WRAP);
+ newtTextboxSetText(c, flowed);
+
+ grid = newtCreateGrid(1, 1);
+ newtGridSetField(grid, 0, 0, NEWT_GRID_COMPONENT, c, 0, 0, 0, 0, 0, 0);
+ newtGridWrappedWindow(grid, title);
+
+ free(flowed);
+ free(buf);
+
+ f = newtForm(NULL, NULL, 0);
+ newtFormAddComponent(f, c);
+
+ newtDrawForm(f);
+ newtRefresh();
+ newtFormDestroy(f);
+}
+
+void remove_wait_message(void)
+{
+ newtPopWindow();
+}
+
+
+static newtComponent form = NULL, scale = NULL;
+static int size_progress;
+static int actually_drawn;
+static char * msg_progress;
+
+void init_progression_raw(char *msg, int size)
+{
+ size_progress = size;
+ if (size) {
+ actually_drawn = 0;
+ newtCenteredWindow(70, 5, "Please wait...");
+ form = newtForm(NULL, NULL, 0);
+ newtFormAddComponent(form, newtLabel(1, 1, msg));
+ scale = newtScale(1, 3, 68, size);
+ newtFormAddComponent(form, scale);
+ newtDrawForm(form);
+ newtRefresh();
+ }
+ else {
+ wait_message(msg);
+ msg_progress = msg;
+ }
+}
+
+void update_progression_raw(int current_size)
+{
+ if (size_progress) {
+ if (current_size <= size_progress)
+ newtScaleSet(scale, current_size);
+ newtRefresh();
+ }
+ else {
+ struct timeval t;
+ int time;
+ static int last_time = -1;
+ gettimeofday(&t, NULL);
+ time = t.tv_sec*3 + t.tv_usec/300000;
+ if (time != last_time) {
+ char msg_prog_final[500];
+ sprintf(msg_prog_final, "%s (%d bytes read) ", msg_progress, current_size);
+ remove_wait_message();
+ wait_message(msg_prog_final);
+ }
+ last_time = time;
+ }
+}
+
+void end_progression_raw(void)
+{
+ if (size_progress) {
+ newtPopWindow();
+ newtFormDestroy(form);
+ }
+ else
+ remove_wait_message();
+}
+
+
+enum return_type ask_from_list_index(char *msg, char ** elems, char ** elems_comments, int * answer)
+{
+ char * items[50000];
+ int rc;
+
+ if (elems_comments) {
+ int i;
+
+ i = 0;
+ while (elems && *elems) {
+ int j = (*elems_comments) ? strlen(*elems_comments) : 0;
+ items[i] = malloc(sizeof(char) * (strlen(*elems) + j + 4));
+ strcpy(items[i], *elems);
+ if (*elems_comments) {
+ strcat(items[i], " (");
+ strcat(items[i], *elems_comments);
+ strcat(items[i], ")");
+ }
+ elems_comments++;
+ i++;
+ elems++;
+ }
+ items[i] = NULL;
+ }
+
+ rc = newtWinMenu("Please choose...", msg, 52, 5, 5, 7, elems_comments ? items : elems, answer, "Ok", "Cancel", NULL);
+
+ if (rc == 2)
+ return RETURN_BACK;
+
+ return RETURN_OK;
+}
+
+enum return_type ask_yes_no(char *msg)
+{
+ int rc;
+
+ rc = newtWinTernary("Please answer...", "Yes", "No", "Back", msg);
+
+ if (rc == 1)
+ return RETURN_OK;
+ else if (rc == 3)
+ return RETURN_BACK;
+ else return RETURN_ERROR;
+}
+
+
+static void (*callback_real_function)(char ** strings) = NULL;
+
+static void default_callback(newtComponent co __attribute__ ((unused)), void * data)
+{
+ newtComponent * entries = data;
+ char * strings[50], ** ptr;
+
+ if (!callback_real_function)
+ return;
+
+ ptr = strings;
+ while (entries && *entries) {
+ *ptr = newtEntryGetValue(*entries);
+ entries++;
+ ptr++;
+ }
+
+ callback_real_function(strings);
+
+ ptr = strings;
+ entries = data;
+ while (entries && *entries) {
+ newtEntrySet(*entries, strdup(*ptr), 1);
+ entries++;
+ ptr++;
+ }
+}
+
+/* only supports up to 50 buttons and entries -- shucks! */
+static int mynewtWinEntries(char * title, char * text, int suggestedWidth, int flexDown,
+ int flexUp, int dataWidth, void (*callback_func)(char ** strings),
+ struct newtWinEntry * items, char * button1, ...) {
+ newtComponent buttons[50], result, form, textw;
+ newtGrid grid, buttonBar, subgrid;
+ int numItems;
+ int rc, i;
+ int numButtons;
+ char * buttonName;
+ newtComponent entries[50];
+
+ va_list args;
+
+ textw = newtTextboxReflowed(-1, -1, text, suggestedWidth, flexDown,
+ flexUp, 0);
+
+ for (numItems = 0; items[numItems].text; numItems++);
+
+ buttonName = button1, numButtons = 0;
+ va_start(args, button1);
+ while (buttonName) {
+ buttons[numButtons] = newtButton(-1, -1, buttonName);
+ numButtons++;
+ buttonName = va_arg(args, char *);
+ }
+
+ va_end(args);
+
+ buttonBar = newtCreateGrid(numButtons, 1);
+ for (i = 0; i < numButtons; i++) {
+ newtGridSetField(buttonBar, i, 0, NEWT_GRID_COMPONENT,
+ buttons[i],
+ i ? 1 : 0, 0, 0, 0, 0, 0);
+ }
+
+ if (callback_func) {
+ callback_real_function = callback_func;
+ entries[numItems] = NULL;
+ }
+ else
+ callback_real_function = NULL;
+
+ subgrid = newtCreateGrid(2, numItems);
+ for (i = 0; i < numItems; i++) {
+ newtComponent entr = newtEntry(-1, -1, items[i].value ?
+ *items[i].value : NULL, dataWidth,
+ items[i].value, items[i].flags);
+
+ newtGridSetField(subgrid, 0, i, NEWT_GRID_COMPONENT,
+ newtLabel(-1, -1, items[i].text),
+ 0, 0, 0, 0, NEWT_ANCHOR_LEFT, 0);
+ newtGridSetField(subgrid, 1, i, NEWT_GRID_COMPONENT,
+ entr,
+ 1, 0, 0, 0, 0, 0);
+ if (callback_func) {
+ entries[i] = entr;
+ newtComponentAddCallback(entr, default_callback, entries);
+ }
+ }
+
+
+ grid = newtCreateGrid(1, 3);
+ form = newtForm(NULL, 0, 0);
+ newtGridSetField(grid, 0, 0, NEWT_GRID_COMPONENT, textw,
+ 0, 0, 0, 0, NEWT_ANCHOR_LEFT, 0);
+ newtGridSetField(grid, 0, 1, NEWT_GRID_SUBGRID, subgrid,
+ 0, 1, 0, 0, 0, 0);
+ newtGridSetField(grid, 0, 2, NEWT_GRID_SUBGRID, buttonBar,
+ 0, 1, 0, 0, 0, NEWT_GRID_FLAG_GROWX);
+ newtGridAddComponentsToForm(grid, form, 1);
+ newtGridWrappedWindow(grid, title);
+ newtGridFree(grid, 1);
+
+ result = newtRunForm(form);
+
+ for (rc = 0; rc < numItems; rc++)
+ *items[rc].value = strdup(*items[rc].value);
+
+ for (rc = 0; result != buttons[rc] && rc < numButtons; rc++);
+ if (rc == numButtons)
+ rc = 0; /* F12 */
+ else
+ rc++;
+
+ newtFormDestroy(form);
+ newtPopWindow();
+
+ return rc;
+}
+
+
+enum return_type ask_from_entries(char *msg, char ** questions, char *** answers, int entry_size, void (*callback_func)(char ** strings))
+{
+ struct newtWinEntry entries[50];
+ int j, i = 0;
+ int rc;
+ char ** already_answers = NULL;
+
+ while (questions && *questions) {
+ entries[i].text = *questions;
+ entries[i].flags = NEWT_FLAG_SCROLL | (!strcmp(*questions, "Password") ? NEWT_FLAG_PASSWORD : 0);
+ i++;
+ questions++;
+ }
+ entries[i].text = NULL;
+ entries[i].value = NULL;
+
+ if (*answers == NULL)
+ *answers = (char **) malloc(sizeof(char *) * i);
+ else
+ already_answers = *answers;
+
+ for (j = 0 ; j < i ; j++) {
+ entries[j].value = &((*answers)[j]);
+ if (already_answers && *already_answers) {
+ *(entries[j].value) = *already_answers;
+ already_answers++;
+ } else
+ *(entries[j].value) = NULL;
+ }
+
+ rc = mynewtWinEntries("Please fill in entries...", msg, 52, 5, 5, entry_size, callback_func, entries, "Ok", "Cancel", NULL);
+
+ if (rc == 3)
+ return RETURN_BACK;
+ if (rc != 1)
+ return RETURN_ERROR;
+
+ return RETURN_OK;
+}
+
+
+void suspend_to_console(void) { newtSuspend(); }
+void resume_from_suspend(void) { newtResume(); }
diff --git a/mdk-stage1/newt/Makefile b/mdk-stage1/newt/Makefile
new file mode 100644
index 000000000..fb6cdd5ff
--- /dev/null
+++ b/mdk-stage1/newt/Makefile
@@ -0,0 +1,42 @@
+ #******************************************************************************
+ #
+ # Guillaume Cottenceau (gc@mandrakesoft.com)
+ #
+ # Copyright 2000 Mandrakesoft
+ #
+ # This software may be freely redistributed under the terms of the GNU
+ # public license.
+ #
+ # 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.
+ #
+ #*****************************************************************************
+
+top_dir = ..
+
+include $(top_dir)/Makefile.common
+
+
+LIBNAME = libnewt
+
+OBJS = newt.o button.o form.o checkbox.o entry.o label.o listbox.o scrollbar.o textbox.o scale.o grid.o windows.o buttonbar.o checkboxtree.o
+
+DEFS = -DVERSION=\"0.50.19\"
+
+INCS = -I../slang
+
+
+TARGETS = $(LIBNAME).a
+
+all: $(TARGETS)
+
+clean:
+ rm -f *.o *.a
+
+$(LIBNAME).a: $(OBJS)
+ ar -cru $@ $^
+ ranlib $@
+
+$(OBJS): %.o: %.c
+ $(DIET) gcc $(CFLAGS) $(DEFS) $(INCS) $(INCLUDES) -c $< -o $@
diff --git a/mdk-stage1/newt/button.c b/mdk-stage1/newt/button.c
new file mode 100644
index 000000000..d7da58175
--- /dev/null
+++ b/mdk-stage1/newt/button.c
@@ -0,0 +1,192 @@
+#include <slang.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "newt.h"
+#include "newt_pr.h"
+
+struct button {
+ char * text;
+ int compact;
+};
+
+static void buttonDrawIt(newtComponent co, int active, int pushed);
+static void buttonDrawText(newtComponent co, int active, int pushed);
+
+static void buttonDraw(newtComponent c);
+static void buttonDestroy(newtComponent co);
+static struct eventResult buttonEvent(newtComponent c,
+ struct event ev);
+static void buttonPlace(newtComponent co, int newLeft, int newTop);
+
+static struct componentOps buttonOps = {
+ buttonDraw,
+ buttonEvent,
+ buttonDestroy,
+ buttonPlace,
+ newtDefaultMappedHandler,
+} ;
+
+static newtComponent createButton(int left, int row, const char * text, int compact) {
+ newtComponent co;
+ struct button * bu;
+
+ co = malloc(sizeof(*co));
+ bu = malloc(sizeof(struct button));
+ co->data = bu;
+
+ bu->text = strdup(text);
+ bu->compact = compact;
+ co->ops = &buttonOps;
+
+ if (bu->compact) {
+ co->height = 1;
+ co->width = strlen(text) + 3;
+ } else {
+ co->height = 4;
+ co->width = strlen(text) + 5;
+ }
+
+ co->top = row;
+ co->left = left;
+ co->takesFocus = 1;
+ co->isMapped = 0;
+
+ newtGotorc(co->top, co->left);
+
+ return co;
+}
+
+newtComponent newtCompactButton(int left, int row, const char * text) {
+ return createButton(left, row, text, 1);
+}
+
+newtComponent newtButton(int left, int row, const char * text) {
+ return createButton(left, row, text, 0);
+}
+
+static void buttonDestroy(newtComponent co) {
+ struct button * bu = co->data;
+
+ free(bu->text);
+ free(bu);
+ free(co);
+}
+
+static void buttonPlace(newtComponent co, int newLeft, int newTop) {
+ co->top = newTop;
+ co->left = newLeft;
+
+ newtGotorc(co->top, co->left);
+}
+
+static void buttonDraw(newtComponent co) {
+ buttonDrawIt(co, 0, 0);
+}
+
+static void buttonDrawIt(newtComponent co, int active, int pushed) {
+ struct button * bu = co->data;
+
+ if (!co->isMapped) return;
+
+ SLsmg_set_color(NEWT_COLORSET_BUTTON);
+
+ if (bu->compact) {
+ if (active)
+ SLsmg_set_color(NEWT_COLORSET_COMPACTBUTTON);
+ else
+ SLsmg_set_color(NEWT_COLORSET_BUTTON);
+ newtGotorc(co->top+ pushed, co->left + 1 + pushed);
+ SLsmg_write_char('<');
+ SLsmg_write_string(bu->text);
+ SLsmg_write_char('>');
+ } else {
+ if (pushed) {
+ SLsmg_set_color(NEWT_COLORSET_BUTTON);
+ newtDrawBox(co->left + 1, co->top + 1, co->width - 1, 3, 0);
+
+ SLsmg_set_color(NEWT_COLORSET_WINDOW);
+ newtClearBox(co->left, co->top, co->width, 1);
+ newtClearBox(co->left, co->top, 1, co->height);
+ } else {
+ newtDrawBox(co->left, co->top, co->width - 1, 3, 1);
+ }
+
+ buttonDrawText(co, active, pushed);
+ }
+}
+
+static void buttonDrawText(newtComponent co, int active, int pushed) {
+ struct button * bu = co->data;
+
+ if (pushed) pushed = 1;
+
+ if (active)
+ SLsmg_set_color(NEWT_COLORSET_ACTBUTTON);
+ else
+ SLsmg_set_color(NEWT_COLORSET_BUTTON);
+
+ newtGotorc(co->top + 1 + pushed, co->left + 1 + pushed);
+ SLsmg_write_char(' ');
+ SLsmg_write_string(bu->text);
+ SLsmg_write_char(' ');
+}
+
+static struct eventResult buttonEvent(newtComponent co,
+ struct event ev) {
+ struct eventResult er;
+ struct button * bu = co->data;
+ er.result = ER_IGNORED;
+ er.u.focus = NULL;
+
+ if (ev.when == EV_NORMAL) {
+ switch (ev.event) {
+ case EV_FOCUS:
+ buttonDrawIt(co, 1, 0);
+ er.result = ER_SWALLOWED;
+ break;
+
+ case EV_UNFOCUS:
+ buttonDrawIt(co, 0, 0);
+ er.result = ER_SWALLOWED;
+ break;
+
+ case EV_KEYPRESS:
+ if (ev.u.key == ' ' || ev.u.key == '\r') {
+ if (!bu->compact) {
+ /* look pushed */
+ buttonDrawIt(co, 1, 1);
+ newtRefresh();
+ newtDelay(150000);
+ buttonDrawIt(co, 1, 0);
+ newtRefresh();
+ newtDelay(150000);
+ }
+
+ er.result = ER_EXITFORM;
+ } else
+ er.result = ER_IGNORED;
+ break;
+ case EV_MOUSE:
+ if (ev.u.mouse.type == MOUSE_BUTTON_DOWN &&
+ co->top <= ev.u.mouse.y &&
+ co->top + co->height - !bu->compact > ev.u.mouse.y &&
+ co->left <= ev.u.mouse.x &&
+ co->left + co->width - !bu->compact > ev.u.mouse.x) {
+ if (!bu->compact) {
+ buttonDrawIt(co, 1, 1);
+ newtRefresh();
+ newtDelay(150000);
+ buttonDrawIt(co, 1, 0);
+ newtRefresh();
+ newtDelay(150000);
+ }
+ er.result = ER_EXITFORM;
+ }
+ break;
+ }
+ } else
+ er.result = ER_IGNORED;
+
+ return er;
+}
diff --git a/mdk-stage1/newt/buttonbar.c b/mdk-stage1/newt/buttonbar.c
new file mode 100644
index 000000000..45473c9d2
--- /dev/null
+++ b/mdk-stage1/newt/buttonbar.c
@@ -0,0 +1,46 @@
+#include <stdarg.h>
+
+#include "newt.h"
+
+/* if they try and pack more then 50 buttons, screw 'em */
+newtGrid newtButtonBarv(char * button1, newtComponent * b1comp, va_list args) {
+ newtGrid grid;
+ struct buttonInfo {
+ char * name;
+ newtComponent * compPtr;
+ } buttons[50];
+ int num;
+ int i;
+
+ buttons[0].name = button1, buttons[0].compPtr = b1comp, num = 1;
+ while (1) {
+ buttons[num].name = va_arg(args, char *);
+ if (!buttons[num].name) break;
+ buttons[num].compPtr = va_arg(args, newtComponent *);
+ num++;
+ }
+
+ grid = newtCreateGrid(num, 1);
+
+ for (i = 0; i < num; i++) {
+ *buttons[i].compPtr = newtButton(-1, -1, buttons[i].name);
+ newtGridSetField(grid, i, 0, NEWT_GRID_COMPONENT,
+ *buttons[i].compPtr,
+ num ? 1 : 0, 0, 0, 0, 0, 0);
+ }
+
+ return grid;
+}
+
+newtGrid newtButtonBar(char * button1, newtComponent * b1comp, ...) {
+ va_list args;
+ newtGrid grid;
+
+ va_start(args, b1comp);
+
+ grid = newtButtonBarv(button1, b1comp, args);
+
+ va_end(args);
+
+ return grid;
+}
diff --git a/mdk-stage1/newt/checkbox.c b/mdk-stage1/newt/checkbox.c
new file mode 100644
index 000000000..643609d34
--- /dev/null
+++ b/mdk-stage1/newt/checkbox.c
@@ -0,0 +1,292 @@
+#include <slang.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "newt.h"
+#include "newt_pr.h"
+
+enum type { CHECK, RADIO };
+
+struct checkbox {
+ char * text;
+ char * seq;
+ char * result;
+ newtComponent prevButton, lastButton;
+ enum type type;
+ char value;
+ int active, inactive;
+ const void * data;
+ int flags;
+ int hasFocus;
+};
+
+static void makeActive(newtComponent co);
+
+static void cbDraw(newtComponent c);
+static void cbDestroy(newtComponent co);
+struct eventResult cbEvent(newtComponent co, struct event ev);
+
+static struct componentOps cbOps = {
+ cbDraw,
+ cbEvent,
+ cbDestroy,
+ newtDefaultPlaceHandler,
+ newtDefaultMappedHandler,
+} ;
+
+newtComponent newtRadiobutton(int left, int top, const char * text, int isDefault,
+ newtComponent prevButton) {
+ newtComponent co;
+ newtComponent curr;
+ struct checkbox * rb;
+ char initialValue;
+
+ if (isDefault)
+ initialValue = '*';
+ else
+ initialValue = ' ';
+
+ co = newtCheckbox(left, top, text, initialValue, " *", NULL);
+ rb = co->data;
+ rb->type = RADIO;
+
+ rb->prevButton = prevButton;
+
+ for (curr = co; curr; curr = rb->prevButton) {
+ rb = curr->data;
+ rb->lastButton = co;
+ }
+
+ return co;
+}
+
+newtComponent newtRadioGetCurrent(newtComponent setMember) {
+ struct checkbox * rb = setMember->data;
+
+ setMember = rb->lastButton;
+ rb = setMember->data;
+
+ while (rb && rb->value != '*') {
+ setMember = rb->prevButton;
+ if (!setMember)
+ return NULL;
+ rb = setMember->data;
+ }
+
+ return setMember;
+}
+
+char newtCheckboxGetValue(newtComponent co) {
+ struct checkbox * cb = co->data;
+
+ return cb->value;
+}
+
+void newtCheckboxSetValue(newtComponent co, char value) {
+ struct checkbox * cb = co->data;
+
+ *cb->result = value;
+ cbDraw(co);
+}
+
+newtComponent newtCheckbox(int left, int top, const char * text, char defValue,
+ const char * seq, char * result) {
+ newtComponent co;
+ struct checkbox * cb;
+
+ if (!seq) seq = " *";
+
+ co = malloc(sizeof(*co));
+ cb = malloc(sizeof(struct checkbox));
+ co->data = cb;
+ cb->flags = 0;
+ if (result)
+ cb->result = result;
+ else
+ cb->result = &cb->value;
+
+ cb->text = strdup(text);
+ cb->seq = strdup(seq);
+ cb->type = CHECK;
+ cb->hasFocus = 0;
+ cb->inactive = COLORSET_CHECKBOX;
+ cb->active = COLORSET_ACTCHECKBOX;
+ defValue ? (*cb->result = defValue) : (*cb->result = cb->seq[0]);
+
+ co->ops = &cbOps;
+
+ co->callback = NULL;
+ co->height = 1;
+ co->width = strlen(text) + 4;
+ co->top = top;
+ co->left = left;
+ co->takesFocus = 1;
+
+ return co;
+}
+
+void newtCheckboxSetFlags(newtComponent co, int flags, enum newtFlagsSense sense) {
+ struct checkbox * cb = co->data;
+ int row, col;
+
+ cb->flags = newtSetFlags(cb->flags, flags, sense);
+
+ if (!(cb->flags & NEWT_FLAG_DISABLED))
+ co->takesFocus = 1;
+ else
+ co->takesFocus = 0;
+
+ newtGetrc(&row, &col);
+ cbDraw(co);
+ newtGotorc(row, col);
+}
+
+static void cbDraw(newtComponent c) {
+ struct checkbox * cb = c->data;
+
+ if (c->top == -1 || !c->isMapped) return;
+
+ if (cb->flags & NEWT_FLAG_DISABLED) {
+ cb->inactive = NEWT_COLORSET_DISENTRY;
+ cb->active = NEWT_COLORSET_DISENTRY;
+ } else {
+ cb->inactive = COLORSET_CHECKBOX;
+ cb->active = COLORSET_ACTCHECKBOX;
+ }
+
+ SLsmg_set_color(cb->inactive);
+
+ newtGotorc(c->top, c->left);
+
+ switch (cb->type) {
+ case RADIO:
+ SLsmg_write_string("( ) ");
+ break;
+
+ case CHECK:
+ SLsmg_write_string("[ ] ");
+ break;
+
+ default:
+ break;
+ }
+
+ SLsmg_write_string(cb->text);
+
+ if (cb->hasFocus)
+ SLsmg_set_color(cb->active);
+
+ newtGotorc(c->top, c->left + 1);
+ SLsmg_write_char(*cb->result);
+}
+
+static void cbDestroy(newtComponent co) {
+ struct checkbox * cb = co->data;
+
+ free(cb->text);
+ free(cb->seq);
+ free(cb);
+ free(co);
+}
+
+struct eventResult cbEvent(newtComponent co, struct event ev) {
+ struct checkbox * cb = co->data;
+ struct eventResult er;
+ const char * cur;
+ er.result = ER_IGNORED;
+ er.u.focus = NULL;
+
+ if (ev.when == EV_NORMAL) {
+ switch (ev.event) {
+ case EV_FOCUS:
+ cb->hasFocus = 1;
+ cbDraw(co);
+ er.result = ER_SWALLOWED;
+ break;
+
+ case EV_UNFOCUS:
+ cb->hasFocus = 0;
+ cbDraw(co);
+ er.result = ER_SWALLOWED;
+ break;
+
+ case EV_KEYPRESS:
+ if (ev.u.key == ' ') {
+ if (cb->type == RADIO) {
+ makeActive(co);
+ } else if (cb->type == CHECK) {
+ cur = strchr(cb->seq, *cb->result);
+ if (!cur)
+ *cb->result = *cb->seq;
+ else {
+ cur++;
+ if (! *cur)
+ *cb->result = *cb->seq;
+ else
+ *cb->result = *cur;
+ }
+ cbDraw(co);
+ er.result = ER_SWALLOWED;
+
+ if (co->callback)
+ co->callback(co, co->callbackData);
+ } else {
+ er.result = ER_IGNORED;
+ }
+ } else if(ev.u.key == NEWT_KEY_ENTER) {
+ er.result = ER_IGNORED;
+ } else {
+ er.result = ER_IGNORED;
+ }
+ break;
+ case EV_MOUSE:
+ if (ev.u.mouse.type == MOUSE_BUTTON_DOWN) {
+ if (cb->type == RADIO) {
+ makeActive(co);
+ } else if (cb->type == CHECK) {
+ cur = strchr(cb->seq, *cb->result);
+ if (!cur)
+ *cb->result = *cb->seq;
+ else {
+ cur++;
+ if (! *cur)
+ *cb->result = *cb->seq;
+ else
+ *cb->result = *cur;
+ }
+ cbDraw(co);
+ er.result = ER_SWALLOWED;
+
+ if (co->callback)
+ co->callback(co, co->callbackData);
+ }
+ }
+ }
+ } else
+ er.result = ER_IGNORED;
+
+ return er;
+}
+
+static void makeActive(newtComponent co) {
+ struct checkbox * cb = co->data;
+ struct checkbox * rb;
+ newtComponent curr;
+
+ /* find the one that's turned off */
+ curr = cb->lastButton;
+ rb = curr->data;
+ while (curr && rb->value == rb->seq[0]) {
+ curr = rb->prevButton;
+ if (curr) rb = curr->data;
+ }
+ if (curr) {
+ rb->value = rb->seq[0];
+ cbDraw(curr);
+ }
+ cb->value = cb->seq[1];
+ cbDraw(co);
+
+ if (co->callback)
+ co->callback(co, co->callbackData);
+}
diff --git a/mdk-stage1/newt/checkboxtree.c b/mdk-stage1/newt/checkboxtree.c
new file mode 100644
index 000000000..00113f23e
--- /dev/null
+++ b/mdk-stage1/newt/checkboxtree.c
@@ -0,0 +1,714 @@
+#include <slang.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "newt.h"
+#include "newt_pr.h"
+
+struct items {
+ char * text;
+ const void *data;
+ unsigned char selected;
+ struct items *next;
+ struct items *prev;
+ struct items *branch;
+ int flags;
+ int depth;
+};
+
+struct CheckboxTree {
+ newtComponent sb;
+ int curWidth; /* size of text w/o scrollbar or border*/
+ int curHeight; /* size of text w/o border */
+ struct items * itemlist;
+ struct items ** flatList, ** currItem, ** firstItem;
+ int flatCount;
+ int flags;
+ int pad;
+ char * seq;
+ char * result;
+};
+
+static void ctDraw(newtComponent c);
+static void ctDestroy(newtComponent co);
+static void ctPlace(newtComponent co, int newLeft, int newTop);
+struct eventResult ctEvent(newtComponent co, struct event ev);
+static void ctMapped(newtComponent co, int isMapped);
+static struct items * findItem(struct items * items, const void * data);
+static void buildFlatList(newtComponent co);
+static void doBuildFlatList(struct CheckboxTree * ct, struct items * item);
+enum countWhat { COUNT_EXPOSED=0, COUNT_SELECTED=1 };
+static int countItems(struct items * item, enum countWhat justExposed);
+
+static struct componentOps ctOps = {
+ ctDraw,
+ ctEvent,
+ ctDestroy,
+ ctPlace,
+ ctMapped,
+} ;
+
+static int countItems(struct items * item, enum countWhat what) {
+ int count = 0;
+
+ while (item) {
+ if ((!item->branch && item->selected == what) || (what == COUNT_EXPOSED))
+ count++;
+ if (item->branch || (what == COUNT_EXPOSED && item->selected))
+ count += countItems(item->branch, what);
+ item = item->next;
+ }
+
+ return count;
+}
+
+static void doBuildFlatList(struct CheckboxTree * ct, struct items * item) {
+ while (item) {
+ ct->flatList[ct->flatCount++] = item;
+ if (item->branch && item->selected) doBuildFlatList(ct, item->branch);
+ item = item->next;
+ }
+}
+
+static void buildFlatList(newtComponent co) {
+ struct CheckboxTree * ct = co->data;
+
+ if (ct->flatList) free(ct->flatList);
+ ct->flatCount = countItems(ct->itemlist, COUNT_EXPOSED);
+
+ ct->flatList = malloc(sizeof(*ct->flatList) * (ct->flatCount+1));
+ ct->flatCount = 0;
+ doBuildFlatList(ct, ct->itemlist);
+ ct->flatList[ct->flatCount] = NULL;
+}
+
+int newtCheckboxTreeAddItem(newtComponent co,
+ const char * text, const void * data,
+ int flags, int index, ...) {
+ va_list argList;
+ int numIndexes;
+ int * indexes;
+ int i;
+
+ va_start(argList, index);
+ numIndexes = 0;
+ i = index;
+ while (i != NEWT_ARG_LAST) {
+ numIndexes++;
+ i = va_arg(argList, int);
+ }
+
+ va_end(argList);
+
+ indexes = alloca(sizeof(*indexes) * (numIndexes + 1));
+ va_start(argList, index);
+ numIndexes = 0;
+ i = index;
+ va_start(argList, index);
+ while (i != NEWT_ARG_LAST) {
+ indexes[numIndexes++] = i;
+ i = va_arg(argList, int);
+ }
+ va_end(argList);
+
+ indexes[numIndexes++] = NEWT_ARG_LAST;
+
+ return newtCheckboxTreeAddArray(co, text, data, flags, indexes);
+}
+
+static int doFindItemPath(struct items * items, void * data, int * path,
+ int * len) {
+ int where = 0;
+
+ while (items) {
+ if (items->data == data) {
+ if (path) path[items->depth] = where;
+ if (len) *len = items->depth + 1;
+ return 1;
+ }
+
+ if (items->branch && doFindItemPath(items->branch, data, path, len)) {
+ if (path) path[items->depth] = where;
+ return 1;
+ }
+
+ items = items->next;
+ where++;
+ }
+
+ return 0;
+}
+
+int * newtCheckboxTreeFindItem(newtComponent co, void * data) {
+ int len;
+ int * path;
+ struct CheckboxTree * ct = co->data;
+
+ if (!doFindItemPath(ct->itemlist, data, NULL, &len)) return NULL;
+
+ path = malloc(sizeof(*path) * (len + 1));
+ doFindItemPath(ct->itemlist, data, path, NULL);
+ path[len] = NEWT_ARG_LAST;
+
+ return path;
+}
+
+int newtCheckboxTreeAddArray(newtComponent co,
+ const char * text, const void * data,
+ int flags, int * indexes) {
+ struct items * curList, * newNode, * item = NULL;
+ struct items ** listPtr = NULL;
+ int i, index, numIndexes;
+ struct CheckboxTree * ct = co->data;
+
+ numIndexes = 0;
+ while (indexes[numIndexes] != NEWT_ARG_LAST) numIndexes++;
+
+ if (!ct->itemlist) {
+ if (numIndexes > 1) return -1;
+
+ ct->itemlist = malloc(sizeof(*ct->itemlist));
+ item = ct->itemlist;
+ item->prev = NULL;
+ item->next = NULL;
+ } else {
+ curList = ct->itemlist;
+ listPtr = &ct->itemlist;
+
+ i = 0;
+ index = indexes[i];
+ while (i < numIndexes) {
+ item = curList;
+
+ if (index == NEWT_ARG_APPEND) {
+ item = NULL;
+ } else {
+ while (index && item)
+ item = item->next, index--;
+ }
+
+ i++;
+ if (i < numIndexes) {
+ curList = item->branch;
+ listPtr = &item->branch;
+ if (!curList && (i + 1 != numIndexes)) return -1;
+
+ index = indexes[i];
+ }
+ }
+
+ if (!curList) { /* create a new branch */
+ item = malloc(sizeof(*curList->prev));
+ item->next = item->prev = NULL;
+ *listPtr = item;
+ } else if (!item) { /* append to end */
+ item = curList;
+ while (item->next) item = item->next;
+ item->next = malloc(sizeof(*curList->prev));
+ item->next->prev = item;
+ item = item->next;
+ item->next = NULL;
+ } else {
+ newNode = malloc(sizeof(*newNode));
+ newNode->prev = item->prev;
+ newNode->next = item;
+
+ if (item->prev) item->prev->next = newNode;
+ item->prev = newNode;
+ item = newNode;
+ if (!item->prev) *listPtr = item;
+ }
+ }
+
+ item->text = strdup(text);
+ item->data = data;
+ if (flags & NEWT_FLAG_SELECTED) {
+ item->selected = 1;
+ } else {
+ item->selected = 0;
+ }
+ item->flags = flags;
+ item->branch = NULL;
+ item->depth = numIndexes - 1;
+
+ i = 4 + (3 * item->depth);
+
+ if ((strlen(text) + i + ct->pad) > (size_t)co->width) {
+ co->width = strlen(text) + i + ct->pad;
+ }
+
+ return 0;
+}
+
+static struct items * findItem(struct items * items, const void * data) {
+ struct items * i;
+
+ while (items) {
+ if (items->data == data) return items;
+ if (items->branch) {
+ i = findItem(items->branch, data);
+ if (i) return i;
+ }
+
+ items = items->next;
+ }
+
+ return NULL;
+}
+
+static void listSelected(struct items * items, int * num, const void ** list, int seqindex) {
+ while (items) {
+ if ((seqindex ? items->selected==seqindex : items->selected) && !items->branch)
+ list[(*num)++] = (void *) items->data;
+ if (items->branch)
+ listSelected(items->branch, num, list, seqindex);
+ items = items->next;
+ }
+}
+
+const void ** newtCheckboxTreeGetSelection(newtComponent co, int *numitems)
+{
+ return newtCheckboxTreeGetMultiSelection(co, numitems, 0);
+}
+
+const void ** newtCheckboxTreeGetMultiSelection(newtComponent co, int *numitems, char seqnum)
+{
+ struct CheckboxTree * ct;
+ const void **retval;
+ int seqindex=0;
+
+ if(!co || !numitems) return NULL;
+
+ ct = co->data;
+
+ if (seqnum) {
+ while( ct->seq[seqindex] && ( ct->seq[seqindex] != seqnum )) seqindex++;
+ } else {
+ seqindex = 0;
+ }
+
+ *numitems = countItems(ct->itemlist, (seqindex ? seqindex : COUNT_SELECTED));
+ if (!*numitems) return NULL;
+
+ retval = malloc(*numitems * sizeof(void *));
+ *numitems = 0;
+ listSelected(ct->itemlist, numitems, retval, seqindex);
+
+ return retval;
+}
+
+newtComponent newtCheckboxTree(int left, int top, int height, int flags) {
+ return newtCheckboxTreeMulti(left, top, height, NULL, flags);
+}
+
+newtComponent newtCheckboxTreeMulti(int left, int top, int height, char *seq, int flags) {
+ newtComponent co;
+ struct CheckboxTree * ct;
+
+ co = malloc(sizeof(*co));
+ ct = malloc(sizeof(struct CheckboxTree));
+ co->callback = NULL;
+ co->data = ct;
+ co->ops = &ctOps;
+ co->takesFocus = 1;
+ co->height = height;
+ co->width = 0;
+ co->isMapped = 0;
+ ct->itemlist = NULL;
+ ct->firstItem = NULL;
+ ct->currItem = NULL;
+ ct->flatList = NULL;
+ if (seq)
+ ct->seq = strdup(seq);
+ else
+ ct->seq = strdup(" *");
+ if (flags & NEWT_FLAG_SCROLL) {
+ ct->sb = newtVerticalScrollbar(left, top, height,
+ COLORSET_LISTBOX, COLORSET_ACTLISTBOX);
+ ct->pad = 2;
+ } else {
+ ct->sb = NULL;
+ ct->pad = 0;
+ }
+
+ return co;
+}
+
+static void ctMapped(newtComponent co, int isMapped) {
+ struct CheckboxTree * ct = co->data;
+
+ co->isMapped = isMapped;
+ if (ct->sb)
+ ct->sb->ops->mapped(ct->sb, isMapped);
+}
+
+static void ctPlace(newtComponent co, int newLeft, int newTop) {
+ struct CheckboxTree * ct = co->data;
+
+ co->top = newTop;
+ co->left = newLeft;
+
+ if (ct->sb)
+ ct->sb->ops->place(ct->sb, co->left + co->width - 1, co->top);
+}
+
+int ctSetItem(newtComponent co, struct items *item, enum newtFlagsSense sense)
+{
+ struct CheckboxTree * ct = co->data;
+ struct items * currItem;
+ struct items * firstItem;
+
+ if (!item)
+ return 1;
+
+ switch(sense) {
+ case NEWT_FLAGS_RESET:
+ item->selected = 0;
+ break;
+ case NEWT_FLAGS_SET:
+ item->selected = 1;
+ break;
+ case NEWT_FLAGS_TOGGLE:
+ if (item->branch)
+ item->selected = !item->selected;
+ else {
+ item->selected++;
+ if (item->selected==strlen(ct->seq))
+ item->selected = 0;
+ }
+ break;
+ }
+
+ if (item->branch) {
+ currItem = *ct->currItem;
+ firstItem = *ct->firstItem;
+
+ buildFlatList(co);
+
+ ct->currItem = ct->flatList;
+ while (*ct->currItem != currItem) ct->currItem++;
+
+ ct->firstItem = ct->flatList;
+ if (ct->flatCount > co->height) {
+ struct items ** last = ct->flatList + ct->flatCount - co->height;
+ while (*ct->firstItem != firstItem && ct->firstItem != last)
+ ct->firstItem++;
+ }
+ }
+
+ return 0;
+}
+
+static void ctSetItems(struct items *item, int selected)
+{
+ for (; item; item = item->next) {
+ if (!item->branch)
+ item->selected = selected;
+ else
+ ctSetItems(item->branch, selected);
+ }
+}
+
+static void ctDraw(newtComponent co) {
+ struct CheckboxTree * ct = co->data;
+ struct items ** item;
+ int i, j;
+ char * spaces = NULL;
+ int currRow = -1;
+
+ if (!co->isMapped) return ;
+
+ if (!ct->firstItem) {
+ buildFlatList(co);
+ ct->firstItem = ct->currItem = ct->flatList;
+ }
+
+ item = ct->firstItem;
+
+ i = 0;
+ while (*item && i < co->height) {
+ newtGotorc(co->top + i, co->left);
+ if (*item == *ct->currItem) {
+ SLsmg_set_color(NEWT_COLORSET_ACTLISTBOX);
+ currRow = co->top + i;
+ } else
+ SLsmg_set_color(NEWT_COLORSET_LISTBOX);
+
+ for (j = 0; j < (*item)->depth; j++)
+ SLsmg_write_string(" ");
+
+ if ((*item)->branch) {
+ if ((*item)->selected)
+ SLsmg_write_string("<-> ");
+ else
+ SLsmg_write_string("<+> ");
+ } else {
+ char tmp[5];
+ snprintf(tmp,5,"[%c] ",ct->seq[(*item)->selected]);
+ SLsmg_write_string(tmp);
+ }
+
+ SLsmg_write_nstring((*item)->text, co->width - 4 -
+ (3 * (*item)->depth));
+ item++;
+ i++;
+ }
+
+ /* There could be empty lines left (i.e. if the user closes an expanded
+ list which is the last thing in the tree, and whose elements are
+ displayed at the bottom of the screen */
+ if (i < co->height) {
+ spaces = alloca(co->width);
+ memset(spaces, ' ', co->width);
+ SLsmg_set_color(NEWT_COLORSET_LISTBOX);
+ }
+ while (i < co->height) {
+ newtGotorc(co->top + i, co->left);
+ SLsmg_write_nstring(spaces, co->width);
+ i++;
+ }
+
+ if(ct->sb) {
+ newtScrollbarSet(ct->sb, ct->currItem - ct->flatList,
+ ct->flatCount - 1);
+ ct->sb->ops->draw(ct->sb);
+ }
+
+ newtGotorc(currRow, co->left + 1);
+}
+
+static void ctDestroy(newtComponent co) {
+ struct CheckboxTree * ct = co->data;
+ struct items * item, * nextitem;
+
+ nextitem = item = ct->itemlist;
+
+ while (item != NULL) {
+ nextitem = item->next;
+ free(item->text);
+ free(item);
+ item = nextitem;
+ }
+
+ free(ct->seq);
+ free(ct);
+ free(co);
+}
+
+struct eventResult ctEvent(newtComponent co, struct event ev) {
+ struct CheckboxTree * ct = co->data;
+ struct eventResult er;
+ struct items ** listEnd, ** lastItem;
+ int key, selnum = 1;
+
+ er.result = ER_IGNORED;
+
+ if(ev.when == EV_EARLY || ev.when == EV_LATE) {
+ return er;
+ }
+
+ switch(ev.event) {
+ case EV_KEYPRESS:
+ key = ev.u.key;
+ if (key == (char) key && key != ' ') {
+ for (selnum = 0; ct->seq[selnum]; selnum++)
+ if (key == ct->seq[selnum])
+ break;
+ if (!ct->seq[selnum])
+ switch (key) {
+ case '-': selnum = 0; break;
+ case '+':
+ case '*': selnum = 1; break;
+ }
+ if (ct->seq[selnum])
+ key = '*';
+ }
+ switch(key) {
+ case ' ':
+ case NEWT_KEY_ENTER:
+ ctSetItem(co, *ct->currItem, NEWT_FLAGS_TOGGLE);
+ er.result = ER_SWALLOWED;
+ if (!(*ct->currItem)->branch || (*ct->currItem)->selected)
+ key = NEWT_KEY_DOWN;
+ else
+ key = '*';
+ break;
+ case '*':
+ if ((*ct->currItem)->branch) {
+ ctSetItems((*ct->currItem)->branch, selnum);
+ if (!(*ct->currItem)->selected)
+ key = NEWT_KEY_DOWN;
+ } else {
+ (*ct->currItem)->selected = selnum;
+ key = NEWT_KEY_DOWN;
+ }
+ er.result = ER_SWALLOWED;
+ break;
+ }
+ switch (key) {
+ case '*':
+ ctDraw(co);
+ if(co->callback) co->callback(co, co->callbackData);
+ return er;
+ case NEWT_KEY_HOME:
+ ct->currItem = ct->flatList;
+ ct->firstItem = ct->flatList;
+ ctDraw(co);
+ if(co->callback) co->callback(co, co->callbackData);
+ er.result = ER_SWALLOWED;
+ return er;
+ case NEWT_KEY_END:
+ ct->currItem = ct->flatList + ct->flatCount - 1;
+ if (ct->flatCount <= co->height)
+ ct->firstItem = ct->flatList;
+ else
+ ct->firstItem = ct->flatList + ct->flatCount - co->height;
+ ctDraw(co);
+ if(co->callback) co->callback(co, co->callbackData);
+ er.result = ER_SWALLOWED;
+ return er;
+ case NEWT_KEY_DOWN:
+ if (ev.u.key != NEWT_KEY_DOWN) {
+ if(co->callback) co->callback(co, co->callbackData);
+ if (strlen(ct->seq) != 2) {
+ ctDraw(co);
+ return er;
+ }
+ }
+ if ((ct->currItem - ct->flatList + 1) < ct->flatCount) {
+ ct->currItem++;
+
+ if (ct->currItem - ct->firstItem >= co->height)
+ ct->firstItem++;
+
+ ctDraw(co);
+ } else if (ev.u.key != NEWT_KEY_DOWN)
+ ctDraw(co);
+ if(co->callback) co->callback(co, co->callbackData);
+ er.result = ER_SWALLOWED;
+ return er;
+ case NEWT_KEY_UP:
+ if (ct->currItem != ct->flatList) {
+ ct->currItem--;
+
+ if (ct->currItem < ct->firstItem)
+ ct->firstItem = ct->currItem;
+
+ ctDraw(co);
+ }
+ er.result = ER_SWALLOWED;
+ if(co->callback) co->callback(co, co->callbackData);
+ return er;
+ case NEWT_KEY_PGUP:
+ if (ct->firstItem - co->height < ct->flatList) {
+ ct->firstItem = ct->currItem = ct->flatList;
+ } else {
+ ct->currItem -= co->height;
+ ct->firstItem -= co->height;
+ }
+
+ ctDraw(co);
+ if(co->callback) co->callback(co, co->callbackData);
+ er.result = ER_SWALLOWED;
+ return er;
+ case NEWT_KEY_PGDN:
+ listEnd = ct->flatList + ct->flatCount - 1;
+ lastItem = ct->firstItem + co->height - 1;
+
+ if (lastItem + co->height > listEnd) {
+ ct->firstItem = listEnd - co->height + 1;
+ ct->currItem = listEnd;
+ } else {
+ ct->currItem += co->height;
+ ct->firstItem += co->height;
+ }
+
+ ctDraw(co);
+ if(co->callback) co->callback(co, co->callbackData);
+ er.result = ER_SWALLOWED;
+ return er;
+ }
+ break;
+
+ case EV_FOCUS:
+ ctDraw(co);
+ er.result = ER_SWALLOWED;
+ break;
+
+ case EV_UNFOCUS:
+ ctDraw(co);
+ er.result = ER_SWALLOWED;
+ break;
+ default:
+ break;
+ }
+
+ return er;
+}
+
+const void * newtCheckboxTreeGetCurrent(newtComponent co) {
+ struct CheckboxTree * ct = co->data;
+
+ if (!ct->currItem) return NULL;
+ return (*ct->currItem)->data;
+}
+
+void newtCheckboxTreeSetEntry(newtComponent co, const void * data, const char * text)
+{
+ struct CheckboxTree * ct;
+ struct items * item;
+ int i;
+
+ if (!co) return;
+ ct = co->data;
+ item = findItem(ct->itemlist, data);
+ if (!item) return;
+
+ free(item->text);
+ item->text = strdup(text);
+
+ i = 4 + (3 * item->depth);
+
+ if ((strlen(text) + i + ct->pad) > (size_t)co->width) {
+ co->width = strlen(text) + i + ct->pad;
+ }
+
+ ctDraw(co);
+}
+
+char newtCheckboxTreeGetEntryValue(newtComponent co, const void * data)
+{
+ struct CheckboxTree * ct;
+ struct items * item;
+
+ if (!co) return -1;
+ ct = co->data;
+ item = findItem(ct->itemlist, data);
+ if (!item) return -1;
+ if (item->branch)
+ return item->selected ? NEWT_CHECKBOXTREE_EXPANDED : NEWT_CHECKBOXTREE_COLLAPSED;
+ else
+ return ct->seq[item->selected];
+}
+
+void newtCheckboxTreeSetEntryValue(newtComponent co, const void * data, char value)
+{
+ struct CheckboxTree * ct;
+ struct items * item;
+ int i;
+
+ if (!co) return;
+ ct = co->data;
+ item = findItem(ct->itemlist, data);
+ if (!item || item->branch) return;
+
+ for(i = 0; ct->seq[i]; i++)
+ if (value == ct->seq[i])
+ break;
+
+ if (!ct->seq[i]) return;
+ item->selected = i;
+
+ ctDraw(co);
+}
+
diff --git a/mdk-stage1/newt/entry.c b/mdk-stage1/newt/entry.c
new file mode 100644
index 000000000..0ee449cf9
--- /dev/null
+++ b/mdk-stage1/newt/entry.c
@@ -0,0 +1,378 @@
+#include <ctype.h>
+#include <slang.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "newt.h"
+#include "newt_pr.h"
+
+struct entry {
+ int flags;
+ char * buf;
+ char ** resultPtr;
+ int bufAlloced;
+ int bufUsed; /* amount of the buffer that's been used */
+ int cursorPosition; /* cursor *in the string* on on screen */
+ int firstChar; /* first character position being shown */
+ newtEntryFilter filter;
+ void * filterData;
+};
+
+static void entryDraw(newtComponent co);
+static void entryDestroy(newtComponent co);
+static struct eventResult entryEvent(newtComponent co,
+ struct event ev);
+
+static struct eventResult entryHandleKey(newtComponent co, int key);
+
+static struct componentOps entryOps = {
+ entryDraw,
+ entryEvent,
+ entryDestroy,
+ newtDefaultPlaceHandler,
+ newtDefaultMappedHandler,
+} ;
+
+void newtEntrySet(newtComponent co, const char * value, int cursorAtEnd) {
+ struct entry * en = co->data;
+
+ if ((strlen(value) + 1) > (unsigned int)en->bufAlloced) {
+ free(en->buf);
+ en->bufAlloced = strlen(value) + 1;
+ en->buf = malloc(en->bufAlloced);
+ if (en->resultPtr) *en->resultPtr = en->buf;
+ }
+ memset(en->buf, 0, en->bufAlloced); /* clear the buffer */
+ strcpy(en->buf, value);
+ en->bufUsed = strlen(value);
+ en->firstChar = 0;
+ if (cursorAtEnd)
+ en->cursorPosition = en->bufUsed;
+ else
+ en->cursorPosition = 0;
+
+ entryDraw(co);
+} ;
+
+newtComponent newtEntry(int left, int top, const char * initialValue, int width,
+ char ** resultPtr, int flags) {
+ newtComponent co;
+ struct entry * en;
+
+ co = malloc(sizeof(*co));
+ en = malloc(sizeof(struct entry));
+ co->data = en;
+
+ co->top = top;
+ co->left = left;
+ co->height = 1;
+ co->width = width;
+ co->isMapped = 0;
+ co->callback = NULL;
+
+ co->ops = &entryOps;
+
+ en->flags = flags;
+ en->cursorPosition = 0;
+ en->firstChar = 0;
+ en->bufUsed = 0;
+ en->bufAlloced = width + 1;
+ en->filter = NULL;
+
+ if (!(en->flags & NEWT_FLAG_DISABLED))
+ co->takesFocus = 1;
+ else
+ co->takesFocus = 0;
+
+ if (initialValue && strlen(initialValue) > (unsigned int)width) {
+ en->bufAlloced = strlen(initialValue) + 1;
+ }
+ en->buf = malloc(en->bufAlloced);
+ en->resultPtr = resultPtr;
+ if (en->resultPtr) *en->resultPtr = en->buf;
+
+ memset(en->buf, 0, en->bufAlloced);
+ if (initialValue) {
+ strcpy(en->buf, initialValue);
+ en->bufUsed = strlen(initialValue);
+ en->cursorPosition = en->bufUsed;
+ } else {
+ *en->buf = '\0';
+ en->bufUsed = 0;
+ en->cursorPosition = 0;
+ }
+
+ return co;
+}
+
+static void entryDraw(newtComponent co) {
+ struct entry * en = co->data;
+ int i;
+ char * chptr;
+ int len;
+
+ if (!co->isMapped) return;
+
+ if (en->flags & NEWT_FLAG_DISABLED)
+ SLsmg_set_color(NEWT_COLORSET_DISENTRY);
+ else
+ SLsmg_set_color(NEWT_COLORSET_ENTRY);
+
+ if (en->flags & NEWT_FLAG_HIDDEN) {
+ newtGotorc(co->top, co->left);
+ for (i = 0; i < co->width; i++)
+ SLsmg_write_char('_');
+ newtGotorc(co->top, co->left);
+
+ return;
+ }
+
+ newtGotorc(co->top, co->left);
+
+ if (en->cursorPosition < en->firstChar) {
+ /* scroll to the left */
+ en->firstChar = en->cursorPosition;
+ } else if ((en->firstChar + co->width) <= en->cursorPosition) {
+ /* scroll to the right */
+ en->firstChar = en->cursorPosition - co->width + 1;
+ }
+
+ chptr = en->buf + en->firstChar;
+
+ if (en->flags & NEWT_FLAG_PASSWORD) {
+ char *tmpptr, *p;
+
+ tmpptr = alloca(strlen(chptr+2));
+ strcpy(tmpptr, chptr);
+ for (p = tmpptr; *p; p++)
+ *p = '*';
+ chptr = tmpptr;
+ }
+
+ len = strlen(chptr);
+
+ if (len <= co->width) {
+ i = len;
+ SLsmg_write_string(chptr);
+ while (i < co->width) {
+ SLsmg_write_char('_');
+ i++;
+ }
+ } else {
+ SLsmg_write_nstring(chptr, co->width);
+ }
+
+ if (en->flags & NEWT_FLAG_HIDDEN)
+ newtGotorc(co->top, co->left);
+ else
+ newtGotorc(co->top, co->left + (en->cursorPosition - en->firstChar));
+}
+
+void newtEntrySetFlags(newtComponent co, int flags, enum newtFlagsSense sense) {
+ struct entry * en = co->data;
+ int row, col;
+
+ en->flags = newtSetFlags(en->flags, flags, sense);
+
+ if (!(en->flags & NEWT_FLAG_DISABLED))
+ co->takesFocus = 1;
+ else
+ co->takesFocus = 0;
+
+ newtGetrc(&row, &col);
+ entryDraw(co);
+ newtGotorc(row, col);
+}
+
+static void entryDestroy(newtComponent co) {
+ struct entry * en = co->data;
+
+ free(en->buf);
+ free(en);
+ free(co);
+}
+
+static struct eventResult entryEvent(newtComponent co,
+ struct event ev) {
+ struct entry * en = co->data;
+ struct eventResult er;
+ int ch;
+ er.result = ER_IGNORED;
+ er.u.focus = NULL;
+
+ if (ev.when == EV_NORMAL) {
+ switch (ev.event) {
+ case EV_FOCUS:
+ newtCursorOn();
+ if (en->flags & NEWT_FLAG_HIDDEN)
+ newtGotorc(co->top, co->left);
+ else
+ newtGotorc(co->top, co->left +
+ (en->cursorPosition - en->firstChar));
+ er.result = ER_SWALLOWED;
+ break;
+
+ case EV_UNFOCUS:
+ newtCursorOff();
+ newtGotorc(0, 0);
+ er.result = ER_SWALLOWED;
+ if (co->callback)
+ co->callback(co, co->callbackData);
+ break;
+
+ case EV_KEYPRESS:
+ ch = ev.u.key;
+ if (en->filter)
+ ch = en->filter(co, en->filterData, ch, en->cursorPosition);
+ if (ch) er = entryHandleKey(co, ch);
+ break;
+
+ case EV_MOUSE:
+ if ((ev.u.mouse.type == MOUSE_BUTTON_DOWN) &&
+ (en->flags ^ NEWT_FLAG_HIDDEN)) {
+ if (strlen(en->buf) >= (size_t) (ev.u.mouse.x - co->left)) {
+ en->cursorPosition = ev.u.mouse.x - co->left;
+ newtGotorc(co->top,
+ co->left +(en->cursorPosition - en->firstChar));
+ } else {
+ en->cursorPosition = strlen(en->buf);
+ newtGotorc(co->top,
+ co->left +(en->cursorPosition - en->firstChar));
+ }
+ }
+ break;
+ }
+ } else
+ er.result = ER_IGNORED;
+
+ return er;
+}
+
+static struct eventResult entryHandleKey(newtComponent co, int key) {
+ struct entry * en = co->data;
+ struct eventResult er;
+ char * chptr, * insPoint;
+
+ er.result = ER_SWALLOWED;
+ switch (key) {
+ case '\r': /* Return */
+ if (en->flags & NEWT_FLAG_RETURNEXIT) {
+ er.result = ER_EXITFORM;
+ } else {
+ er.result = ER_NEXTCOMP;
+ }
+ break;
+
+ case '\001': /* ^A */
+ case NEWT_KEY_HOME:
+ en->cursorPosition = 0;
+ break;
+
+ case '\005': /* ^E */
+ case NEWT_KEY_END:
+ en->cursorPosition = en->bufUsed;
+ break;
+
+ case '\013': /* ^K */
+ en->bufUsed = en->cursorPosition;
+ memset(en->buf + en->bufUsed, 0, en->bufAlloced - en->bufUsed);
+ break;
+
+ case '\002': /* ^B */
+ case NEWT_KEY_LEFT:
+ if (en->cursorPosition)
+ en->cursorPosition--;
+ break;
+
+ case '\004':
+ case NEWT_KEY_DELETE:
+ chptr = en->buf + en->cursorPosition;
+ if (*chptr) {
+ chptr++;
+ while (*chptr) {
+ *(chptr - 1) = *chptr;
+ chptr++;
+ }
+ *(chptr - 1) = '\0';
+ en->bufUsed--;
+ }
+ break;
+
+ case NEWT_KEY_BKSPC:
+ if (en->cursorPosition) {
+ /* if this isn't true, there's nothing to erase */
+ chptr = en->buf + en->cursorPosition;
+ en->bufUsed--;
+ en->cursorPosition--;
+ while (*chptr) {
+ *(chptr - 1) = *chptr;
+ chptr++;
+ }
+ *(chptr - 1) = '\0';
+ }
+ break;
+
+ case '\006': /* ^B */
+ case NEWT_KEY_RIGHT:
+ if (en->cursorPosition < en->bufUsed)
+ en->cursorPosition++;
+ break;
+
+ default:
+ if ((key >= 0x20 && key <= 0x7e) || (key >= 0xa0 && key <= 0xff)) {
+ if (!(en->flags & NEWT_FLAG_SCROLL) && en->bufUsed >= co->width) {
+ SLtt_beep();
+ break;
+ }
+
+ if ((en->bufUsed + 1) == en->bufAlloced) {
+ en->bufAlloced += 20;
+ en->buf = realloc(en->buf, en->bufAlloced);
+ if (en->resultPtr) *en->resultPtr = en->buf;
+ memset(en->buf + en->bufUsed + 1, 0, 20);
+ }
+
+ if (en->cursorPosition == en->bufUsed) {
+ en->bufUsed++;
+ } else {
+ /* insert the new character */
+
+ /* chptr is the last character in the string */
+ chptr = (en->buf + en->bufUsed) - 1;
+ if ((en->bufUsed + 1) == en->bufAlloced) {
+ /* this string fills the buffer, so clip it */
+ chptr--;
+ } else
+ en->bufUsed++;
+
+ insPoint = en->buf + en->cursorPosition;
+
+ while (chptr >= insPoint) {
+ *(chptr + 1) = *chptr;
+ chptr--;
+ }
+
+ }
+
+ en->buf[en->cursorPosition++] = key;
+ } else {
+ er.result = ER_IGNORED;
+ }
+ }
+
+ entryDraw(co);
+
+ return er;
+}
+
+char * newtEntryGetValue(newtComponent co) {
+ struct entry * en = co->data;
+
+ return en->buf;
+}
+
+void newtEntrySetFilter(newtComponent co, newtEntryFilter filter, void * data) {
+ struct entry * en = co->data;
+ en->filter = filter;
+ en->filterData = data;
+}
diff --git a/mdk-stage1/newt/form.c b/mdk-stage1/newt/form.c
new file mode 100644
index 000000000..ad7520e95
--- /dev/null
+++ b/mdk-stage1/newt/form.c
@@ -0,0 +1,713 @@
+#include <unistd.h>
+#include <slang.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+#include <sys/types.h>
+
+#include "newt.h"
+#include "newt_pr.h"
+
+
+/****************************************************************************
+ These forms handle vertical scrolling of components with a height of 1
+
+ Horizontal scrolling won't work, and scrolling large widgets will fail
+ miserably. It shouldn't be too hard to fix either of those if anyone
+ cares to. I only use scrolling for listboxes and text boxes though so
+ I didn't bother.
+*****************************************************************************/
+
+struct element {
+ int top, left; /* Actual, not virtual. These are translated */
+ newtComponent co; /* into actual through vertOffset */
+};
+
+struct fdInfo {
+ int fd;
+ int flags;
+};
+
+struct form {
+ int numCompsAlloced;
+ struct element * elements;
+ int numComps;
+ int currComp;
+ int fixedHeight;
+ int flags;
+ int vertOffset;
+ newtComponent vertBar, exitComp;
+ const char * help;
+ int numRows;
+ int * hotKeys;
+ int numHotKeys;
+ int background;
+ int beenSet;
+ int numFds;
+ struct fdInfo * fds;
+ int maxFd;
+ int timer; /* in milliseconds */
+ struct timeval lastTimeout;
+ void * helpTag;
+ newtCallback helpCb;
+};
+
+static void gotoComponent(struct form * form, int newComp);
+static struct eventResult formEvent(newtComponent co, struct event ev);
+static struct eventResult sendEvent(newtComponent comp, struct event ev);
+static void formPlace(newtComponent co, int left, int top);
+
+/* Global, ick */
+static newtCallback helpCallback;
+
+/* this isn't static as grid.c tests against it to find forms */
+struct componentOps formOps = {
+ newtDrawForm,
+ formEvent,
+ newtFormDestroy,
+ formPlace,
+ newtDefaultMappedHandler,
+} ;
+
+static inline int componentFits(newtComponent co, int compNum) {
+ struct form * form = co->data;
+ struct element * el = form->elements + compNum;
+
+ if ((co->top + form->vertOffset) > el->top) return 0;
+ if ((co->top + form->vertOffset + co->height) <
+ (el->top + el->co->height)) return 0;
+
+ return 1;
+}
+
+newtComponent newtForm(newtComponent vertBar, void * help, int flags) {
+ newtComponent co;
+ struct form * form;
+
+ co = malloc(sizeof(*co));
+ form = malloc(sizeof(*form));
+ co->data = form;
+ co->width = 0;
+ co->height = 0;
+ co->top = -1;
+ co->left = -1;
+ co->isMapped = 0;
+
+ co->takesFocus = 0; /* we may have 0 components */
+ co->ops = &formOps;
+
+ form->help = help;
+ form->flags = flags;
+ form->numCompsAlloced = 5;
+ form->numComps = 0;
+ form->currComp = -1;
+ form->vertOffset = 0;
+ form->fixedHeight = 0;
+ form->numRows = 0;
+ form->numFds = 0;
+ form->maxFd = 0;
+ form->fds = NULL;
+ form->beenSet = 0;
+ form->elements = malloc(sizeof(*(form->elements)) * form->numCompsAlloced);
+
+ form->background = COLORSET_WINDOW;
+ form->hotKeys = malloc(sizeof(int));
+ form->numHotKeys = 0;
+ form->timer = 0;
+ form->lastTimeout.tv_sec = form->lastTimeout.tv_usec = 0;
+ if (!(form->flags & NEWT_FLAG_NOF12)) {
+ newtFormAddHotKey(co, NEWT_KEY_F12);
+ }
+
+ if (vertBar)
+ form->vertBar = vertBar;
+ else
+ form->vertBar = NULL;
+
+ form->helpTag = help;
+ form->helpCb = helpCallback;
+
+ return co;
+}
+
+newtComponent newtFormGetCurrent(newtComponent co) {
+ struct form * form = co->data;
+
+ return form->elements[form->currComp].co;
+}
+
+void newtFormSetCurrent(newtComponent co, newtComponent subco) {
+ struct form * form = co->data;
+ int i, new;
+
+ for (i = 0; i < form->numComps; i++) {
+ if (form->elements[i].co == subco) break;
+ }
+
+ if (form->elements[i].co != subco) return;
+ new = i;
+
+ if (co->isMapped && !componentFits(co, new)) {
+ gotoComponent(form, -1);
+ form->vertOffset = form->elements[new].top - co->top - 1;
+ if (form->vertOffset > (form->numRows - co->height))
+ form->vertOffset = form->numRows - co->height;
+ }
+
+ gotoComponent(form, new);
+}
+
+void newtFormSetTimer(newtComponent co, int millisecs) {
+ struct form * form = co->data;
+
+ form->timer = millisecs;
+ form->lastTimeout.tv_usec = 0;
+ form->lastTimeout.tv_sec = 0;
+}
+
+void newtFormSetHeight(newtComponent co, int height) {
+ struct form * form = co->data;
+
+ form->fixedHeight = 1;
+ co->height = height;
+}
+
+void newtFormSetWidth(newtComponent co, int width) {
+ co->width = width;
+}
+
+void newtFormAddComponent(newtComponent co, newtComponent newco) {
+ struct form * form = co->data;
+
+ co->takesFocus = 1;
+
+ if (form->numCompsAlloced == form->numComps) {
+ form->numCompsAlloced += 5;
+ form->elements = realloc(form->elements,
+ sizeof(*(form->elements)) * form->numCompsAlloced);
+ }
+
+ /* we grab real values for these a bit later */
+ form->elements[form->numComps].left = -2;
+ form->elements[form->numComps].top = -2;
+ form->elements[form->numComps].co = newco;
+
+ if (newco->takesFocus && form->currComp == -1)
+ form->currComp = form->numComps;
+
+ form->numComps++;
+}
+
+void newtFormAddComponents(newtComponent co, ...) {
+ va_list ap;
+ newtComponent subco;
+
+ va_start(ap, co);
+
+ while ((subco = va_arg(ap, newtComponent)))
+ newtFormAddComponent(co, subco);
+
+ va_end(ap);
+}
+
+static void formPlace(newtComponent co, int left, int top) {
+ struct form * form = co->data;
+ int vertDelta, horizDelta;
+ struct element * el;
+ int i;
+
+ newtFormSetSize(co);
+
+ vertDelta = top - co->top;
+ horizDelta = left - co->left;
+ co->top = top;
+ co->left = left;
+
+ for (i = 0, el = form->elements; i < form->numComps; i++, el++) {
+ el->co->top += vertDelta;
+ el->top += vertDelta;
+ el->co->left += horizDelta;
+ el->left += horizDelta;
+ }
+}
+
+void newtDrawForm(newtComponent co) {
+ struct form * form = co->data;
+ struct element * el;
+ int i;
+
+ newtFormSetSize(co);
+
+ SLsmg_set_color(form->background);
+ newtClearBox(co->left, co->top, co->width, co->height);
+ for (i = 0, el = form->elements; i < form->numComps; i++, el++) {
+ /* the scrollbar *always* fits somewhere */
+ if (el->co == form->vertBar) {
+ el->co->ops->mapped(el->co, 1);
+ el->co->ops->draw(el->co);
+ } else {
+ /* only draw it if it'll fit on the screen vertically */
+ if (componentFits(co, i)) {
+ el->co->top = el->top - form->vertOffset;
+ el->co->ops->mapped(el->co, 1);
+ el->co->ops->draw(el->co);
+ } else {
+ el->co->ops->mapped(el->co, 0);
+ }
+ }
+ }
+
+ if (form->vertBar)
+ newtScrollbarSet(form->vertBar, form->vertOffset,
+ form->numRows - co->height);
+}
+
+static struct eventResult formEvent(newtComponent co, struct event ev) {
+ struct form * form = co->data;
+ newtComponent subco = form->elements[form->currComp].co;
+ int new, wrap = 0;
+ struct eventResult er;
+ int dir = 0, page = 0;
+ int i, num, found;
+ struct element * el;
+
+ er.result = ER_IGNORED;
+ if (!form->numComps) return er;
+
+ subco = form->elements[form->currComp].co;
+
+ switch (ev.when) {
+ case EV_EARLY:
+ if (ev.event == EV_KEYPRESS) {
+ if (ev.u.key == NEWT_KEY_TAB) {
+ er.result = ER_SWALLOWED;
+ dir = 1;
+ wrap = 1;
+ } else if (ev.u.key == NEWT_KEY_UNTAB) {
+ er.result = ER_SWALLOWED;
+ dir = -1;
+ wrap = 1;
+ }
+ }
+
+ if (form->numComps) {
+ i = form->currComp;
+ num = 0;
+ while (er.result == ER_IGNORED && num != form->numComps ) {
+ er = form->elements[i].co->ops->event(form->elements[i].co, ev);
+
+ num++;
+ i++;
+ if (i == form->numComps) i = 0;
+ }
+ }
+
+ break;
+
+ case EV_NORMAL:
+ if (ev.event == EV_MOUSE) {
+ found = 0;
+ for (i = 0, el = form->elements; i < form->numComps; i++, el++) {
+ if ((el->co->top <= ev.u.mouse.y) &&
+ (el->co->top + el->co->height > ev.u.mouse.y) &&
+ (el->co->left <= ev.u.mouse.x) &&
+ (el->co->left + el->co->width > ev.u.mouse.x)) {
+ found = 1;
+ if (el->co->takesFocus) {
+ gotoComponent(form, i);
+ subco = form->elements[form->currComp].co;
+ }
+ }
+ /* If we did not find a co to send this event to, we
+ should just swallow the event here. */
+ }
+ if (!found) {
+ er.result = ER_SWALLOWED;
+
+ return er;
+ }
+ }
+ er = subco->ops->event(subco, ev);
+ switch (er.result) {
+ case ER_NEXTCOMP:
+ er.result = ER_SWALLOWED;
+ dir = 1;
+ break;
+
+ case ER_EXITFORM:
+ form->exitComp = subco;
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case EV_LATE:
+ er = subco->ops->event(subco, ev);
+
+ if (er.result == ER_IGNORED) {
+ switch (ev.u.key) {
+ case NEWT_KEY_UP:
+ case NEWT_KEY_LEFT:
+ case NEWT_KEY_BKSPC:
+ er.result = ER_SWALLOWED;
+ dir = -1;
+ break;
+
+ case NEWT_KEY_DOWN:
+ case NEWT_KEY_RIGHT:
+ er.result = ER_SWALLOWED;
+ dir = 1;
+ break;
+
+ case NEWT_KEY_PGUP:
+ er.result = ER_SWALLOWED;
+ dir = -1;
+ page = 1;
+ break;
+
+ case NEWT_KEY_PGDN:
+ er.result = ER_SWALLOWED;
+ dir = 1;
+ page = 1;
+ break;
+ }
+ }
+ }
+
+ if (dir) {
+ new = form->currComp;
+
+ if (page) {
+ new += dir * co->height;
+ if (new < 0)
+ new = 0;
+ else if (new >= form->numComps)
+ new = (form->numComps - 1);
+
+ while (!form->elements[new].co->takesFocus)
+ new = new - dir;
+ } else {
+ do {
+ new += dir;
+
+ if (wrap) {
+ if (new < 0)
+ new = form->numComps - 1;
+ else if (new >= form->numComps)
+ new = 0;
+ } else if (new < 0 || new >= form->numComps)
+ return er;
+ } while (!form->elements[new].co->takesFocus);
+ }
+
+ /* make sure this component is visible */
+ if (!componentFits(co, new)) {
+ gotoComponent(form, -1);
+
+ if (dir < 0) {
+ /* make the new component the first one */
+ form->vertOffset = form->elements[new].top - co->top;
+ } else {
+ /* make the new component the last one */
+ form->vertOffset = (form->elements[new].top +
+ form->elements[new].co->height) -
+ (co->top + co->height);
+ }
+
+ if (form->vertOffset < 0) form->vertOffset = 0;
+ if (form->vertOffset > (form->numRows - co->height))
+ form->vertOffset = form->numRows - co->height;
+
+ newtDrawForm(co);
+ }
+
+ gotoComponent(form, new);
+ er.result = ER_SWALLOWED;
+ }
+
+ return er;
+}
+
+/* this also destroys all of the components on the form */
+void newtFormDestroy(newtComponent co) {
+ newtComponent subco;
+ struct form * form = co->data;
+ int i;
+
+ /* first, destroy all of the components */
+ for (i = 0; i < form->numComps; i++) {
+ subco = form->elements[i].co;
+ if (subco->ops->destroy) {
+ subco->ops->destroy(subco);
+ } else {
+ if (subco->data) free(subco->data);
+ free(subco);
+ }
+ }
+
+ if (form->hotKeys) free(form->hotKeys);
+
+ free(form->elements);
+ free(form);
+ free(co);
+}
+
+newtComponent newtRunForm(newtComponent co) {
+ struct newtExitStruct es;
+
+ newtFormRun(co, &es);
+ if (es.reason == NEWT_EXIT_HOTKEY) {
+ if (es.u.key == NEWT_KEY_F12) {
+ es.reason = NEWT_EXIT_COMPONENT;
+ es.u.co = co;
+ } else {
+ return NULL;
+ }
+ }
+
+ return es.u.co;
+}
+
+void newtFormAddHotKey(newtComponent co, int key) {
+ struct form * form = co->data;
+
+ form->numHotKeys++;
+ form->hotKeys = realloc(form->hotKeys, sizeof(int) * form->numHotKeys);
+ form->hotKeys[form->numHotKeys - 1] = key;
+}
+
+void newtFormSetSize(newtComponent co) {
+ struct form * form = co->data;
+ int delta, i;
+ struct element * el;
+
+ if (form->beenSet) return;
+
+ form->beenSet = 1;
+
+ if (!form->numComps) return;
+
+ co->width = 0;
+ if (!form->fixedHeight) co->height = 0;
+
+ co->top = form->elements[0].co->top;
+ co->left = form->elements[0].co->left;
+ for (i = 0, el = form->elements; i < form->numComps; i++, el++) {
+ if (el->co->ops == &formOps)
+ newtFormSetSize(el->co);
+
+ el->left = el->co->left;
+ el->top = el->co->top;
+
+ if (co->left > el->co->left) {
+ delta = co->left - el->co->left;
+ co->left -= delta;
+ co->width += delta;
+ }
+
+ if (co->top > el->co->top) {
+ delta = co->top - el->co->top;
+ co->top -= delta;
+ if (!form->fixedHeight)
+ co->height += delta;
+ }
+
+ if ((co->left + co->width) < (el->co->left + el->co->width))
+ co->width = (el->co->left + el->co->width) - co->left;
+
+ if (!form->fixedHeight) {
+ if ((co->top + co->height) < (el->co->top + el->co->height))
+ co->height = (el->co->top + el->co->height) - co->top;
+ }
+
+ if ((el->co->top + el->co->height - co->top) > form->numRows) {
+ form->numRows = el->co->top + el->co->height - co->top;
+ }
+ }
+}
+
+void newtFormRun(newtComponent co, struct newtExitStruct * es) {
+ struct form * form = co->data;
+ struct event ev;
+ struct eventResult er;
+ int key, i, max;
+ int done = 0;
+ fd_set readSet, writeSet;
+ struct timeval nextTimeout, now, timeout;
+
+ newtFormSetSize(co);
+ /* draw all of the components */
+ newtDrawForm(co);
+
+ if (form->currComp == -1) {
+ gotoComponent(form, 0);
+ } else
+ gotoComponent(form, form->currComp);
+
+ while (!done) {
+ newtRefresh();
+
+ FD_ZERO(&readSet);
+ FD_ZERO(&writeSet);
+ FD_SET(0, &readSet);
+ max = form->maxFd;
+
+ for (i = 0; i < form->numFds; i++) {
+ if (form->fds[i].flags & NEWT_FD_READ)
+ FD_SET(form->fds[i].fd, &readSet);
+ if (form->fds[i].flags & NEWT_FD_WRITE)
+ FD_SET(form->fds[i].fd, &writeSet);
+ }
+
+ if (form->timer) {
+ /* Calculate when we next need to return with a timeout. Do
+ this inside the loop in case a callback resets the timer. */
+ if (!form->lastTimeout.tv_sec && !form->lastTimeout.tv_usec)
+ gettimeofday(&form->lastTimeout, NULL);
+
+ nextTimeout.tv_sec = form->lastTimeout.tv_sec +
+ (form->timer / 1000);
+ nextTimeout.tv_usec = form->lastTimeout.tv_usec +
+ (form->timer % 1000) * 1000;
+
+ gettimeofday(&now, 0);
+
+ if (now.tv_sec > nextTimeout.tv_sec) {
+ timeout.tv_sec = timeout.tv_usec = 0;
+ } else if (now.tv_sec == nextTimeout.tv_sec) {
+ timeout.tv_sec = 0;
+ if (now.tv_usec > nextTimeout.tv_usec)
+ timeout.tv_usec = 0;
+ else
+ timeout.tv_usec = nextTimeout.tv_usec - now.tv_usec;
+ } else if (now.tv_sec < nextTimeout.tv_sec) {
+ timeout.tv_sec = nextTimeout.tv_sec - now.tv_sec;
+ if (now.tv_usec > nextTimeout.tv_usec)
+ timeout.tv_sec--,
+ timeout.tv_usec = nextTimeout.tv_usec + 1000000 -
+ now.tv_usec;
+ else
+ timeout.tv_usec = nextTimeout.tv_usec - now.tv_usec;
+ }
+ } else {
+ timeout.tv_sec = timeout.tv_usec = 0;
+ }
+
+ i = select(max + 1, &readSet, &writeSet, NULL,
+ form->timer ? &timeout : NULL);
+ if (i < 0) continue; /* ?? What should we do here? */
+
+ if (i == 0) {
+ done = 1;
+ es->reason = NEWT_EXIT_TIMER;
+ gettimeofday(&form->lastTimeout, NULL);
+ } else
+ {
+ if (FD_ISSET(0, &readSet)) {
+
+ key = newtGetKey();
+
+ if (key == NEWT_KEY_RESIZE) {
+ /* newtResizeScreen(1); */
+ continue;
+ }
+
+ for (i = 0; i < form->numHotKeys; i++) {
+ if (form->hotKeys[i] == key) {
+ es->reason = NEWT_EXIT_HOTKEY;
+ es->u.key = key;
+ done = 1;
+ break;
+ }
+ }
+
+ if (key == NEWT_KEY_F1 && form->helpTag && form->helpCb)
+ form->helpCb(co, form->helpTag);
+
+ if (!done) {
+ ev.event = EV_KEYPRESS;
+ ev.u.key = key;
+
+ er = sendEvent(co, ev);
+
+ if (er.result == ER_EXITFORM) {
+ done = 1;
+ es->reason = NEWT_EXIT_COMPONENT;
+ es->u.co = form->exitComp;
+ }
+ }
+ } else {
+ es->reason = NEWT_EXIT_FDREADY;
+ done = 1;
+ }
+ }
+ }
+ newtRefresh();
+}
+
+static struct eventResult sendEvent(newtComponent co, struct event ev) {
+ struct eventResult er;
+
+ ev.when = EV_EARLY;
+ er = co->ops->event(co, ev);
+
+ if (er.result == ER_IGNORED) {
+ ev.when = EV_NORMAL;
+ er = co->ops->event(co, ev);
+ }
+
+ if (er.result == ER_IGNORED) {
+ ev.when = EV_LATE;
+ er = co->ops->event(co, ev);
+ }
+
+ return er;
+}
+
+static void gotoComponent(struct form * form, int newComp) {
+ struct event ev;
+
+ if (form->currComp != -1) {
+ ev.event = EV_UNFOCUS;
+ sendEvent(form->elements[form->currComp].co, ev);
+ }
+
+ form->currComp = newComp;
+
+ if (form->currComp != -1) {
+ ev.event = EV_FOCUS;
+ ev.when = EV_NORMAL;
+ sendEvent(form->elements[form->currComp].co, ev);
+ }
+}
+
+void newtComponentAddCallback(newtComponent co, newtCallback f, void * data) {
+ co->callback = f;
+ co->callbackData = data;
+}
+
+void newtComponentTakesFocus(newtComponent co, int val) {
+ co->takesFocus = val;
+}
+
+void newtFormSetBackground(newtComponent co, int color) {
+ struct form * form = co->data;
+
+ form->background = color;
+}
+
+void newtFormWatchFd(newtComponent co, int fd, int fdFlags) {
+ struct form * form = co->data;
+
+ form->fds = realloc(form->fds, (form->numFds + 1) * sizeof(*form->fds));
+ form->fds[form->numFds].fd = fd;
+ form->fds[form->numFds++].flags = fdFlags;
+ if (form->maxFd < fd) form->maxFd = fd;
+}
+
+void newtSetHelpCallback(newtCallback cb) {
+ helpCallback = cb;
+}
diff --git a/mdk-stage1/newt/grid.c b/mdk-stage1/newt/grid.c
new file mode 100644
index 000000000..37d2b2e74
--- /dev/null
+++ b/mdk-stage1/newt/grid.c
@@ -0,0 +1,389 @@
+#include <alloca.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "newt.h"
+#include "newt_pr.h"
+
+struct gridField {
+ enum newtGridElement type;
+ union {
+ newtGrid grid;
+ newtComponent co;
+ } u;
+ int padLeft, padTop, padRight, padBottom;
+ int anchor;
+ int flags;
+};
+
+struct grid_s {
+ int rows, cols;
+ int width, height; /* totals, -1 means unknown */
+ struct gridField ** fields;
+};
+
+/* this is a bit of a hack */
+extern struct componentOps formOps[];
+
+newtGrid newtCreateGrid(int cols, int rows) {
+ newtGrid grid;
+
+ grid = malloc(sizeof(*grid));
+ grid->rows = rows;
+ grid->cols = cols;
+
+ grid->fields = malloc(sizeof(*grid->fields) * cols);
+ while (cols--) {
+ grid->fields[cols] = malloc(sizeof(**(grid->fields)) * rows);
+ memset(grid->fields[cols], 0, sizeof(**(grid->fields)) * rows);
+ }
+
+ grid->width = grid->height = -1;
+
+ return grid;
+}
+
+void newtGridSetField(newtGrid grid, int col, int row,
+ enum newtGridElement type, void * val, int padLeft,
+ int padTop, int padRight, int padBottom, int anchor,
+ int flags) {
+ struct gridField * field = &grid->fields[col][row];
+
+ if (field->type == NEWT_GRID_SUBGRID)
+ newtGridFree(field->u.grid, 1);
+
+ field->type = type;
+ field->u.co = (void *) val;
+
+ field->padLeft = padLeft;
+ field->padRight = padRight;
+ field->padTop = padTop;
+ field->padBottom = padBottom;
+ field->anchor = anchor;
+ field->flags = flags;
+
+ grid->width = grid->height = -1;
+}
+
+static void distSpace(int extra, int items, int * list) {
+ int all, some, i;
+
+ all = extra / items;
+ some = extra % items;
+ for (i = 0; i < items; i++) {
+ list[i] += all;
+ if (some) {
+ list[i]++;
+ some--;
+ }
+ }
+}
+
+static void shuffleGrid(newtGrid grid, int left, int top, int set) {
+ struct gridField * field;
+ int row, col;
+ int i, j;
+ int minWidth, minHeight;
+ int * widths, * heights;
+ int thisLeft, thisTop;
+ int x, y, remx, remy;
+
+ widths = alloca(sizeof(*widths) * grid->cols);
+ memset(widths, 0, sizeof(*widths) * grid->cols);
+ heights = alloca(sizeof(*heights) * grid->rows);
+ memset(heights, 0, sizeof(*heights) * grid->rows);
+
+ minWidth = 0;
+ for (row = 0; row < grid->rows; row++) {
+ i = 0;
+ for (col = 0; col < grid->cols; col++) {
+ field = &grid->fields[col][row];
+ if (field->type == NEWT_GRID_SUBGRID) {
+ /* we'll have to redo this later */
+ if (field->u.grid->width == -1)
+ shuffleGrid(field->u.grid, left, top, 0);
+ j = field->u.grid->width;
+ } else if (field->type == NEWT_GRID_COMPONENT) {
+ if (field->u.co->ops == formOps)
+ newtFormSetSize(field->u.co);
+ j = field->u.co->width;
+ } else
+ j = 0;
+
+ j += field->padLeft + field->padRight;
+
+ if (j > widths[col]) widths[col] = j;
+ i += widths[col];
+ }
+
+ if (i > minWidth) minWidth = i;
+ }
+
+ minHeight = 0;
+ for (col = 0; col < grid->cols; col++) {
+ i = 0;
+ for (row = 0; row < grid->rows; row++) {
+ field = &grid->fields[col][row];
+ if (field->type == NEWT_GRID_SUBGRID) {
+ /* we'll have to redo this later */
+ if (field->u.grid->height == -1)
+ shuffleGrid(field->u.grid, 0, 0, 0);
+ j = field->u.grid->height;
+ } else if (field->type == NEWT_GRID_COMPONENT){
+ j = field->u.co->height;
+ } else
+ j = 0;
+
+ j += field->padTop + field->padBottom;
+
+ if (j > heights[row]) heights[row] = j;
+ i += heights[row];
+ }
+
+ if (i > minHeight) minHeight = i;
+ }
+
+ /* this catches the -1 case */
+ if (grid->width < minWidth) grid->width = minWidth; /* ack! */
+ if (grid->height < minHeight) grid->height = minHeight; /* ditto! */
+
+ if (!set) return;
+
+ distSpace(grid->width - minWidth, grid->cols, widths);
+ distSpace(grid->height - minHeight, grid->rows, heights);
+
+ thisTop = top;
+ for (row = 0; row < grid->rows; row++) {
+ i = 0;
+ thisLeft = left;
+ for (col = 0; col < grid->cols; col++) {
+ field = &grid->fields[col][row];
+
+ if (field->type == NEWT_GRID_EMPTY) continue;
+
+ x = thisLeft + field->padLeft;
+ remx = widths[col] - field->padLeft - field->padRight;
+ y = thisTop + field->padTop;
+ remy = heights[row] - field->padTop - field->padBottom;
+
+ if (field->type == NEWT_GRID_SUBGRID) {
+ remx -= field->u.grid->width;
+ remy -= field->u.grid->height;
+ } else if (field->type == NEWT_GRID_COMPONENT) {
+ remx -= field->u.co->width;
+ remy -= field->u.co->height;
+ }
+
+ if (!(field->flags & NEWT_GRID_FLAG_GROWX)) {
+ if (field->anchor & NEWT_ANCHOR_RIGHT)
+ x += remx;
+ else if (!(field->anchor & NEWT_ANCHOR_LEFT))
+ x += (remx / 2);
+ }
+
+ if (!(field->flags & NEWT_GRID_FLAG_GROWY)) {
+ if (field->anchor & NEWT_ANCHOR_BOTTOM)
+ y += remx;
+ else if (!(field->anchor & NEWT_ANCHOR_TOP))
+ y += (remy / 2);
+ }
+
+ if (field->type == NEWT_GRID_SUBGRID) {
+ if (field->flags & NEWT_GRID_FLAG_GROWX)
+ field->u.grid->width = widths[col] - field->padLeft
+ - field->padRight;
+ if (field->flags & NEWT_GRID_FLAG_GROWY)
+ field->u.grid->height = heights[col] - field->padTop
+ - field->padBottom;
+
+ shuffleGrid(field->u.grid, x, y, 1);
+ } else if (field->type == NEWT_GRID_COMPONENT) {
+ field->u.co->ops->place(field->u.co, x, y);
+ }
+
+ thisLeft += widths[col];
+ }
+
+ thisTop += heights[row];
+ }
+}
+
+void newtGridPlace(newtGrid grid, int left, int top) {
+ shuffleGrid(grid, left, top, 1);
+}
+
+void newtGridFree(newtGrid grid, int recurse) {
+ int row, col;
+
+ for (col = 0; col < grid->cols; col++) {
+ if (recurse) {
+ for (row = 0; row < grid->rows; row++) {
+ if (grid->fields[col][row].type == NEWT_GRID_SUBGRID)
+ newtGridFree(grid->fields[col][row].u.grid, 1);
+ }
+ }
+
+ free(grid->fields[col]);
+ }
+
+ free(grid->fields);
+ free(grid);
+}
+
+void newtGridGetSize(newtGrid grid, int * width, int * height) {
+ if (grid->width == -1 || grid->height == -1) {
+ grid->width = grid->height = -1;
+ shuffleGrid(grid, 0, 0, 1);
+ }
+
+ *width = grid->width;
+ *height = grid->height;
+}
+
+void newtGridWrappedWindow(newtGrid grid, char * title) {
+ int width, height, offset = 0;
+
+ newtGridGetSize(grid, &width, &height);
+ if ((size_t)width < strlen(title) + 2) {
+ offset = ((strlen(title) + 2) - width) / 2;
+ width = strlen(title) + 2;
+ }
+ newtCenteredWindow(width + 2, height + 2, title);
+ newtGridPlace(grid, 1 + offset, 1);
+}
+
+void newtGridWrappedWindowAt(newtGrid grid, char * title, int left, int top) {
+ int width, height;
+
+ newtGridGetSize(grid, &width, &height);
+ newtOpenWindow(left, top, width + 2, height + 2, title);
+ newtGridPlace(grid, 1, 1);
+}
+
+void newtGridAddComponentsToForm(newtGrid grid, newtComponent form,
+ int recurse) {
+ int row, col;
+
+ for (col = 0; col < grid->cols; col++) {
+ for (row = 0; row < grid->rows; row++) {
+ if (grid->fields[col][row].type == NEWT_GRID_SUBGRID && recurse)
+ newtGridAddComponentsToForm(grid->fields[col][row].u.grid,
+ form, 1);
+ else if (grid->fields[col][row].type == NEWT_GRID_COMPONENT)
+ newtFormAddComponent(form, grid->fields[col][row].u.co);
+ }
+ }
+}
+
+/* this handles up to 50 items */
+static newtGrid stackem(int isVert, enum newtGridElement type1, void * what1,
+ va_list args, int close) {
+ struct item {
+ enum newtGridElement type;
+ void * what;
+ } items[50];
+ int i, num;
+ newtGrid grid;
+
+ items[0].type = type1, items[0].what = what1, num = 1;
+ while (1) {
+ items[num].type = va_arg(args, enum newtGridElement);
+ if (items[num].type == NEWT_GRID_EMPTY) break;
+
+ items[num].what = va_arg(args, void *);
+ num++;
+ }
+
+ grid = newtCreateGrid(isVert ? 1 : num, isVert ? num : 1);
+
+ for (i = 0; i < num; i++) {
+ newtGridSetField(grid, isVert ? 0 : i, isVert ? i : 0,
+ items[i].type, items[i].what,
+ close ? 0 : (i ? (isVert ? 0 : 1) : 0),
+ close ? 0 : (i ? (isVert ? 1 : 0) : 0), 0, 0, 0, 0);
+ }
+
+ return grid;
+}
+
+newtGrid newtGridHCloseStacked(enum newtGridElement type1, void * what1, ...) {
+ va_list args;
+ newtGrid grid;
+
+ va_start(args, what1);
+
+ grid = stackem(0, type1, what1, args, 1);
+
+ va_start(args, what1);
+
+ return grid;
+}
+
+newtGrid newtGridVCloseStacked(enum newtGridElement type1, void * what1, ...) {
+ va_list args;
+ newtGrid grid;
+
+ va_start(args, what1);
+
+ grid = stackem(1, type1, what1, args, 1);
+
+ va_start(args, what1);
+
+ return grid;
+}
+
+newtGrid newtGridVStacked(enum newtGridElement type1, void * what1, ...) {
+ va_list args;
+ newtGrid grid;
+
+ va_start(args, what1);
+
+ grid = stackem(1, type1, what1, args, 0);
+
+ va_start(args, what1);
+
+ return grid;
+}
+
+newtGrid newtGridHStacked(enum newtGridElement type1, void * what1, ...) {
+ va_list args;
+ newtGrid grid;
+
+ va_start(args, what1);
+
+ grid = stackem(0, type1, what1, args, 0);
+
+ va_start(args, what1);
+
+ return grid;
+}
+
+newtGrid newtGridBasicWindow(newtComponent text, newtGrid middle,
+ newtGrid buttons) {
+ newtGrid grid;
+
+ grid = newtCreateGrid(1, 3);
+ newtGridSetField(grid, 0, 0, NEWT_GRID_COMPONENT, text,
+ 0, 0, 0, 0, NEWT_ANCHOR_LEFT, 0);
+ newtGridSetField(grid, 0, 1, NEWT_GRID_SUBGRID, middle,
+ 0, 1, 0, 0, 0, 0);
+ newtGridSetField(grid, 0, 2, NEWT_GRID_SUBGRID, buttons,
+ 0, 1, 0, 0, 0, NEWT_GRID_FLAG_GROWX);
+
+ return grid;
+}
+
+newtGrid newtGridSimpleWindow(newtComponent text, newtComponent middle,
+ newtGrid buttons) {
+ newtGrid grid;
+
+ grid = newtCreateGrid(1, 3);
+ newtGridSetField(grid, 0, 0, NEWT_GRID_COMPONENT, text,
+ 0, 0, 0, 0, NEWT_ANCHOR_LEFT, 0);
+ newtGridSetField(grid, 0, 1, NEWT_GRID_COMPONENT, middle,
+ 0, 1, 0, 0, 0, 0);
+ newtGridSetField(grid, 0, 2, NEWT_GRID_SUBGRID, buttons,
+ 0, 1, 0, 0, 0, NEWT_GRID_FLAG_GROWX);
+
+ return grid;
+}
diff --git a/mdk-stage1/newt/label.c b/mdk-stage1/newt/label.c
new file mode 100644
index 000000000..f1a9cebbf
--- /dev/null
+++ b/mdk-stage1/newt/label.c
@@ -0,0 +1,81 @@
+#include <slang.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "newt.h"
+#include "newt_pr.h"
+
+struct label {
+ char * text;
+ int length;
+};
+
+static void labelDraw(newtComponent co);
+static void labelDestroy(newtComponent co);
+
+static struct componentOps labelOps = {
+ labelDraw,
+ newtDefaultEventHandler,
+ labelDestroy,
+ newtDefaultPlaceHandler,
+ newtDefaultMappedHandler,
+} ;
+
+newtComponent newtLabel(int left, int top, const char * text) {
+ newtComponent co;
+ struct label * la;
+
+ co = malloc(sizeof(*co));
+ la = malloc(sizeof(struct label));
+ co->data = la;
+
+ co->ops = &labelOps;
+
+ co->height = 1;
+ co->width = strlen(text);
+ co->top = top;
+ co->left = left;
+ co->takesFocus = 0;
+
+ la->length = strlen(text);
+ la->text = strdup(text);
+
+ return co;
+}
+
+void newtLabelSetText(newtComponent co, const char * text) {
+ int newLength;
+ struct label * la = co->data;
+
+ newLength = strlen(text);
+ if (newLength <= la->length) {
+ memset(la->text, ' ', la->length);
+ memcpy(la->text, text, newLength);
+ } else {
+ free(la->text);
+ la->text = strdup(text);
+ la->length = newLength;
+ co->width = newLength;
+ }
+
+ labelDraw(co);
+}
+
+static void labelDraw(newtComponent co) {
+ struct label * la = co->data;
+
+ if (co->isMapped == -1) return;
+
+ SLsmg_set_color(COLORSET_LABEL);
+
+ newtGotorc(co->top, co->left);
+ SLsmg_write_string(la->text);
+}
+
+static void labelDestroy(newtComponent co) {
+ struct label * la = co->data;
+
+ free(la->text);
+ free(la);
+ free(co);
+}
diff --git a/mdk-stage1/newt/listbox.c b/mdk-stage1/newt/listbox.c
new file mode 100644
index 000000000..cdbf792ca
--- /dev/null
+++ b/mdk-stage1/newt/listbox.c
@@ -0,0 +1,752 @@
+/* This goofed-up box whacked into shape by Elliot Lee <sopwith@cuc.edu>
+ (from the original listbox by Erik Troan <ewt@redhat.com>)
+ and contributed to newt for use under the LGPL license.
+ Copyright (C) 1996, 1997 Elliot Lee */
+
+#include <slang.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "newt.h"
+#include "newt_pr.h"
+
+
+/* Linked list of items in the listbox */
+struct items {
+ char * text;
+ const void *data;
+ unsigned char isSelected;
+ struct items *next;
+};
+
+/* Holds all the relevant information for this listbox */
+struct listbox {
+ newtComponent sb; /* Scrollbar on right side of listbox */
+ int curWidth; /* size of text w/o scrollbar or border*/
+ int curHeight; /* size of text w/o border */
+ int sbAdjust;
+ int bdxAdjust, bdyAdjust;
+ int numItems, numSelected;
+ int userHasSetWidth;
+ int currItem, startShowItem; /* startShowItem is the first item displayed
+ on the screen */
+ int isActive; /* If we handle key events all the time, it seems
+ to do things even when they are supposed to be for
+ another button/whatever */
+ struct items *boxItems;
+ int grow;
+ int flags; /* flags for this listbox, right now just
+ NEWT_FLAG_RETURNEXIT */
+};
+
+static void listboxDraw(newtComponent co);
+static void listboxDestroy(newtComponent co);
+static struct eventResult listboxEvent(newtComponent co, struct event ev);
+static void newtListboxRealSetCurrent(newtComponent co);
+static void listboxPlace(newtComponent co, int newLeft, int newTop);
+static inline void updateWidth(newtComponent co, struct listbox * li,
+ int maxField);
+static void listboxMapped(newtComponent co, int isMapped);
+
+static struct componentOps listboxOps = {
+ listboxDraw,
+ listboxEvent,
+ listboxDestroy,
+ listboxPlace,
+ listboxMapped,
+};
+
+static void listboxMapped(newtComponent co, int isMapped) {
+ struct listbox * li = co->data;
+
+ co->isMapped = isMapped;
+ if (li->sb)
+ li->sb->ops->mapped(li->sb, isMapped);
+}
+
+static void listboxPlace(newtComponent co, int newLeft, int newTop) {
+ struct listbox * li = co->data;
+
+ co->top = newTop;
+ co->left = newLeft;
+
+ if (li->sb)
+ li->sb->ops->place(li->sb, co->left + co->width - li->bdxAdjust - 1,
+ co->top);
+}
+
+newtComponent newtListbox(int left, int top, int height, int flags) {
+ newtComponent co, sb;
+ struct listbox * li;
+
+ if (!(co = malloc(sizeof(*co))))
+ return NULL;
+
+ if (!(li = malloc(sizeof(struct listbox)))) {
+ free(co);
+ return NULL;
+ }
+
+ li->boxItems = NULL;
+ li->numItems = 0;
+ li->currItem = 0;
+ li->numSelected = 0;
+ li->isActive = 0;
+ li->userHasSetWidth = 0;
+ li->startShowItem = 0;
+ li->sbAdjust = 0;
+ li->bdxAdjust = 0;
+ li->bdyAdjust = 0;
+ li->flags = flags & (NEWT_FLAG_RETURNEXIT | NEWT_FLAG_BORDER |
+ NEWT_FLAG_MULTIPLE);
+
+ if (li->flags & NEWT_FLAG_BORDER) {
+ li->bdxAdjust = 2;
+ li->bdyAdjust = 1;
+ }
+
+ co->height = height;
+ li->curHeight = co->height - (2 * li->bdyAdjust);
+
+ if (height) {
+ li->grow = 0;
+ if (flags & NEWT_FLAG_SCROLL) {
+ sb = newtVerticalScrollbar(left, top + li->bdyAdjust,
+ li->curHeight,
+ COLORSET_LISTBOX, COLORSET_ACTLISTBOX);
+ li->sbAdjust = 3;
+ } else {
+ sb = NULL;
+ }
+ } else {
+ li->grow = 1;
+ sb = NULL;
+ }
+
+ li->sb = sb;
+ co->data = li;
+ co->isMapped = 0;
+ co->left = left;
+ co->top = top;
+ co->ops = &listboxOps;
+ co->takesFocus = 1;
+ co->callback = NULL;
+
+ updateWidth(co, li, 5);
+
+ return co;
+}
+
+static inline void updateWidth(newtComponent co, struct listbox * li,
+ int maxField) {
+ li->curWidth = maxField;
+ co->width = li->curWidth + li->sbAdjust + 2 * li->bdxAdjust;
+
+ if (li->sb)
+ li->sb->left = co->left + co->width - li->bdxAdjust - 1;
+}
+
+void newtListboxSetCurrentByKey(newtComponent co, void * key) {
+ struct listbox * li = co->data;
+ struct items * item;
+ int i;
+
+ item = li->boxItems, i = 0;
+ while (item && item->data != key)
+ item = item->next, i++;
+
+ if (item)
+ newtListboxSetCurrent(co, i);
+}
+
+void newtListboxSetCurrent(newtComponent co, int num)
+{
+ struct listbox * li = co->data;
+
+ if (num >= li->numItems)
+ li->currItem = li->numItems - 1;
+ else if (num < 0)
+ li->currItem = 0;
+ else
+ li->currItem = num;
+
+ if (li->currItem < li->startShowItem)
+ li->startShowItem = li->currItem;
+ else if (li->currItem - li->startShowItem > li->curHeight - 1)
+ li->startShowItem = li->currItem - li->curHeight + 1;
+ if (li->startShowItem + li->curHeight > li->numItems)
+ li->startShowItem = li->numItems - li->curHeight;
+ if(li->startShowItem < 0)
+ li->startShowItem = 0;
+
+ newtListboxRealSetCurrent(co);
+}
+
+static void newtListboxRealSetCurrent(newtComponent co)
+{
+ struct listbox * li = co->data;
+
+ if(li->sb)
+ newtScrollbarSet(li->sb, li->currItem + 1, li->numItems);
+ listboxDraw(co);
+ if(co->callback) co->callback(co, co->callbackData);
+}
+
+void newtListboxSetWidth(newtComponent co, int width) {
+ struct listbox * li = co->data;
+
+ co->width = width;
+ li->curWidth = co->width - li->sbAdjust - 2 * li->bdxAdjust;
+ li->userHasSetWidth = 1;
+ if (li->sb) li->sb->left = co->width + co->left - 1;
+ listboxDraw(co);
+}
+
+void * newtListboxGetCurrent(newtComponent co) {
+ struct listbox * li = co->data;
+ int i;
+ struct items *item;
+
+ for(i = 0, item = li->boxItems; item != NULL && i < li->currItem;
+ i++, item = item->next);
+
+ if (item)
+ return (void *)item->data;
+ else
+ return NULL;
+}
+
+void newtListboxSelectItem(newtComponent co, const void * key,
+ enum newtFlagsSense sense)
+{
+ struct listbox * li = co->data;
+ int i;
+ struct items * item;
+
+ item = li->boxItems, i = 0;
+ while (item && item->data != key)
+ item = item->next, i++;
+
+ if (!item) return;
+
+ if (item->isSelected)
+ li->numSelected--;
+
+ switch(sense) {
+ case NEWT_FLAGS_RESET:
+ item->isSelected = 0; break;
+ case NEWT_FLAGS_SET:
+ item->isSelected = 1; break;
+ case NEWT_FLAGS_TOGGLE:
+ item->isSelected = !item->isSelected;
+ }
+
+ if (item->isSelected)
+ li->numSelected++;
+
+ listboxDraw(co);
+}
+
+void newtListboxClearSelection(newtComponent co)
+{
+ struct items *item;
+ struct listbox * li = co->data;
+
+ for(item = li->boxItems; item != NULL;
+ item = item->next)
+ item->isSelected = 0;
+ li->numSelected = 0;
+ listboxDraw(co);
+}
+
+/* Free the returned array after use, but NOT the values in the array */
+void ** newtListboxGetSelection(newtComponent co, int *numitems)
+{
+ struct listbox * li;
+ int i;
+ void **retval;
+ struct items *item;
+
+ if(!co || !numitems) return NULL;
+
+ li = co->data;
+ if(!li || !li->numSelected) return NULL;
+
+ retval = malloc(li->numSelected * sizeof(void *));
+ for(i = 0, item = li->boxItems; item != NULL;
+ item = item->next)
+ if(item->isSelected)
+ retval[i++] = (void *)item->data;
+ *numitems = li->numSelected;
+ return retval;
+}
+
+void newtListboxSetEntry(newtComponent co, int num, const char * text) {
+ struct listbox * li = co->data;
+ int i;
+ struct items *item;
+
+ for(i = 0, item = li->boxItems; item != NULL && i < num;
+ i++, item = item->next);
+
+ if(!item)
+ return;
+ else {
+ free(item->text);
+ item->text = strdup(text);
+ }
+ if (li->userHasSetWidth == 0 && strlen(text) > (size_t)li->curWidth) {
+ updateWidth(co, li, strlen(text));
+ }
+
+ if (num >= li->startShowItem && num <= li->startShowItem + co->height)
+ listboxDraw(co);
+}
+
+void newtListboxSetData(newtComponent co, int num, void * data) {
+ struct listbox * li = co->data;
+ int i;
+ struct items *item;
+
+ for(i = 0, item = li->boxItems; item != NULL && i < num;
+ i++, item = item->next);
+
+ item->data = data;
+}
+
+int newtListboxAppendEntry(newtComponent co, const char * text,
+ const void * data) {
+ struct listbox * li = co->data;
+ struct items *item;
+
+ if(li->boxItems) {
+ for (item = li->boxItems; item->next != NULL; item = item->next);
+
+ item = item->next = malloc(sizeof(struct items));
+ } else {
+ item = li->boxItems = malloc(sizeof(struct items));
+ }
+
+ if (!li->userHasSetWidth && text && (strlen(text) > (size_t)li->curWidth))
+ updateWidth(co, li, strlen(text));
+
+ item->text = strdup(text); item->data = data; item->next = NULL;
+ item->isSelected = 0;
+
+ if (li->grow)
+ co->height++, li->curHeight++;
+ li->numItems++;
+
+ return 0;
+}
+
+int newtListboxInsertEntry(newtComponent co, const char * text,
+ const void * data, void * key) {
+ struct listbox * li = co->data;
+ struct items *item, *t;
+
+ if (li->boxItems) {
+ if (key) {
+ item = li->boxItems;
+ while (item && item->data != key) item = item->next;
+
+ if (!item) return 1;
+
+ t = item->next;
+ item = item->next = malloc(sizeof(struct items));
+ item->next = t;
+ } else {
+ t = li->boxItems;
+ item = li->boxItems = malloc(sizeof(struct items));
+ item->next = t;
+ }
+ } else if (key) {
+ return 1;
+ } else {
+ item = li->boxItems = malloc(sizeof(struct items));
+ item->next = NULL;
+ }
+
+ if (!li->userHasSetWidth && text && (strlen(text) > (size_t)li->curWidth))
+ updateWidth(co, li, strlen(text));
+
+ item->text = strdup(text?text:"(null)"); item->data = data;
+ item->isSelected = 0;
+
+ if (li->sb)
+ li->sb->left = co->left + co->width - li->bdxAdjust - 1;
+ li->numItems++;
+
+ listboxDraw(co);
+
+ return 0;
+}
+
+int newtListboxDeleteEntry(newtComponent co, void * key) {
+ struct listbox * li = co->data;
+ int widest = 0, t;
+ struct items *item, *item2 = NULL;
+ int num;
+
+ if (li->boxItems == NULL || li->numItems <= 0)
+ return 0;
+
+ num = 0;
+
+ item2 = NULL, item = li->boxItems;
+ while (item && item->data != key) {
+ item2 = item;
+ item = item->next;
+ num++;
+ }
+
+ if (!item)
+ return -1;
+
+ if (item2)
+ item2->next = item->next;
+ else
+ li->boxItems = item->next;
+
+ free(item->text);
+ free(item);
+ li->numItems--;
+
+ if (!li->userHasSetWidth) {
+ widest = 0;
+ for (item = li->boxItems; item != NULL; item = item->next)
+ if ((t = strlen(item->text)) > widest) widest = t;
+ }
+
+ if (li->currItem >= num)
+ li->currItem--;
+
+ if (!li->userHasSetWidth) {
+ updateWidth(co, li, widest);
+ }
+
+ listboxDraw(co);
+
+ return 0;
+}
+
+void newtListboxClear(newtComponent co)
+{
+ struct listbox * li;
+ struct items *anitem, *nextitem;
+ if(co == NULL || (li = co->data) == NULL)
+ return;
+ for(anitem = li->boxItems; anitem != NULL; anitem = nextitem) {
+ nextitem = anitem->next;
+ free(anitem->text);
+ free(anitem);
+ }
+ li->numItems = li->numSelected = li->currItem = li->startShowItem = 0;
+ li->boxItems = NULL;
+ if (!li->userHasSetWidth)
+ updateWidth(co, li, 5);
+}
+
+/* If you don't want to get back the text, pass in NULL for the ptr-ptr. Same
+ goes for the data. */
+void newtListboxGetEntry(newtComponent co, int num, char **text, void **data) {
+ struct listbox * li = co->data;
+ int i;
+ struct items *item;
+
+ if (!li->boxItems || num >= li->numItems) {
+ if(text)
+ *text = NULL;
+ if(data)
+ *data = NULL;
+ return;
+ }
+
+ i = 0;
+ item = li->boxItems;
+ while (item && i < num) {
+ i++, item = item->next;
+ }
+
+ if (item) {
+ if (text)
+ *text = item->text;
+ if (data)
+ *data = (void *)item->data;
+ }
+}
+
+static void listboxDraw(newtComponent co)
+{
+ struct listbox * li = co->data;
+ struct items *item;
+ int i, j;
+
+ if (!co->isMapped) return ;
+
+ if(li->flags & NEWT_FLAG_BORDER) {
+ if(li->isActive)
+ SLsmg_set_color(NEWT_COLORSET_ACTLISTBOX);
+ else
+ SLsmg_set_color(NEWT_COLORSET_LISTBOX);
+
+ newtDrawBox(co->left, co->top, co->width, co->height, 0);
+ }
+
+ if(li->sb)
+ li->sb->ops->draw(li->sb);
+
+ SLsmg_set_color(NEWT_COLORSET_LISTBOX);
+
+ for(i = 0, item = li->boxItems; item != NULL && i < li->startShowItem;
+ i++, item = item->next);
+
+ j = i;
+
+ for (i = 0; item != NULL && i < li->curHeight; i++, item = item->next) {
+ if (!item->text) continue;
+
+ newtGotorc(co->top + i + li->bdyAdjust, co->left + li->bdxAdjust);
+ if(j + i == li->currItem) {
+ if(item->isSelected)
+ SLsmg_set_color(NEWT_COLORSET_ACTSELLISTBOX);
+ else
+ SLsmg_set_color(NEWT_COLORSET_ACTLISTBOX);
+ } else if(item->isSelected)
+ SLsmg_set_color(NEWT_COLORSET_SELLISTBOX);
+ else
+ SLsmg_set_color(NEWT_COLORSET_LISTBOX);
+
+ SLsmg_write_nstring(item->text, li->curWidth);
+
+ }
+ newtGotorc(co->top + (li->currItem - li->startShowItem), co->left);
+}
+
+static struct eventResult listboxEvent(newtComponent co, struct event ev) {
+ struct eventResult er;
+ struct listbox * li = co->data;
+ struct items *item;
+ int i;
+
+ er.result = ER_IGNORED;
+
+ if(ev.when == EV_EARLY || ev.when == EV_LATE) {
+ return er;
+ }
+
+ switch(ev.event) {
+ case EV_KEYPRESS:
+ if (!li->isActive) break;
+
+ switch(ev.u.key) {
+ case ' ':
+ if(!(li->flags & NEWT_FLAG_MULTIPLE)) break;
+ newtListboxSelectItem(co, li->boxItems[li->currItem].data,
+ NEWT_FLAGS_TOGGLE);
+ er.result = ER_SWALLOWED;
+ /* We don't break here, because it is cool to be able to
+ hold space to select a bunch of items in a list at once */
+
+ case NEWT_KEY_DOWN:
+ if(li->numItems <= 0) break;
+ if(li->currItem < li->numItems - 1) {
+ li->currItem++;
+ if(li->currItem > (li->startShowItem + li->curHeight - 1)) {
+ li->startShowItem = li->currItem - li->curHeight + 1;
+ if(li->startShowItem + li->curHeight > li->numItems)
+ li->startShowItem = li->numItems - li->curHeight;
+ }
+ if(li->sb)
+ newtScrollbarSet(li->sb, li->currItem + 1, li->numItems);
+ listboxDraw(co);
+ }
+ if(co->callback) co->callback(co, co->callbackData);
+ er.result = ER_SWALLOWED;
+ break;
+
+ case NEWT_KEY_ENTER:
+ if(li->numItems <= 0) break;
+ if(li->flags & NEWT_FLAG_RETURNEXIT)
+ er.result = ER_EXITFORM;
+ break;
+
+ case NEWT_KEY_UP:
+ if(li->numItems <= 0) break;
+ if(li->currItem > 0) {
+ li->currItem--;
+ if(li->currItem < li->startShowItem)
+ li->startShowItem = li->currItem;
+ if(li->sb)
+ newtScrollbarSet(li->sb, li->currItem + 1, li->numItems);
+ listboxDraw(co);
+ }
+ if(co->callback) co->callback(co, co->callbackData);
+ er.result = ER_SWALLOWED;
+ break;
+
+ case NEWT_KEY_PGUP:
+ if(li->numItems <= 0) break;
+ li->startShowItem -= li->curHeight - 1;
+ if(li->startShowItem < 0)
+ li->startShowItem = 0;
+ li->currItem -= li->curHeight - 1;
+ if(li->currItem < 0)
+ li->currItem = 0;
+ newtListboxRealSetCurrent(co);
+ er.result = ER_SWALLOWED;
+ break;
+
+ case NEWT_KEY_PGDN:
+ if(li->numItems <= 0) break;
+ li->startShowItem += li->curHeight;
+ if(li->startShowItem > (li->numItems - li->curHeight)) {
+ li->startShowItem = li->numItems - li->curHeight;
+ }
+ li->currItem += li->curHeight;
+ if(li->currItem >= li->numItems) {
+ li->currItem = li->numItems - 1;
+ }
+ newtListboxRealSetCurrent(co);
+ er.result = ER_SWALLOWED;
+ break;
+
+ case NEWT_KEY_HOME:
+ if(li->numItems <= 0) break;
+ newtListboxSetCurrent(co, 0);
+ er.result = ER_SWALLOWED;
+ break;
+
+ case NEWT_KEY_END:
+ if(li->numItems <= 0) break;
+ li->startShowItem = li->numItems - li->curHeight;
+ if(li->startShowItem < 0)
+ li->startShowItem = 0;
+ li->currItem = li->numItems - 1;
+ newtListboxRealSetCurrent(co);
+ er.result = ER_SWALLOWED;
+ break;
+ default:
+ if (li->numItems <= 0) break;
+ if (ev.u.key < NEWT_KEY_EXTRA_BASE && isalpha(ev.u.key)) {
+ for(i = 0, item = li->boxItems; item != NULL &&
+ i < li->currItem; i++, item = item->next);
+
+ if (item && item->text && (toupper(*item->text) == toupper(ev.u.key))) {
+ item = item->next;
+ i++;
+ } else {
+ item = li->boxItems;
+ i = 0;
+ }
+ while (item && item->text &&
+ toupper(*item->text) != toupper(ev.u.key)) {
+ item = item->next;
+ i++;
+ }
+ if (item) {
+ li->currItem = i;
+ if(li->currItem < li->startShowItem ||
+ li->currItem > li->startShowItem)
+ li->startShowItem =
+ li->currItem > li->numItems - li->curHeight ?
+ li->startShowItem = li->numItems - li->curHeight :
+ li->currItem;
+ if(li->sb)
+ newtScrollbarSet(li->sb, li->currItem + 1, li->numItems);
+ newtListboxRealSetCurrent(co);
+ er.result = ER_SWALLOWED;
+ }
+ }
+ }
+ break;
+
+ case EV_FOCUS:
+ li->isActive = 1;
+ listboxDraw(co);
+ er.result = ER_SWALLOWED;
+ break;
+
+ case EV_UNFOCUS:
+ li->isActive = 0;
+ listboxDraw(co);
+ er.result = ER_SWALLOWED;
+ break;
+
+ case EV_MOUSE:
+ /* if this mouse click was within the listbox, make the current
+ item the item clicked on. */
+ /* Up scroll arrow */
+ if (li->sb &&
+ ev.u.mouse.x == co->left + co->width - li->bdxAdjust - 1 &&
+ ev.u.mouse.y == co->top + li->bdyAdjust) {
+ if(li->numItems <= 0) break;
+ if(li->currItem > 0) {
+ li->currItem--;
+ if(li->currItem < li->startShowItem)
+ li->startShowItem = li->currItem;
+ if(li->sb)
+ newtScrollbarSet(li->sb, li->currItem + 1, li->numItems);
+ listboxDraw(co);
+ }
+ if(co->callback) co->callback(co, co->callbackData);
+ er.result = ER_SWALLOWED;
+ break;
+ }
+ /* Down scroll arrow */
+ if (li->sb &&
+ ev.u.mouse.x == co->left + co->width - li->bdxAdjust - 1 &&
+ ev.u.mouse.y == co->top + co->height - li->bdyAdjust - 1) {
+ if(li->numItems <= 0) break;
+ if(li->currItem < li->numItems - 1) {
+ li->currItem++;
+ if(li->currItem > (li->startShowItem + li->curHeight - 1)) {
+ li->startShowItem = li->currItem - li->curHeight + 1;
+ if(li->startShowItem + li->curHeight > li->numItems)
+ li->startShowItem = li->numItems - li->curHeight;
+ }
+ if(li->sb)
+ newtScrollbarSet(li->sb, li->currItem + 1, li->numItems);
+ listboxDraw(co);
+ }
+ if(co->callback) co->callback(co, co->callbackData);
+ er.result = ER_SWALLOWED;
+ break;
+ }
+ if ((ev.u.mouse.y >= co->top + li->bdyAdjust) &&
+ (ev.u.mouse.y <= co->top + co->height - (li->bdyAdjust * 2)) &&
+ (ev.u.mouse.x >= co->left + li->bdxAdjust) &&
+ (ev.u.mouse.x <= co->left + co->width + (li->bdxAdjust * 2))) {
+ li->currItem = li->startShowItem +
+ (ev.u.mouse.y - li->bdyAdjust - co->top);
+ newtListboxRealSetCurrent(co);
+ listboxDraw(co);
+ if(co->callback) co->callback(co, co->callbackData);
+ er.result = ER_SWALLOWED;
+ break;
+ }
+ }
+
+ return er;
+}
+
+static void listboxDestroy(newtComponent co) {
+ struct listbox * li = co->data;
+ struct items * item, * nextitem;
+
+ nextitem = item = li->boxItems;
+
+ while (item != NULL) {
+ nextitem = item->next;
+ free(item->text);
+ free(item);
+ item = nextitem;
+ }
+
+ if (li->sb) li->sb->ops->destroy(li->sb);
+
+ free(li);
+ free(co);
+}
diff --git a/mdk-stage1/newt/newt.c b/mdk-stage1/newt/newt.c
new file mode 100644
index 000000000..8ff5e39a5
--- /dev/null
+++ b/mdk-stage1/newt/newt.c
@@ -0,0 +1,672 @@
+#include <slang.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/signal.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <termios.h>
+#include <unistd.h>
+
+#include "newt.h"
+#include "newt_pr.h"
+
+struct Window {
+ int height, width, top, left;
+ short * buffer;
+ char * title;
+};
+
+struct keymap {
+ char * str;
+ int code;
+ char * tc;
+};
+
+static struct Window windowStack[20];
+static struct Window * currentWindow = NULL;
+
+static char * helplineStack[20];
+static char ** currentHelpline = NULL;
+
+static int cursorRow, cursorCol;
+static int needResize;
+static int cursorOn = 1;
+
+static const char * defaultHelpLine =
+" <Tab>/<Alt-Tab> between elements | <Space> selects | <F12> next screen"
+;
+
+const struct newtColors newtDefaultColorPalette = {
+ "cyan", "black", /* root fg, bg */
+ "black", "blue", /* border fg, bg */
+ "white", "blue", /* window fg, bg */
+ "white", "black", /* shadow fg, bg */
+ "white", "blue", /* title fg, bg */
+ "black", "cyan", /* button fg, bg */
+ "yellow", "cyan", /* active button fg, bg */
+ "yellow", "blue", /* checkbox fg, bg */
+ "blue", "brown", /* active checkbox fg, bg */
+ "yellow", "blue", /* entry box fg, bg */
+ "white", "blue", /* label fg, bg */
+ "black", "cyan", /* listbox fg, bg */
+ "yellow", "cyan", /* active listbox fg, bg */
+ "white", "blue", /* textbox fg, bg */
+ "cyan", "black", /* active textbox fg, bg */
+ "white", "blue", /* help line */
+ "yellow", "blue", /* root text */
+ "blue", /* scale full */
+ "red", /* scale empty */
+ "blue", "cyan", /* disabled entry fg, bg */
+ "white", "blue", /* compact button fg, bg */
+ "yellow", "red", /* active & sel listbox */
+ "black", "brown" /* selected listbox */
+};
+
+static const struct keymap keymap[] = {
+ { "\033OA", NEWT_KEY_UP, "kh" },
+ { "\033[A", NEWT_KEY_UP, "ku" },
+ { "\033OB", NEWT_KEY_DOWN, "kd" },
+ { "\033[B", NEWT_KEY_DOWN, "kd" },
+ { "\033[C", NEWT_KEY_RIGHT, "kr" },
+ { "\033OC", NEWT_KEY_RIGHT, "kr" },
+ { "\033[D", NEWT_KEY_LEFT, "kl" },
+ { "\033OD", NEWT_KEY_LEFT, "kl" },
+ { "\033[H", NEWT_KEY_HOME, "kh" },
+ { "\033[1~", NEWT_KEY_HOME, "kh" },
+ { "\033Ow", NEWT_KEY_END, "kH" },
+ { "\033[4~", NEWT_KEY_END, "kH" },
+
+ { "\033[3~", NEWT_KEY_DELETE, "kl" },
+ { "\033[2~", NEWT_KEY_INSERT, NULL },
+
+ { "\033\t", NEWT_KEY_UNTAB, NULL },
+
+ { "\033[5~", NEWT_KEY_PGUP, NULL },
+ { "\033[6~", NEWT_KEY_PGDN, NULL },
+ { "\033V", NEWT_KEY_PGUP, "kH" },
+ { "\033v", NEWT_KEY_PGUP, "kH" },
+
+ { "\033[[A", NEWT_KEY_F1, NULL },
+ { "\033[[B", NEWT_KEY_F2, NULL },
+ { "\033[[C", NEWT_KEY_F3, NULL },
+ { "\033[[D", NEWT_KEY_F4, NULL },
+ { "\033[[E", NEWT_KEY_F5, NULL },
+
+ { "\033OP", NEWT_KEY_F1, NULL },
+ { "\033OQ", NEWT_KEY_F2, NULL },
+ { "\033OR", NEWT_KEY_F3, NULL },
+ { "\033OS", NEWT_KEY_F4, NULL },
+
+ { "\033[11~", NEWT_KEY_F1, NULL },
+ { "\033[12~", NEWT_KEY_F2, NULL },
+ { "\033[13~", NEWT_KEY_F3, NULL },
+ { "\033[14~", NEWT_KEY_F4, NULL },
+ { "\033[15~", NEWT_KEY_F5, NULL },
+ { "\033[17~", NEWT_KEY_F6, NULL },
+ { "\033[18~", NEWT_KEY_F7, NULL },
+ { "\033[19~", NEWT_KEY_F8, NULL },
+ { "\033[20~", NEWT_KEY_F9, NULL },
+ { "\033[21~", NEWT_KEY_F10, NULL },
+ { "\033[23~", NEWT_KEY_F11, NULL },
+ { "\033[24~", NEWT_KEY_F12, NULL },
+
+ { NULL, 0, NULL }, /* LEAVE this one */
+};
+static char keyPrefix = '\033';
+
+static const char * version = "Newt windowing library version " VERSION
+ " - (C) 1996-2000 Red Hat Software. "
+ "Redistributable under the term of the Library "
+ "GNU Public License. "
+ "Written by Erik Troan\n";
+
+static newtSuspendCallback suspendCallback = NULL;
+static void * suspendCallbackData = NULL;
+
+void newtSetSuspendCallback(newtSuspendCallback cb, void * data) {
+ suspendCallback = cb;
+ suspendCallbackData = data;
+}
+
+static void handleSigwinch(int signum __attribute__ ((unused))) {
+ needResize = 1;
+}
+
+static int getkeyInterruptHook(void) {
+ return -1;
+}
+
+void newtFlushInput(void) {
+ while (SLang_input_pending(0)) {
+ SLang_getkey();
+ }
+}
+
+void newtRefresh(void) {
+ SLsmg_refresh();
+}
+
+void newtSuspend(void) {
+ SLtt_set_cursor_visibility (1);
+ SLsmg_suspend_smg();
+ SLang_reset_tty();
+ SLtt_set_cursor_visibility (cursorOn);
+}
+
+void newtResume(void) {
+ SLsmg_resume_smg ();
+ SLsmg_refresh();
+ SLang_init_tty(0, 0, 0);
+}
+
+void newtCls(void) {
+ SLsmg_set_color(NEWT_COLORSET_ROOT);
+ SLsmg_gotorc(0, 0);
+ SLsmg_erase_eos();
+
+ newtRefresh();
+}
+
+#if defined(THIS_DOESNT_WORK)
+void newtResizeScreen(int redraw) {
+ newtPushHelpLine("");
+
+ SLtt_get_screen_size();
+ SLang_init_tty(0, 0, 0);
+
+ SLsmg_touch_lines (0, SLtt_Screen_Rows - 1);
+
+ /* I don't know why I need this */
+ SLsmg_refresh();
+
+ newtPopHelpLine();
+
+ if (redraw)
+ SLsmg_refresh();
+}
+#endif
+
+int newtInit(void) {
+ char * MonoValue, * MonoEnv = "NEWT_MONO";
+
+ /* use the version variable just to be sure it gets included */
+ (void) strlen(version);
+
+ SLtt_get_terminfo();
+ SLtt_get_screen_size();
+
+ MonoValue = getenv(MonoEnv);
+ if ( MonoValue == NULL ) {
+ SLtt_Use_Ansi_Colors = 1;
+ } else {
+ SLtt_Use_Ansi_Colors = 0;
+ }
+
+ SLsmg_init_smg();
+ SLang_init_tty(0, 0, 0);
+
+ newtSetColors(newtDefaultColorPalette);
+ newtCursorOff();
+ /*initKeymap();*/
+
+ /*memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = handleSigwinch;
+ sigaction(SIGWINCH, &sa, NULL);*/
+
+ SLsignal_intr(SIGWINCH, handleSigwinch);
+ SLang_getkey_intr_hook = getkeyInterruptHook;
+
+
+
+ return 0;
+}
+
+int newtFinished(void) {
+ SLsmg_gotorc(SLtt_Screen_Rows - 1, 0);
+ newtCursorOn();
+ SLsmg_refresh();
+ SLsmg_reset_smg();
+ SLang_reset_tty();
+
+ return 0;
+}
+
+void newtSetColors(struct newtColors colors) {
+ SLtt_set_color(NEWT_COLORSET_ROOT, "", colors.rootFg, colors.rootBg);
+ SLtt_set_color(NEWT_COLORSET_BORDER, "", colors.borderFg, colors.borderBg);
+ SLtt_set_color(NEWT_COLORSET_WINDOW, "", colors.windowFg, colors.windowBg);
+ SLtt_set_color(NEWT_COLORSET_SHADOW, "", colors.shadowFg, colors.shadowBg);
+ SLtt_set_color(NEWT_COLORSET_TITLE, "", colors.titleFg, colors.titleBg);
+ SLtt_set_color(NEWT_COLORSET_BUTTON, "", colors.buttonFg, colors.buttonBg);
+ SLtt_set_color(NEWT_COLORSET_ACTBUTTON, "", colors.actButtonFg,
+ colors.actButtonBg);
+ SLtt_set_color(NEWT_COLORSET_CHECKBOX, "", colors.checkboxFg,
+ colors.checkboxBg);
+ SLtt_set_color(NEWT_COLORSET_ACTCHECKBOX, "", colors.actCheckboxFg,
+ colors.actCheckboxBg);
+ SLtt_set_color(NEWT_COLORSET_ENTRY, "", colors.entryFg, colors.entryBg);
+ SLtt_set_color(NEWT_COLORSET_LABEL, "", colors.labelFg, colors.labelBg);
+ SLtt_set_color(NEWT_COLORSET_LISTBOX, "", colors.listboxFg,
+ colors.listboxBg);
+ SLtt_set_color(NEWT_COLORSET_ACTLISTBOX, "", colors.actListboxFg,
+ colors.actListboxBg);
+ SLtt_set_color(NEWT_COLORSET_TEXTBOX, "", colors.textboxFg,
+ colors.textboxBg);
+ SLtt_set_color(NEWT_COLORSET_ACTTEXTBOX, "", colors.actTextboxFg,
+ colors.actTextboxBg);
+ SLtt_set_color(NEWT_COLORSET_HELPLINE, "", colors.helpLineFg,
+ colors.helpLineBg);
+ SLtt_set_color(NEWT_COLORSET_ROOTTEXT, "", colors.rootTextFg,
+ colors.rootTextBg);
+
+ SLtt_set_color(NEWT_COLORSET_EMPTYSCALE, "", "black",
+ colors.emptyScale);
+ SLtt_set_color(NEWT_COLORSET_FULLSCALE, "", "black",
+ colors.fullScale);
+ SLtt_set_color(NEWT_COLORSET_DISENTRY, "", colors.disabledEntryFg,
+ colors.disabledEntryBg);
+
+ SLtt_set_color(NEWT_COLORSET_COMPACTBUTTON, "", colors.compactButtonFg,
+ colors.compactButtonBg);
+
+ SLtt_set_color(NEWT_COLORSET_ACTSELLISTBOX, "", colors.actSelListboxFg,
+ colors.actSelListboxBg);
+ SLtt_set_color(NEWT_COLORSET_SELLISTBOX, "", colors.selListboxFg,
+ colors.selListboxBg);
+}
+
+int newtGetKey(void) {
+ int key;
+ char buf[10], * chptr = buf;
+ const struct keymap * curr;
+
+ do {
+ key = SLang_getkey();
+ if (key == 0xFFFF) {
+ if (needResize)
+ return NEWT_KEY_RESIZE;
+
+ /* ignore other signals */
+ continue;
+ }
+
+ if (key == NEWT_KEY_SUSPEND && suspendCallback)
+ suspendCallback(suspendCallbackData);
+ } while (key == NEWT_KEY_SUSPEND);
+
+ switch (key) {
+ case 'v' | 0x80:
+ case 'V' | 0x80:
+ return NEWT_KEY_PGUP;
+
+ case 22:
+ return NEWT_KEY_PGDN;
+
+ return NEWT_KEY_BKSPC;
+ case 0x7f:
+ return NEWT_KEY_BKSPC;
+
+ case 0x08:
+ return NEWT_KEY_BKSPC;
+
+ default:
+ if (key != keyPrefix) return key;
+ }
+
+ memset(buf, 0, sizeof(buf));
+
+ *chptr++ = key;
+ while (SLang_input_pending(5)) {
+ key = SLang_getkey();
+ if (key == keyPrefix) {
+ /* he hit unknown keys too many times -- start over */
+ memset(buf, 0, sizeof(buf));
+ chptr = buf;
+ }
+
+ *chptr++ = key;
+
+ /* this search should use bsearch(), but when we only look through
+ a list of 20 (or so) keymappings, it's probably faster just to
+ do a inline linear search */
+
+ for (curr = keymap; curr->code; curr++) {
+ if (curr->str) {
+ if (!strcmp(curr->str, buf))
+ return curr->code;
+ }
+ }
+ }
+
+ for (curr = keymap; curr->code; curr++) {
+ if (curr->str) {
+ if (!strcmp(curr->str, buf))
+ return curr->code;
+ }
+ }
+
+ /* Looks like we were a bit overzealous in reading characters. Return
+ just the first character, and put everything else back in the buffer
+ for later */
+
+ chptr--;
+ while (chptr > buf)
+ SLang_ungetkey(*chptr--);
+
+ return *chptr;
+}
+
+void newtWaitForKey(void) {
+ newtRefresh();
+
+ SLang_getkey();
+ newtClearKeyBuffer();
+}
+
+void newtClearKeyBuffer(void) {
+ while (SLang_input_pending(1)) {
+ SLang_getkey();
+ }
+}
+
+int newtOpenWindow(int left, int top, int width, int height,
+ const char * title) {
+ int j, row, col;
+ int n;
+ int i;
+
+ newtFlushInput();
+
+ if (!currentWindow) {
+ currentWindow = windowStack;
+ } else {
+ currentWindow++;
+ }
+
+ currentWindow->left = left;
+ currentWindow->top = top;
+ currentWindow->width = width;
+ currentWindow->height = height;
+ currentWindow->title = title ? strdup(title) : NULL;
+
+ currentWindow->buffer = malloc(sizeof(short) * (width + 3) * (height + 3));
+
+ row = top - 1;
+ col = left - 1;
+ n = 0;
+ for (j = 0; j < height + 3; j++, row++) {
+ SLsmg_gotorc(row, col);
+ SLsmg_read_raw((SLsmg_Char_Type *)currentWindow->buffer + n,
+ currentWindow->width + 3);
+ n += currentWindow->width + 3;
+ }
+
+ SLsmg_set_color(NEWT_COLORSET_BORDER);
+ SLsmg_draw_box(top - 1, left - 1, height + 2, width + 2);
+
+ if (currentWindow->title) {
+ i = strlen(currentWindow->title) + 4;
+ i = ((width - i) / 2) + left;
+ SLsmg_gotorc(top - 1, i);
+ SLsmg_set_char_set(1);
+ SLsmg_write_char(SLSMG_RTEE_CHAR);
+ SLsmg_set_char_set(0);
+ SLsmg_write_char(' ');
+ SLsmg_set_color(NEWT_COLORSET_TITLE);
+ SLsmg_write_string((char *)currentWindow->title);
+ SLsmg_set_color(NEWT_COLORSET_BORDER);
+ SLsmg_write_char(' ');
+ SLsmg_set_char_set(1);
+ SLsmg_write_char(SLSMG_LTEE_CHAR);
+ SLsmg_set_char_set(0);
+ }
+
+ SLsmg_set_color(NEWT_COLORSET_WINDOW);
+ SLsmg_fill_region(top, left, height, width, ' ');
+
+ SLsmg_set_color(NEWT_COLORSET_SHADOW);
+ SLsmg_fill_region(top + height + 1, left, 1, width + 2, ' ');
+ SLsmg_fill_region(top, left + width + 1, height + 1, 1, ' ');
+
+ for (i = top; i < (top + height + 1); i++) {
+ SLsmg_gotorc(i, left + width + 1);
+ SLsmg_write_string(" ");
+ }
+
+ return 0;
+}
+
+int newtCenteredWindow(int width, int height, const char * title) {
+ int top, left;
+
+ top = (SLtt_Screen_Rows - height) / 2;
+
+ /* I don't know why, but this seems to look better */
+ if ((SLtt_Screen_Rows % 2) && (top % 2)) top--;
+
+ left = (SLtt_Screen_Cols - width) / 2;
+
+ newtOpenWindow(left, top, width, height, title);
+
+ return 0;
+}
+
+void newtPopWindow(void) {
+ int j, row, col;
+ int n = 0;
+
+ row = col = 0;
+
+ row = currentWindow->top - 1;
+ col = currentWindow->left - 1;
+ for (j = 0; j < currentWindow->height + 3; j++, row++) {
+ SLsmg_gotorc(row, col);
+ SLsmg_write_raw((SLsmg_Char_Type *)currentWindow->buffer + n,
+ currentWindow->width + 3);
+ n += currentWindow->width + 3;
+ }
+
+ free(currentWindow->buffer);
+ free(currentWindow->title);
+
+ if (currentWindow == windowStack)
+ currentWindow = NULL;
+ else
+ currentWindow--;
+
+ SLsmg_set_char_set(0);
+
+ newtRefresh();
+}
+
+void newtGetWindowPos(int * x, int * y) {
+ if (currentWindow) {
+ *x = currentWindow->left;
+ *y = currentWindow->top;
+ } else
+ *x = *y = 0;
+}
+
+void newtGetrc(int * row, int * col) {
+ *row = cursorRow;
+ *col = cursorCol;
+}
+
+void newtGotorc(int newRow, int newCol) {
+ if (currentWindow) {
+ newRow += currentWindow->top;
+ newCol += currentWindow->left;
+ }
+
+ cursorRow = newRow;
+ cursorCol = newCol;
+ SLsmg_gotorc(cursorRow, cursorCol);
+}
+
+void newtDrawBox(int left, int top, int width, int height, int shadow) {
+ if (currentWindow) {
+ top += currentWindow->top;
+ left += currentWindow->left;
+ }
+
+ SLsmg_draw_box(top, left, height, width);
+
+ if (shadow) {
+ SLsmg_set_color(NEWT_COLORSET_SHADOW);
+ SLsmg_fill_region(top + height, left + 1, 1, width - 1, ' ');
+ SLsmg_fill_region(top + 1, left + width, height, 1, ' ');
+ }
+}
+
+void newtClearBox(int left, int top, int width, int height) {
+ if (currentWindow) {
+ top += currentWindow->top;
+ left += currentWindow->left;
+ }
+
+ SLsmg_fill_region(top, left, height, width, ' ');
+}
+
+#if 0
+/* This doesn't seem to work quite right. I don't know why not, but when
+ I rsh from an rxvt into a box and run this code, the machine returns
+ console key's (\033[B) rather then xterm ones (\033OB). */
+static void initKeymap(void) {
+ struct keymap * curr;
+
+ for (curr = keymap; curr->code; curr++) {
+ if (!curr->str)
+ curr->str = SLtt_tgetstr(curr->tc);
+ }
+
+ /* Newt's keymap handling is a bit broken. It assumes that any extended
+ keystrokes begin with ESC. If you're using a homebrek terminal you
+ will probably need to fix this, or just yell at me and I'll be so
+ ashamed of myself for doing it this way I'll fix it */
+
+ keyPrefix = 0x1b; /* ESC */
+}
+#endif
+
+void newtDelay(int usecs) {
+ fd_set set;
+ struct timeval tv;
+
+ FD_ZERO(&set);
+
+ tv.tv_sec = usecs / 1000000;
+ tv.tv_usec = usecs % 1000000;
+
+ select(0, &set, &set, &set, &tv);
+}
+
+struct eventResult newtDefaultEventHandler(newtComponent c __attribute__ ((unused)),
+ struct event ev __attribute__ ((unused))) {
+ struct eventResult er;
+
+ er.result = ER_IGNORED;
+ return er;
+}
+
+void newtRedrawHelpLine(void) {
+ char * buf;
+
+ SLsmg_set_color(NEWT_COLORSET_HELPLINE);
+
+ buf = alloca(SLtt_Screen_Cols + 1);
+ memset(buf, ' ', SLtt_Screen_Cols);
+ buf[SLtt_Screen_Cols] = '\0';
+
+ if (currentHelpline)
+ memcpy(buf, *currentHelpline, strlen(*currentHelpline));
+
+ SLsmg_gotorc(SLtt_Screen_Rows - 1, 0);
+ SLsmg_write_string(buf);
+}
+
+void newtPushHelpLine(const char * text) {
+ if (!text)
+ text = defaultHelpLine;
+
+ if (currentHelpline)
+ (*(++currentHelpline)) = strdup(text);
+ else {
+ currentHelpline = helplineStack;
+ *currentHelpline = strdup(text);
+ }
+
+ newtRedrawHelpLine();
+}
+
+void newtPopHelpLine(void) {
+ if (!currentHelpline) return;
+
+ free(*currentHelpline);
+ if (currentHelpline == helplineStack)
+ currentHelpline = NULL;
+ else
+ currentHelpline--;
+
+ newtRedrawHelpLine();
+}
+
+void newtDrawRootText(int col, int row, const char * text) {
+ SLsmg_set_color(NEWT_COLORSET_ROOTTEXT);
+
+ if (col < 0) {
+ col = SLtt_Screen_Cols + col;
+ }
+
+ if (row < 0) {
+ row = SLtt_Screen_Rows + row;
+ }
+
+ SLsmg_gotorc(row, col);
+ SLsmg_write_string((char *)text);
+}
+
+int newtSetFlags(int oldFlags, int newFlags, enum newtFlagsSense sense) {
+ switch (sense) {
+ case NEWT_FLAGS_SET:
+ return oldFlags | newFlags;
+
+ case NEWT_FLAGS_RESET:
+ return oldFlags & (~newFlags);
+
+ case NEWT_FLAGS_TOGGLE:
+ return oldFlags ^ newFlags;
+
+ default:
+ return oldFlags;
+ }
+}
+
+void newtBell(void)
+{
+ SLtt_beep();
+}
+
+void newtGetScreenSize(int * cols, int * rows) {
+ if (rows) *rows = SLtt_Screen_Rows;
+ if (cols) *cols = SLtt_Screen_Cols;
+}
+
+void newtDefaultPlaceHandler(newtComponent c, int newLeft, int newTop) {
+ c->left = newLeft;
+ c->top = newTop;
+}
+
+void newtDefaultMappedHandler(newtComponent c, int isMapped) {
+ c->isMapped = isMapped;
+}
+
+void newtCursorOff(void) {
+ cursorOn = 0;
+ SLtt_set_cursor_visibility (cursorOn);
+}
+
+void newtCursorOn(void) {
+ cursorOn = 1;
+ SLtt_set_cursor_visibility (cursorOn);
+}
diff --git a/mdk-stage1/newt/newt.h b/mdk-stage1/newt/newt.h
new file mode 100644
index 000000000..d3fd8bedc
--- /dev/null
+++ b/mdk-stage1/newt/newt.h
@@ -0,0 +1,362 @@
+#ifndef H_NEWT
+#define H_NEWT
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdarg.h>
+
+#define NEWT_COLORSET_ROOT 2
+#define NEWT_COLORSET_BORDER 3
+#define NEWT_COLORSET_WINDOW 4
+#define NEWT_COLORSET_SHADOW 5
+#define NEWT_COLORSET_TITLE 6
+#define NEWT_COLORSET_BUTTON 7
+#define NEWT_COLORSET_ACTBUTTON 8
+#define NEWT_COLORSET_CHECKBOX 9
+#define NEWT_COLORSET_ACTCHECKBOX 10
+#define NEWT_COLORSET_ENTRY 11
+#define NEWT_COLORSET_LABEL 12
+#define NEWT_COLORSET_LISTBOX 13
+#define NEWT_COLORSET_ACTLISTBOX 14
+#define NEWT_COLORSET_TEXTBOX 15
+#define NEWT_COLORSET_ACTTEXTBOX 16
+#define NEWT_COLORSET_HELPLINE 17
+#define NEWT_COLORSET_ROOTTEXT 18
+#define NEWT_COLORSET_EMPTYSCALE 19
+#define NEWT_COLORSET_FULLSCALE 20
+#define NEWT_COLORSET_DISENTRY 21
+#define NEWT_COLORSET_COMPACTBUTTON 22
+#define NEWT_COLORSET_ACTSELLISTBOX 23
+#define NEWT_COLORSET_SELLISTBOX 24
+
+#define NEWT_ARG_LAST -100000
+#define NEWT_ARG_APPEND -1
+
+struct newtColors {
+ char * rootFg, * rootBg;
+ char * borderFg, * borderBg;
+ char * windowFg, * windowBg;
+ char * shadowFg, * shadowBg;
+ char * titleFg, * titleBg;
+ char * buttonFg, * buttonBg;
+ char * actButtonFg, * actButtonBg;
+ char * checkboxFg, * checkboxBg;
+ char * actCheckboxFg, * actCheckboxBg;
+ char * entryFg, * entryBg;
+ char * labelFg, * labelBg;
+ char * listboxFg, * listboxBg;
+ char * actListboxFg, * actListboxBg;
+ char * textboxFg, * textboxBg;
+ char * actTextboxFg, * actTextboxBg;
+ char * helpLineFg, * helpLineBg;
+ char * rootTextFg, * rootTextBg;
+ char * emptyScale, * fullScale;
+ char * disabledEntryFg, * disabledEntryBg;
+ char * compactButtonFg, * compactButtonBg;
+ char * actSelListboxFg, * actSelListboxBg;
+ char * selListboxFg, * selListboxBg;
+};
+
+enum newtFlagsSense { NEWT_FLAGS_SET, NEWT_FLAGS_RESET, NEWT_FLAGS_TOGGLE };
+
+#define NEWT_FLAG_RETURNEXIT (1 << 0)
+#define NEWT_FLAG_HIDDEN (1 << 1)
+#define NEWT_FLAG_SCROLL (1 << 2)
+#define NEWT_FLAG_DISABLED (1 << 3)
+/* OBSOLETE #define NEWT_FLAG_NOSCROLL (1 << 4) for listboxes */
+#define NEWT_FLAG_BORDER (1 << 5)
+#define NEWT_FLAG_WRAP (1 << 6)
+#define NEWT_FLAG_NOF12 (1 << 7)
+#define NEWT_FLAG_MULTIPLE (1 << 8)
+#define NEWT_FLAG_SELECTED (1 << 9)
+#define NEWT_FLAG_CHECKBOX (1 << 10)
+#define NEWT_FLAG_PASSWORD (1 << 11) /* draw '*' of chars in entrybox */
+#define NEWT_FD_READ (1 << 0)
+#define NEWT_FD_WRITE (1 << 1)
+
+#define NEWT_CHECKBOXTREE_COLLAPSED '\0'
+#define NEWT_CHECKBOXTREE_EXPANDED '\1'
+#define NEWT_CHECKBOXTREE_UNSELECTED ' '
+#define NEWT_CHECKBOXTREE_SELECTED '*'
+
+/* Backwards compatibility */
+#define NEWT_LISTBOX_RETURNEXIT NEWT_FLAG_RETURNEXIT
+#define NEWT_ENTRY_SCROLL NEWT_FLAG_SCROLL
+#define NEWT_ENTRY_HIDDEN NEWT_FLAG_HIDDEN
+#define NEWT_ENTRY_RETURNEXIT NEWT_FLAG_RETURNEXIT
+#define NEWT_ENTRY_DISABLED NEWT_FLAG_DISABLED
+
+#define NEWT_TEXTBOX_WRAP NEWT_FLAG_WRAP
+#define NEWT_TEXTBOX_SCROLL NEWT_FLAG_SCROLL
+#define NEWT_FORM_NOF12 NEWT_FLAG_NOF12
+
+#define newtListboxAddEntry newtListboxAppendEntry
+
+
+typedef struct newtComponent_struct * newtComponent;
+
+extern const struct newtColors newtDefaultColorPalette;
+
+typedef void (*newtCallback)(newtComponent, void *);
+typedef void (*newtSuspendCallback)(void * data);
+
+int newtInit(void);
+int newtFinished(void);
+void newtCls(void);
+void newtResizeScreen(int redraw);
+void newtWaitForKey(void);
+void newtClearKeyBuffer(void);
+void newtDelay(int usecs);
+/* top, left are *not* counting the border */
+int newtOpenWindow(int left, int top, int width, int height,
+ const char * title);
+int newtCenteredWindow(int width, int height, const char * title);
+void newtPopWindow(void);
+void newtSetColors(struct newtColors colors);
+void newtRefresh(void);
+void newtSuspend(void);
+void newtSetSuspendCallback(newtSuspendCallback cb, void * data);
+void newtSetHelpCallback(newtCallback cb);
+void newtResume(void);
+void newtPushHelpLine(const char * text);
+void newtRedrawHelpLine(void);
+void newtPopHelpLine(void);
+void newtDrawRootText(int col, int row, const char * text);
+void newtBell(void);
+void newtCursorOff(void);
+void newtCursorOn(void);
+
+/* Components */
+
+newtComponent newtCompactButton(int left, int top, const char * text);
+newtComponent newtButton(int left, int top, const char * text);
+newtComponent newtCheckbox(int left, int top, const char * text, char defValue,
+ const char * seq, char * result);
+char newtCheckboxGetValue(newtComponent co);
+void newtCheckboxSetValue(newtComponent co, char value);
+void newtCheckboxSetFlags(newtComponent co, int flags, enum newtFlagsSense sense);
+
+
+newtComponent newtRadiobutton(int left, int top, const char * text, int isDefault,
+ newtComponent prevButton);
+newtComponent newtRadioGetCurrent(newtComponent setMember);
+newtComponent newtListitem(int left, int top, const char * text, int isDefault,
+ newtComponent prevItem, const void * data, int flags);
+void newtListitemSet(newtComponent co, const char * text);
+void * newtListitemGetData(newtComponent co);
+void newtGetScreenSize(int * cols, int * rows);
+
+newtComponent newtLabel(int left, int top, const char * text);
+void newtLabelSetText(newtComponent co, const char * text);
+newtComponent newtVerticalScrollbar(int left, int top, int height,
+ int normalColorset, int thumbColorset);
+void newtScrollbarSet(newtComponent co, int where, int total);
+
+newtComponent newtListbox(int left, int top, int height, int flags);
+void * newtListboxGetCurrent(newtComponent co);
+void newtListboxSetCurrent(newtComponent co, int num);
+void newtListboxSetCurrentByKey(newtComponent co, void * key);
+void newtListboxSetEntry(newtComponent co, int num, const char * text);
+void newtListboxSetWidth(newtComponent co, int width);
+void newtListboxSetData(newtComponent co, int num, void * data);
+int newtListboxAppendEntry(newtComponent co, const char * text,
+ const void * data);
+/* Send the key to insert after, or NULL to insert at the top */
+int newtListboxInsertEntry(newtComponent co, const char * text, const void * data, void * key);
+int newtListboxDeleteEntry(newtComponent co, void * data);
+void newtListboxClear(newtComponent co); /* removes all entries from listbox */
+void newtListboxGetEntry(newtComponent co, int num, char **text, void **data);
+/* Returns an array of data pointers from items, last element is NULL */
+void **newtListboxGetSelection(newtComponent co, int *numitems);
+void newtListboxClearSelection(newtComponent co);
+void newtListboxSelectItem(newtComponent co, const void * key,
+ enum newtFlagsSense sense);
+
+newtComponent newtCheckboxTree(int left, int top, int height, int flags);
+newtComponent newtCheckboxTreeMulti(int left, int top, int height, char *seq, int flags);
+const void ** newtCheckboxTreeGetSelection(newtComponent co, int *numitems);
+const void * newtCheckboxTreeGetCurrent(newtComponent co);
+const void ** newtCheckboxTreeGetMultiSelection(newtComponent co, int *numitems, char seqnum);
+/* last item is NEWT_ARG_LAST for all of these */
+int newtCheckboxTreeAddItem(newtComponent co,
+ const char * text, const void * data,
+ int flags, int index, ...);
+int newtCheckboxTreeAddArray(newtComponent co,
+ const char * text, const void * data,
+ int flags, int * indexes);
+int * newtCheckboxTreeFindItem(newtComponent co, void * data);
+void newtCheckboxTreeSetEntry(newtComponent co, const void * data,
+ const char * text);
+char newtCheckboxTreeGetEntryValue(newtComponent co, const void * data);
+void newtCheckboxTreeSetEntryValue(newtComponent co, const void * data,
+ char value);
+
+newtComponent newtTextboxReflowed(int left, int top, char * text, int width,
+ int flexDown, int flexUp, int flags);
+newtComponent newtTextbox(int left, int top, int width, int height, int flags);
+void newtTextboxSetText(newtComponent co, const char * text);
+void newtTextboxSetHeight(newtComponent co, int height);
+int newtTextboxGetNumLines(newtComponent co);
+char * newtReflowText(char * text, int width, int flexDown, int flexUp,
+ int * actualWidth, int * actualHeight);
+
+struct newtExitStruct {
+ enum { NEWT_EXIT_HOTKEY, NEWT_EXIT_COMPONENT, NEWT_EXIT_FDREADY,
+ NEWT_EXIT_TIMER } reason;
+ union {
+ int key;
+ newtComponent co;
+ } u;
+} ;
+
+newtComponent newtForm(newtComponent vertBar, void * helpTag, int flags);
+void newtFormSetTimer(newtComponent form, int millisecs);
+void newtFormWatchFd(newtComponent form, int fd, int fdFlags);
+void newtFormSetSize(newtComponent co);
+newtComponent newtFormGetCurrent(newtComponent co);
+void newtFormSetBackground(newtComponent co, int color);
+void newtFormSetCurrent(newtComponent co, newtComponent subco);
+void newtFormAddComponent(newtComponent form, newtComponent co);
+void newtFormAddComponents(newtComponent form, ...);
+void newtFormSetHeight(newtComponent co, int height);
+void newtFormSetWidth(newtComponent co, int width);
+newtComponent newtRunForm(newtComponent form); /* obsolete */
+void newtFormRun(newtComponent co, struct newtExitStruct * es);
+void newtDrawForm(newtComponent form);
+void newtFormAddHotKey(newtComponent co, int key);
+
+typedef int (*newtEntryFilter)(newtComponent entry, void * data, int ch,
+ int cursor);
+newtComponent newtEntry(int left, int top, const char * initialValue, int width,
+ char ** resultPtr, int flags);
+void newtEntrySet(newtComponent co, const char * value, int cursorAtEnd);
+void newtEntrySetFilter(newtComponent co, newtEntryFilter filter, void * data);
+char * newtEntryGetValue(newtComponent co);
+void newtEntrySetFlags(newtComponent co, int flags, enum newtFlagsSense sense);
+
+newtComponent newtScale(int left, int top, int width, int fullValue);
+void newtScaleSet(newtComponent co, unsigned int amount);
+
+void newtComponentAddCallback(newtComponent co, newtCallback f, void * data);
+void newtComponentTakesFocus(newtComponent co, int val);
+
+/* this also destroys all of the components (including other forms) on the
+ form */
+void newtFormDestroy(newtComponent form);
+
+/* Key codes */
+
+#define NEWT_KEY_TAB '\t'
+#define NEWT_KEY_ENTER '\r'
+#define NEWT_KEY_SUSPEND '\032' /* ctrl - z*/
+#define NEWT_KEY_RETURN NEWT_KEY_ENTER
+
+#define NEWT_KEY_EXTRA_BASE 0x8000
+#define NEWT_KEY_UP NEWT_KEY_EXTRA_BASE + 1
+#define NEWT_KEY_DOWN NEWT_KEY_EXTRA_BASE + 2
+#define NEWT_KEY_LEFT NEWT_KEY_EXTRA_BASE + 4
+#define NEWT_KEY_RIGHT NEWT_KEY_EXTRA_BASE + 5
+#define NEWT_KEY_BKSPC NEWT_KEY_EXTRA_BASE + 6
+#define NEWT_KEY_DELETE NEWT_KEY_EXTRA_BASE + 7
+#define NEWT_KEY_HOME NEWT_KEY_EXTRA_BASE + 8
+#define NEWT_KEY_END NEWT_KEY_EXTRA_BASE + 9
+#define NEWT_KEY_UNTAB NEWT_KEY_EXTRA_BASE + 10
+#define NEWT_KEY_PGUP NEWT_KEY_EXTRA_BASE + 11
+#define NEWT_KEY_PGDN NEWT_KEY_EXTRA_BASE + 12
+#define NEWT_KEY_INSERT NEWT_KEY_EXTRA_BASE + 13
+
+#define NEWT_KEY_F1 NEWT_KEY_EXTRA_BASE + 101
+#define NEWT_KEY_F2 NEWT_KEY_EXTRA_BASE + 102
+#define NEWT_KEY_F3 NEWT_KEY_EXTRA_BASE + 103
+#define NEWT_KEY_F4 NEWT_KEY_EXTRA_BASE + 104
+#define NEWT_KEY_F5 NEWT_KEY_EXTRA_BASE + 105
+#define NEWT_KEY_F6 NEWT_KEY_EXTRA_BASE + 106
+#define NEWT_KEY_F7 NEWT_KEY_EXTRA_BASE + 107
+#define NEWT_KEY_F8 NEWT_KEY_EXTRA_BASE + 108
+#define NEWT_KEY_F9 NEWT_KEY_EXTRA_BASE + 109
+#define NEWT_KEY_F10 NEWT_KEY_EXTRA_BASE + 110
+#define NEWT_KEY_F11 NEWT_KEY_EXTRA_BASE + 111
+#define NEWT_KEY_F12 NEWT_KEY_EXTRA_BASE + 112
+
+/* not really a key, but newtGetKey returns it */
+#define NEWT_KEY_RESIZE NEWT_KEY_EXTRA_BASE + 113
+
+#define NEWT_ANCHOR_LEFT (1 << 0)
+#define NEWT_ANCHOR_RIGHT (1 << 1)
+#define NEWT_ANCHOR_TOP (1 << 2)
+#define NEWT_ANCHOR_BOTTOM (1 << 3)
+
+#define NEWT_GRID_FLAG_GROWX (1 << 0)
+#define NEWT_GRID_FLAG_GROWY (1 << 1)
+
+typedef struct grid_s * newtGrid;
+enum newtGridElement { NEWT_GRID_EMPTY = 0,
+ NEWT_GRID_COMPONENT, NEWT_GRID_SUBGRID };
+
+newtGrid newtCreateGrid(int cols, int rows);
+/* TYPE, what, TYPE, what, ..., NULL */
+newtGrid newtGridVStacked(enum newtGridElement type, void * what, ...);
+newtGrid newtGridVCloseStacked(enum newtGridElement type, void * what, ...);
+newtGrid newtGridHStacked(enum newtGridElement type1, void * what1, ...);
+newtGrid newtGridHCloseStacked(enum newtGridElement type1, void * what1, ...);
+newtGrid newtGridBasicWindow(newtComponent text, newtGrid middle,
+ newtGrid buttons);
+newtGrid newtGridSimpleWindow(newtComponent text, newtComponent middle,
+ newtGrid buttons);
+void newtGridSetField(newtGrid grid, int col, int row,
+ enum newtGridElement type, void * val, int padLeft,
+ int padTop, int padRight, int padBottom, int anchor,
+ int flags);
+void newtGridPlace(newtGrid grid, int left, int top);
+#define newtGridDestroy newtGridFree
+void newtGridFree(newtGrid grid, int recurse);
+void newtGridGetSize(newtGrid grid, int * width, int * height);
+void newtGridWrappedWindow(newtGrid grid, char * title);
+void newtGridWrappedWindowAt(newtGrid grid, char * title, int left, int top);
+void newtGridAddComponentsToForm(newtGrid grid, newtComponent form,
+ int recurse);
+
+/* convienve */
+newtGrid newtButtonBarv(char * button1, newtComponent * b1comp, va_list args);
+newtGrid newtButtonBar(char * button1, newtComponent * b1comp, ...);
+
+/* automatically centered and shrink wrapped */
+void newtWinMessage(char * title, char * buttonText, char * text, ...);
+void newtWinMessagev(char * title, char * buttonText, char * text,
+ va_list argv);
+
+/* having separate calls for these two seems silly, but having two separate
+ variable length-arg lists seems like a bad idea as well */
+
+/* Returns 0 if F12 was pressed, 1 for button1, 2 for button2 */
+int newtWinChoice(char * title, char * button1, char * button2,
+ char * text, ...);
+/* Returns 0 if F12 was pressed, 1 for button1, 2 for button2,
+ 3 for button3 */
+int newtWinTernary(char * title, char * button1, char * button2,
+ char * button3, char * message, ...);
+
+/* Returns the button number pressed, 0 on F12 */
+int newtWinMenu(char * title, char * text, int suggestedWidth, int flexDown,
+ int flexUp, int maxListHeight, char ** items, int * listItem,
+ char * button1, ...);
+
+struct newtWinEntry {
+ char * text;
+ char ** value; /* may be initialized to set default */
+ int flags;
+};
+
+/* Returns the button number pressed, 0 on F12. The final values are
+ dynamically allocated, and need to be freed. */
+int newtWinEntries(char * title, char * text, int suggestedWidth, int flexDown,
+ int flexUp, int dataWidth,
+ struct newtWinEntry * items, char * button1, ...);
+
+#ifdef __cplusplus
+} /* End of extern "C" { */
+#endif
+
+#endif /* H_NEWT */
diff --git a/mdk-stage1/newt/newt_pr.h b/mdk-stage1/newt/newt_pr.h
new file mode 100644
index 000000000..76f5e2f6f
--- /dev/null
+++ b/mdk-stage1/newt/newt_pr.h
@@ -0,0 +1,82 @@
+#ifndef H_NEWT_PR
+#define H_NEWT_PR
+
+#define COLORSET_ROOT NEWT_COLORSET_ROOT
+#define COLORSET_BORDER NEWT_COLORSET_BORDER
+#define COLORSET_WINDOW NEWT_COLORSET_WINDOW
+#define COLORSET_SHADOW NEWT_COLORSET_SHADOW
+#define COLORSET_TITLE NEWT_COLORSET_TITLE
+#define COLORSET_BUTTON NEWT_COLORSET_BUTTON
+#define COLORSET_ACTBUTTON NEWT_COLORSET_ACTBUTTON
+#define COLORSET_CHECKBOX NEWT_COLORSET_CHECKBOX
+#define COLORSET_ACTCHECKBOX NEWT_COLORSET_ACTCHECKBOX
+#define COLORSET_ENTRY NEWT_COLORSET_ENTRY
+#define COLORSET_LABEL NEWT_COLORSET_LABEL
+#define COLORSET_LISTBOX NEWT_COLORSET_LISTBOX
+#define COLORSET_ACTLISTBOX NEWT_COLORSET_ACTLISTBOX
+#define COLORSET_TEXTBOX NEWT_COLORSET_TEXTBOX
+#define COLORSET_ACTTEXTBOX NEWT_COLORSET_ACTTEXTBOX
+
+int newtSetFlags(int oldFlags, int newFlags, enum newtFlagsSense sense);
+
+void newtGotorc(int row, int col);
+void newtGetrc(int * row, int * col);
+void newtGetWindowPos(int * x, int * y);
+void newtDrawBox(int left, int top, int width, int height, int shadow);
+void newtClearBox(int left, int top, int width, int height);
+
+int newtGetKey(void);
+
+struct newtComponent_struct {
+ /* common data */
+ int height, width;
+ int top, left;
+ int takesFocus;
+ int isMapped;
+
+ struct componentOps * ops;
+
+ newtCallback callback;
+ void * callbackData;
+
+ void * data;
+} ;
+
+enum eventResultTypes { ER_IGNORED, ER_SWALLOWED, ER_EXITFORM, ER_SETFOCUS,
+ ER_NEXTCOMP };
+struct eventResult {
+ enum eventResultTypes result;
+ union {
+ newtComponent focus;
+ } u;
+};
+
+enum eventTypes { EV_FOCUS, EV_UNFOCUS, EV_KEYPRESS, EV_MOUSE };
+enum eventSequence { EV_EARLY, EV_NORMAL, EV_LATE };
+
+struct event {
+ enum eventTypes event;
+ enum eventSequence when;
+ union {
+ int key;
+ struct {
+ enum { MOUSE_MOTION, MOUSE_BUTTON_DOWN, MOUSE_BUTTON_UP } type;
+ int x, y;
+ } mouse;
+ } u;
+} ;
+
+struct componentOps {
+ void (* draw)(newtComponent c);
+ struct eventResult (* event)(newtComponent c, struct event ev);
+ void (* destroy)(newtComponent c);
+ void (* place)(newtComponent c, int newLeft, int newTop);
+ void (* mapped)(newtComponent c, int isMapped);
+} ;
+
+void newtDefaultPlaceHandler(newtComponent c, int newLeft, int newTop);
+void newtDefaultMappedHandler(newtComponent c, int isMapped);
+struct eventResult newtDefaultEventHandler(newtComponent c,
+ struct event ev);
+
+#endif /* H_NEWT_PR */
diff --git a/mdk-stage1/newt/scale.c b/mdk-stage1/newt/scale.c
new file mode 100644
index 000000000..800958580
--- /dev/null
+++ b/mdk-stage1/newt/scale.c
@@ -0,0 +1,72 @@
+#include <slang.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "newt.h"
+#include "newt_pr.h"
+
+struct scale {
+ int fullValue;
+ int charsSet;
+};
+
+static void scaleDraw(newtComponent co);
+
+static struct componentOps scaleOps = {
+ scaleDraw,
+ newtDefaultEventHandler,
+ NULL,
+ newtDefaultPlaceHandler,
+ newtDefaultMappedHandler,
+} ;
+
+newtComponent newtScale(int left, int top, int width, int fullValue) {
+ newtComponent co;
+ struct scale * sc;
+
+ co = malloc(sizeof(*co));
+ sc = malloc(sizeof(struct scale));
+ co->data = sc;
+
+ co->ops = &scaleOps;
+
+ co->height = 1;
+ co->width = width;
+ co->top = top;
+ co->left = left;
+ co->takesFocus = 0;
+
+ sc->fullValue = fullValue;
+ sc->charsSet = 0;
+
+ return co;
+}
+
+void newtScaleSet(newtComponent co, unsigned int amount) {
+ struct scale * sc = co->data;
+ int newCharsSet;
+
+ newCharsSet = (amount * co->width) / sc->fullValue;
+
+ if (newCharsSet != sc->charsSet) {
+ sc->charsSet = newCharsSet;
+ scaleDraw(co);
+ }
+}
+
+static void scaleDraw(newtComponent co) {
+ struct scale * sc = co->data;
+ int i;
+
+ if (co->top == -1) return;
+
+ newtGotorc(co->top, co->left);
+
+ SLsmg_set_color(NEWT_COLORSET_FULLSCALE);
+ for (i = 0; i < sc->charsSet; i++)
+ SLsmg_write_string(" ");
+
+ SLsmg_set_color(NEWT_COLORSET_EMPTYSCALE);
+ for (i = 0; i < (co->width - sc->charsSet); i++)
+ SLsmg_write_string(" ");
+}
diff --git a/mdk-stage1/newt/scrollbar.c b/mdk-stage1/newt/scrollbar.c
new file mode 100644
index 000000000..cb4bc2757
--- /dev/null
+++ b/mdk-stage1/newt/scrollbar.c
@@ -0,0 +1,124 @@
+#include <slang.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "newt.h"
+#include "newt_pr.h"
+
+struct scrollbar {
+ int curr;
+ int cs, csThumb;
+ int arrows;
+} ;
+
+static void sbDraw(newtComponent co);
+static void sbDestroy(newtComponent co);
+static void sbDrawThumb(newtComponent co, int isOn);
+
+static struct componentOps sbOps = {
+ sbDraw,
+ newtDefaultEventHandler,
+ sbDestroy,
+ newtDefaultPlaceHandler,
+ newtDefaultMappedHandler,
+} ;
+
+void newtScrollbarSet(newtComponent co, int where, int total) {
+ struct scrollbar * sb = co->data;
+ int new;
+
+ if (sb->arrows)
+ new = (where * (co->height - 3)) / (total ? total : 1) + 1;
+ else
+ new = (where * (co->height - 1)) / (total ? total : 1);
+ if (new != sb->curr) {
+ sbDrawThumb(co, 0);
+ sb->curr = new;
+ sbDrawThumb(co, 1);
+ }
+}
+
+newtComponent newtVerticalScrollbar(int left, int top, int height,
+ int normalColorset, int thumbColorset) {
+ newtComponent co;
+ struct scrollbar * sb;
+
+ co = malloc(sizeof(*co));
+ sb = malloc(sizeof(*sb));
+ co->data = sb;
+
+ if (!strcmp(getenv("TERM"), "linux") && height >= 2) {
+ sb->arrows = 1;
+ sb->curr = 1;
+ } else {
+ sb->arrows = 0;
+ sb->curr = 0;
+ }
+ sb->cs = normalColorset;
+ sb->csThumb = thumbColorset;
+
+ co->ops = &sbOps;
+ co->isMapped = 0;
+ co->left = left;
+ co->top = top;
+ co->height = height;
+ co->width = 1;
+ co->takesFocus = 0;
+
+ return co;
+}
+
+static void sbDraw(newtComponent co) {
+ struct scrollbar * sb = co->data;
+ int i;
+
+ if (!co->isMapped) return;
+
+ SLsmg_set_color(sb->cs);
+
+ SLsmg_set_char_set(1);
+ if (sb->arrows) {
+ newtGotorc(co->top, co->left);
+ SLsmg_write_char('\x2d');
+ for (i = 1; i < co->height - 1; i++) {
+ newtGotorc(i + co->top, co->left);
+ SLsmg_write_char('\x61');
+ }
+ newtGotorc(co->top + co->height - 1, co->left);
+ SLsmg_write_char('\x2e');
+ } else {
+ for (i = 0; i < co->height; i++) {
+ newtGotorc(i + co->top, co->left);
+ SLsmg_write_char('\x61');
+ }
+ }
+
+ SLsmg_set_char_set(0);
+
+ sbDrawThumb(co, 1);
+}
+
+static void sbDrawThumb(newtComponent co, int isOn) {
+ struct scrollbar * sb = co->data;
+ char ch = isOn ? '#' : '\x61';
+
+ if (!co->isMapped) return;
+
+ newtGotorc(sb->curr + co->top, co->left);
+ SLsmg_set_char_set(1);
+
+ /*if (isOn)
+ SLsmg_set_color(sb->csThumb);
+ else*/
+ SLsmg_set_color(sb->cs);
+
+ SLsmg_write_char(ch);
+ SLsmg_set_char_set(0);
+}
+
+static void sbDestroy(newtComponent co) {
+ struct scrollbar * sb = co->data;
+
+ free(sb);
+ free(co);
+}
diff --git a/mdk-stage1/newt/textbox.c b/mdk-stage1/newt/textbox.c
new file mode 100644
index 000000000..8eb4ae4db
--- /dev/null
+++ b/mdk-stage1/newt/textbox.c
@@ -0,0 +1,409 @@
+#include <ctype.h>
+#include <slang.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "newt.h"
+#include "newt_pr.h"
+
+struct textbox {
+ char ** lines;
+ int numLines;
+ int linesAlloced;
+ int doWrap;
+ newtComponent sb;
+ int topLine;
+ int textWidth;
+};
+
+static char * expandTabs(const char * text);
+static void textboxDraw(newtComponent co);
+static void addLine(newtComponent co, const char * s, int len);
+static void doReflow(const char * text, char ** resultPtr, int width,
+ int * badness, int * heightPtr);
+static struct eventResult textboxEvent(newtComponent c,
+ struct event ev);
+static void textboxDestroy(newtComponent co);
+static void textboxPlace(newtComponent co, int newLeft, int newTop);
+static void textboxMapped(newtComponent co, int isMapped);
+
+static struct componentOps textboxOps = {
+ textboxDraw,
+ textboxEvent,
+ textboxDestroy,
+ textboxPlace,
+ textboxMapped,
+} ;
+
+static void textboxMapped(newtComponent co, int isMapped) {
+ struct textbox * tb = co->data;
+
+ co->isMapped = isMapped;
+ if (tb->sb)
+ tb->sb->ops->mapped(tb->sb, isMapped);
+}
+
+static void textboxPlace(newtComponent co, int newLeft, int newTop) {
+ struct textbox * tb = co->data;
+
+ co->top = newTop;
+ co->left = newLeft;
+
+ if (tb->sb)
+ tb->sb->ops->place(tb->sb, co->left + co->width - 1, co->top);
+}
+
+void newtTextboxSetHeight(newtComponent co, int height) {
+ co->height = height;
+}
+
+int newtTextboxGetNumLines(newtComponent co) {
+ struct textbox * tb = co->data;
+
+ return (tb->numLines);
+}
+
+newtComponent newtTextboxReflowed(int left, int top, char * text, int width,
+ int flexDown, int flexUp, int flags __attribute__ ((unused))) {
+ newtComponent co;
+ char * reflowedText;
+ int actWidth, actHeight;
+
+ reflowedText = newtReflowText(text, width, flexDown, flexUp,
+ &actWidth, &actHeight);
+
+ co = newtTextbox(left, top, actWidth, actHeight, NEWT_FLAG_WRAP);
+ newtTextboxSetText(co, reflowedText);
+ free(reflowedText);
+
+ return co;
+}
+
+newtComponent newtTextbox(int left, int top, int width, int height, int flags) {
+ newtComponent co;
+ struct textbox * tb;
+
+ co = malloc(sizeof(*co));
+ tb = malloc(sizeof(*tb));
+ co->data = tb;
+
+ co->ops = &textboxOps;
+
+ co->height = height;
+ co->top = top;
+ co->left = left;
+ co->takesFocus = 0;
+ co->width = width;
+
+ tb->doWrap = flags & NEWT_FLAG_WRAP;
+ tb->numLines = 0;
+ tb->linesAlloced = 0;
+ tb->lines = NULL;
+ tb->topLine = 0;
+ tb->textWidth = width;
+
+ if (flags & NEWT_FLAG_SCROLL) {
+ co->width += 2;
+ tb->sb = newtVerticalScrollbar(co->left + co->width - 1, co->top,
+ co->height, COLORSET_TEXTBOX, COLORSET_TEXTBOX);
+ } else {
+ tb->sb = NULL;
+ }
+
+ return co;
+}
+
+static char * expandTabs(const char * text) {
+ int bufAlloced = strlen(text) + 40;
+ char * buf, * dest;
+ const char * src;
+ int bufUsed = 0;
+ int linePos = 0;
+ int i;
+
+ buf = malloc(bufAlloced + 1);
+ for (src = text, dest = buf; *src; src++) {
+ if ((bufUsed + 10) > bufAlloced) {
+ bufAlloced += strlen(text) / 2;
+ buf = realloc(buf, bufAlloced + 1);
+ dest = buf + bufUsed;
+ }
+ if (*src == '\t') {
+ i = 8 - (linePos & 8);
+ memset(dest, ' ', i);
+ dest += i, bufUsed += i, linePos += i;
+ } else {
+ if (*src == '\n')
+ linePos = 0;
+ else
+ linePos++;
+
+ *dest++ = *src;
+ bufUsed++;
+ }
+ }
+
+ *dest = '\0';
+ return buf;
+}
+
+#define iseuckanji(c) (0xa1 <= (unsigned char)(c&0xff) && (unsigned char)(c&0xff) <= 0xfe)
+
+static void doReflow(const char * text, char ** resultPtr, int width,
+ int * badness, int * heightPtr) {
+ char * result = NULL;
+ const char * chptr, * end;
+ int i;
+ int howbad = 0;
+ int height = 0;
+ int kanji = 0;
+
+ if (resultPtr) {
+ /* XXX I think this will work */
+ result = malloc(strlen(text) + (strlen(text) / width) + 50);
+ *result = '\0';
+ }
+
+ while (*text) {
+ kanji = 0;
+ end = strchr(text, '\n');
+ if (!end)
+ end = text + strlen(text);
+
+ while (*text && text < end) {
+ if (end - text < width) {
+ if (result) {
+ strncat(result, text, end - text);
+ strcat(result, "\n");
+ height++;
+ }
+
+ if (end - text < (width / 2))
+ howbad += ((width / 2) - (end - text)) / 2;
+ text = end;
+ if (*text) text++;
+ } else {
+ chptr = text;
+ kanji = 0;
+ for ( i = 0; i < width - 1; i++ ) {
+ if ( !iseuckanji(*chptr)) {
+ kanji = 0;
+ } else if ( kanji == 1 ) {
+ kanji = 2;
+ } else {
+ kanji = 1;
+ }
+ chptr++;
+ }
+ if (kanji == 0) {
+ while (chptr > text && !isspace(*chptr)) chptr--;
+ while (chptr > text && isspace(*chptr)) chptr--;
+ chptr++;
+ }
+
+ if (chptr-text == 1 && !isspace(*chptr))
+ chptr = text + width - 1;
+
+ if (chptr > text)
+ howbad += width - (chptr - text) + 1;
+ if (result) {
+ if (kanji == 1) {
+ strncat(result, text, chptr - text + 1);
+ chptr++;
+ kanji = 0;
+ } else {
+ strncat(result, text, chptr - text);
+ }
+ strcat(result, "\n");
+ height++;
+ }
+
+ if (isspace(*chptr))
+ text = chptr + 1;
+ else
+ text = chptr;
+ while (isspace(*text)) text++;
+ }
+ }
+ }
+
+// if (result) printf("result: %s\n", result);
+
+ if (badness) *badness = howbad;
+ if (resultPtr) *resultPtr = result;
+ if (heightPtr) *heightPtr = height;
+}
+
+char * newtReflowText(char * text, int width, int flexDown, int flexUp,
+ int * actualWidth, int * actualHeight) {
+ int min, max;
+ int i;
+ char * result;
+ int minbad, minbadwidth, howbad;
+ char * expandedText;
+
+ expandedText = expandTabs(text);
+
+ if (flexDown || flexUp) {
+ min = width - flexDown;
+ max = width + flexUp;
+
+ minbad = -1;
+ minbadwidth = width;
+
+ for (i = min; i <= max; i++) {
+ doReflow(expandedText, NULL, i, &howbad, NULL);
+
+ if (minbad == -1 || howbad < minbad) {
+ minbad = howbad;
+ minbadwidth = i;
+ }
+ }
+
+ width = minbadwidth;
+ }
+
+ doReflow(expandedText, &result, width, NULL, actualHeight);
+ free(expandedText);
+ if (actualWidth) *actualWidth = width;
+ return result;
+}
+
+void newtTextboxSetText(newtComponent co, const char * text) {
+ const char * start, * end;
+ struct textbox * tb = co->data;
+ char * reflowed, * expanded;
+ int badness, height;
+
+ if (tb->lines) {
+ free(tb->lines);
+ tb->linesAlloced = tb->numLines = 0;
+ }
+
+ expanded = expandTabs(text);
+
+ if (tb->doWrap) {
+ doReflow(expanded, &reflowed, tb->textWidth, &badness, &height);
+ free(expanded);
+ expanded = reflowed;
+ }
+
+ for (start = expanded; *start; start++)
+ if (*start == '\n') tb->linesAlloced++;
+
+ /* This ++ leaves room for an ending line w/o a \n */
+ tb->linesAlloced++;
+ tb->lines = malloc(sizeof(char *) * tb->linesAlloced);
+
+ start = expanded;
+ while ((end = strchr(start, '\n'))) {
+ addLine(co, start, end - start);
+ start = end + 1;
+ }
+
+ if (*start)
+ addLine(co, start, strlen(start));
+
+ free(expanded);
+}
+
+/* This assumes the buffer is allocated properly! */
+static void addLine(newtComponent co, const char * s, int len) {
+ struct textbox * tb = co->data;
+
+ if (len > tb->textWidth) len = tb->textWidth;
+
+ tb->lines[tb->numLines] = malloc(tb->textWidth + 1);
+ memset(tb->lines[tb->numLines], ' ', tb->textWidth);
+ memcpy(tb->lines[tb->numLines], s, len);
+ tb->lines[tb->numLines++][tb->textWidth] = '\0';
+}
+
+static void textboxDraw(newtComponent c) {
+ int i;
+ struct textbox * tb = c->data;
+ int size;
+
+ if (tb->sb) {
+ size = tb->numLines - c->height;
+ newtScrollbarSet(tb->sb, tb->topLine, size ? size : 0);
+ tb->sb->ops->draw(tb->sb);
+ }
+
+ SLsmg_set_color(NEWT_COLORSET_TEXTBOX);
+
+ for (i = 0; (i + tb->topLine) < tb->numLines && i < c->height; i++) {
+ newtGotorc(c->top + i, c->left);
+ SLsmg_write_string(tb->lines[i + tb->topLine]);
+ }
+}
+
+static struct eventResult textboxEvent(newtComponent co,
+ struct event ev) {
+ struct textbox * tb = co->data;
+ struct eventResult er;
+
+ er.result = ER_IGNORED;
+
+ if (ev.when == EV_EARLY && ev.event == EV_KEYPRESS && tb->sb) {
+ switch (ev.u.key) {
+ case NEWT_KEY_UP:
+ if (tb->topLine) tb->topLine--;
+ textboxDraw(co);
+ er.result = ER_SWALLOWED;
+ break;
+
+ case NEWT_KEY_DOWN:
+ if (tb->topLine < (tb->numLines - co->height)) tb->topLine++;
+ textboxDraw(co);
+ er.result = ER_SWALLOWED;
+ break;
+
+ case NEWT_KEY_PGDN:
+ tb->topLine += co->height;
+ if (tb->topLine > (tb->numLines - co->height)) {
+ tb->topLine = tb->numLines - co->height;
+ if (tb->topLine < 0) tb->topLine = 0;
+ }
+ textboxDraw(co);
+ er.result = ER_SWALLOWED;
+ break;
+
+ case NEWT_KEY_PGUP:
+ tb->topLine -= co->height;
+ if (tb->topLine < 0) tb->topLine = 0;
+ textboxDraw(co);
+ er.result = ER_SWALLOWED;
+ break;
+ }
+ }
+ if (ev.when == EV_EARLY && ev.event == EV_MOUSE && tb->sb) {
+ /* Top scroll arrow */
+ if (ev.u.mouse.x == co->width && ev.u.mouse.y == co->top) {
+ if (tb->topLine) tb->topLine--;
+ textboxDraw(co);
+
+ er.result = ER_SWALLOWED;
+ }
+ /* Bottom scroll arrow */
+ if (ev.u.mouse.x == co->width &&
+ ev.u.mouse.y == co->top + co->height - 1) {
+ if (tb->topLine < (tb->numLines - co->height)) tb->topLine++;
+ textboxDraw(co);
+
+ er.result = ER_SWALLOWED;
+ }
+ }
+ return er;
+}
+
+static void textboxDestroy(newtComponent co) {
+ int i;
+ struct textbox * tb = co->data;
+
+ for (i = 0; i < tb->numLines; i++)
+ free(tb->lines[i]);
+ free(tb->lines);
+ free(tb);
+ free(co);
+}
diff --git a/mdk-stage1/newt/windows.c b/mdk-stage1/newt/windows.c
new file mode 100644
index 000000000..30a8d526c
--- /dev/null
+++ b/mdk-stage1/newt/windows.c
@@ -0,0 +1,275 @@
+#include <errno.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "errno.h"
+#include "newt.h"
+
+static void * newtvwindow(char * title, char * button1, char * button2,
+ char * button3, char * message, va_list args) {
+ newtComponent b1, b2 = NULL, b3 = NULL, t, f, answer;
+ char * buf = NULL;
+ int size = 0;
+ int i = 0;
+ int scroll = 0;
+ int width, height;
+ char * flowedText;
+ newtGrid grid, buttonGrid;
+
+ do {
+ size += 1000;
+ if (buf) free(buf);
+ buf = malloc(size);
+ i = vsnprintf(buf, size, message, args);
+ } while (i >= size || i == -1);
+
+ flowedText = newtReflowText(buf, 50, 5, 5, &width, &height);
+ if (height > 6) {
+ free(flowedText);
+ flowedText = newtReflowText(buf, 60, 5, 5, &width, &height);
+ }
+ free(buf);
+
+ if (height > 12) {
+ height = 12;
+ scroll = NEWT_FLAG_SCROLL;
+ }
+ t = newtTextbox(-1, -1, width, height, NEWT_TEXTBOX_WRAP | scroll);
+ newtTextboxSetText(t, flowedText);
+ free(flowedText);
+
+ if (button3) {
+ buttonGrid = newtButtonBar(button1, &b1, button2, &b2,
+ button3, &b3, NULL);
+ } else if (button2) {
+ buttonGrid = newtButtonBar(button1, &b1, button2, &b2, NULL);
+ } else {
+ buttonGrid = newtButtonBar(button1, &b1, NULL);
+ }
+
+ newtGridSetField(buttonGrid, 0, 0, NEWT_GRID_COMPONENT, b1,
+ 0, 0, button2 ? 1 : 0, 0, 0, 0);
+
+ grid = newtCreateGrid(1, 2);
+ newtGridSetField(grid, 0, 0, NEWT_GRID_COMPONENT, t, 0, 0, 0, 0, 0, 0);
+ newtGridSetField(grid, 0, 1, NEWT_GRID_SUBGRID, buttonGrid,
+ 0, 1, 0, 0, 0, NEWT_GRID_FLAG_GROWX);
+ newtGridWrappedWindow(grid, title);
+
+ f = newtForm(NULL, NULL, 0);
+ newtFormAddComponents(f, t, b1, NULL);
+
+ if (button2)
+ newtFormAddComponent(f, b2);
+ if (button3)
+ newtFormAddComponent(f, b3);
+
+ answer = newtRunForm(f);
+ newtGridFree(grid, 1);
+
+ newtFormDestroy(f);
+ newtPopWindow();
+
+ if (answer == f)
+ return NULL;
+ else if (answer == b1)
+ return button1;
+ else if (answer == b2)
+ return button2;
+
+ return button3;
+}
+
+int newtWinChoice(char * title, char * button1, char * button2,
+ char * message, ...) {
+ va_list args;
+ void * rc;
+
+ va_start(args, message);
+ rc = newtvwindow(title, button1, button2, NULL, message, args);
+ va_end(args);
+
+ if (rc == button1)
+ return 1;
+ else if (rc == button2)
+ return 2;
+
+ return 0;
+}
+
+void newtWinMessage(char * title, char * buttonText, char * text, ...) {
+ va_list args;
+
+ va_start(args, text);
+ newtvwindow(title, buttonText, NULL, NULL, text, args);
+ va_end(args);
+}
+
+void newtWinMessagev(char * title, char * buttonText, char * text,
+ va_list argv) {
+ newtvwindow(title, buttonText, NULL, NULL, text, argv);
+}
+
+int newtWinTernary(char * title, char * button1, char * button2,
+ char * button3, char * message, ...) {
+ va_list args;
+ void * rc;
+
+ va_start(args, message);
+ rc = newtvwindow(title, button1, button2, button3, message, args);
+ va_end(args);
+
+ if (rc == button1)
+ return 1;
+ else if (rc == button2)
+ return 2;
+ else if (rc == button3)
+ return 3;
+
+ return 0;
+}
+
+/* only supports up to 50 buttons -- shucks! */
+int newtWinMenu(char * title, char * text, int suggestedWidth, int flexDown,
+ int flexUp, int maxListHeight, char ** items, int * listItem,
+ char * button1, ...) {
+ newtComponent textbox, listbox, result, form;
+ va_list args;
+ newtComponent buttons[50];
+ newtGrid grid, buttonBar;
+ int numButtons;
+ int i, rc;
+ int needScroll;
+ char * buttonName;
+
+ textbox = newtTextboxReflowed(-1, -1, text, suggestedWidth, flexDown,
+ flexUp, 0);
+
+ for (i = 0; items[i]; i++) ;
+ if (i < maxListHeight) maxListHeight = i;
+ needScroll = i > maxListHeight;
+
+ listbox = newtListbox(-1, -1, maxListHeight,
+ (needScroll ? NEWT_FLAG_SCROLL : 0) | NEWT_FLAG_RETURNEXIT);
+ for (i = 0; items[i]; i++) {
+ newtListboxAddEntry(listbox, items[i], (void *) (long)i);
+ }
+
+ newtListboxSetCurrent(listbox, *listItem);
+
+ buttonName = button1, numButtons = 0;
+ va_start(args, button1);
+ while (buttonName) {
+ buttons[numButtons] = newtButton(-1, -1, buttonName);
+ numButtons++;
+ buttonName = va_arg(args, char *);
+ }
+
+ va_end(args);
+
+ buttonBar = newtCreateGrid(numButtons, 1);
+ for (i = 0; i < numButtons; i++) {
+ newtGridSetField(buttonBar, i, 0, NEWT_GRID_COMPONENT,
+ buttons[i],
+ i ? 1 : 0, 0, 0, 0, 0, 0);
+ }
+
+ grid = newtGridSimpleWindow(textbox, listbox, buttonBar);
+ newtGridWrappedWindow(grid, title);
+
+ form = newtForm(NULL, 0, 0);
+ newtGridAddComponentsToForm(grid, form, 1);
+ newtGridFree(grid, 1);
+
+ result = newtRunForm(form);
+
+ *listItem = ((long) newtListboxGetCurrent(listbox));
+
+ for (rc = 0; result != buttons[rc] && rc < numButtons; rc++);
+ if (rc == numButtons)
+ rc = 0; /* F12 or return-on-exit (which are the same for us) */
+ else
+ rc++;
+
+ newtFormDestroy(form);
+ newtPopWindow();
+
+ return rc;
+}
+
+/* only supports up to 50 buttons and entries -- shucks! */
+int newtWinEntries(char * title, char * text, int suggestedWidth, int flexDown,
+ int flexUp, int dataWidth,
+ struct newtWinEntry * items, char * button1, ...) {
+ newtComponent buttons[50], result, form, textw;
+ newtGrid grid, buttonBar, subgrid;
+ int numItems;
+ int rc, i;
+ int numButtons;
+ char * buttonName;
+ va_list args;
+
+ textw = newtTextboxReflowed(-1, -1, text, suggestedWidth, flexDown,
+ flexUp, 0);
+
+ for (numItems = 0; items[numItems].text; numItems++);
+
+ buttonName = button1, numButtons = 0;
+ va_start(args, button1);
+ while (buttonName) {
+ buttons[numButtons] = newtButton(-1, -1, buttonName);
+ numButtons++;
+ buttonName = va_arg(args, char *);
+ }
+
+ va_end(args);
+
+ buttonBar = newtCreateGrid(numButtons, 1);
+ for (i = 0; i < numButtons; i++) {
+ newtGridSetField(buttonBar, i, 0, NEWT_GRID_COMPONENT,
+ buttons[i],
+ i ? 1 : 0, 0, 0, 0, 0, 0);
+ }
+
+ subgrid = newtCreateGrid(2, numItems);
+ for (i = 0; i < numItems; i++) {
+ newtGridSetField(subgrid, 0, i, NEWT_GRID_COMPONENT,
+ newtLabel(-1, -1, items[i].text),
+ 0, 0, 0, 0, NEWT_ANCHOR_LEFT, 0);
+ newtGridSetField(subgrid, 1, i, NEWT_GRID_COMPONENT,
+ newtEntry(-1, -1, items[i].value ?
+ *items[i].value : NULL, dataWidth,
+ items[i].value, items[i].flags),
+ 1, 0, 0, 0, 0, 0);
+ }
+
+ grid = newtCreateGrid(1, 3);
+ form = newtForm(NULL, 0, 0);
+ newtGridSetField(grid, 0, 0, NEWT_GRID_COMPONENT, textw,
+ 0, 0, 0, 0, NEWT_ANCHOR_LEFT, 0);
+ newtGridSetField(grid, 0, 1, NEWT_GRID_SUBGRID, subgrid,
+ 0, 1, 0, 0, 0, 0);
+ newtGridSetField(grid, 0, 2, NEWT_GRID_SUBGRID, buttonBar,
+ 0, 1, 0, 0, 0, NEWT_GRID_FLAG_GROWX);
+ newtGridAddComponentsToForm(grid, form, 1);
+ newtGridWrappedWindow(grid, title);
+ newtGridFree(grid, 1);
+
+ result = newtRunForm(form);
+
+ for (rc = 0; rc < numItems; rc++)
+ *items[rc].value = strdup(*items[rc].value);
+
+ for (rc = 0; result != buttons[rc] && rc < numButtons; rc++);
+ if (rc == numButtons)
+ rc = 0; /* F12 */
+ else
+ rc++;
+
+ newtFormDestroy(form);
+ newtPopWindow();
+
+ return rc;
+}
diff --git a/mdk-stage1/nfs_mount4.h b/mdk-stage1/nfs_mount4.h
new file mode 100644
index 000000000..85650773a
--- /dev/null
+++ b/mdk-stage1/nfs_mount4.h
@@ -0,0 +1,54 @@
+/*
+ * We want to be able to compile mount on old kernels in such a way
+ * that the binary will work well on more recent kernels.
+ * Thus, if necessary we teach nfsmount.c the structure of new fields
+ * that will come later.
+ *
+ * Moreover, the new kernel includes conflict with glibc includes
+ * so it is easiest to ignore the kernel altogether (at compile time).
+ */
+
+#define NFS_MOUNT_VERSION 4
+
+struct nfs2_fh {
+ char data[32];
+};
+struct nfs3_fh {
+ unsigned short size;
+ unsigned char data[64];
+};
+
+struct nfs_mount_data {
+ int version; /* 1 */
+ int fd; /* 1 */
+ struct nfs2_fh old_root; /* 1 */
+ int flags; /* 1 */
+ int rsize; /* 1 */
+ int wsize; /* 1 */
+ int timeo; /* 1 */
+ int retrans; /* 1 */
+ int acregmin; /* 1 */
+ int acregmax; /* 1 */
+ int acdirmin; /* 1 */
+ int acdirmax; /* 1 */
+ struct sockaddr_in addr; /* 1 */
+ char hostname[256]; /* 1 */
+ int namlen; /* 2 */
+ unsigned int bsize; /* 3 */
+ struct nfs3_fh root; /* 4 */
+};
+
+/* bits in the flags field */
+
+#define NFS_MOUNT_SOFT 0x0001 /* 1 */
+#define NFS_MOUNT_INTR 0x0002 /* 1 */
+#define NFS_MOUNT_SECURE 0x0004 /* 1 */
+#define NFS_MOUNT_POSIX 0x0008 /* 1 */
+#define NFS_MOUNT_NOCTO 0x0010 /* 1 */
+#define NFS_MOUNT_NOAC 0x0020 /* 1 */
+#define NFS_MOUNT_TCP 0x0040 /* 2 */
+#define NFS_MOUNT_VER3 0x0080 /* 3 */
+#define NFS_MOUNT_KERBEROS 0x0100 /* 3 */
+#define NFS_MOUNT_NONLM 0x0200 /* 3 */
+#define NFS_MOUNT_BROKEN_SUID 0x0400 /* 4 */
+
diff --git a/mdk-stage1/nfsmount.c b/mdk-stage1/nfsmount.c
new file mode 100644
index 000000000..ce329d43c
--- /dev/null
+++ b/mdk-stage1/nfsmount.c
@@ -0,0 +1,740 @@
+ /*
+ * Guillaume Cottenceau (gc@mandrakesoft.com)
+ *
+ * Copyright 2003 Mandrakesoft
+ *
+ * This software may be freely redistributed under the terms of the GNU
+ * public license.
+ *
+ * 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.
+ *
+ * basing on nfsmount.c from util-linux-2.11z:
+ * - use our logging facilities
+ * - use our host resolving stuff
+ * - remove unneeded code
+ */
+
+/*
+ * nfsmount.c -- Linux NFS mount
+ * Copyright (C) 1993 Rick Sladkey <jrs@world.std.com>
+ *
+ * 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, 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.
+ *
+ * Wed Feb 8 12:51:48 1995, biro@yggdrasil.com (Ross Biro): allow all port
+ * numbers to be specified on the command line.
+ *
+ * Fri, 8 Mar 1996 18:01:39, Swen Thuemmler <swen@uni-paderborn.de>:
+ * Omit the call to connect() for Linux version 1.3.11 or later.
+ *
+ * Wed Oct 1 23:55:28 1997: Dick Streefland <dick_streefland@tasking.com>
+ * Implemented the "bg", "fg" and "retry" mount options for NFS.
+ *
+ * 1999-02-22 Arkadiusz Miśkiewicz <misiek@pld.ORG.PL>
+ * - added Native Language Support
+ *
+ * Modified by Olaf Kirch and Trond Myklebust for new NFS code,
+ * plus NFSv3 stuff.
+ *
+ * 2003-04-14 David Black <david.black@xilinx.com>
+ * - added support for multiple hostname NFS mounts
+ */
+
+/*
+ * nfsmount.c,v 1.1.1.1 1993/11/18 08:40:51 jrs Exp
+ */
+
+#define HAVE_rpcsvc_nfs_prot_h
+#define HAVE_inet_aton
+
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <netdb.h>
+#include <time.h>
+#include <rpc/rpc.h>
+#include <rpc/pmap_prot.h>
+#include <rpc/pmap_clnt.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/utsname.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <values.h>
+
+#include "nfsmount.h"
+
+#ifdef HAVE_rpcsvc_nfs_prot_h
+#include <rpcsvc/nfs_prot.h>
+#else
+#include <linux/nfs.h>
+#define nfsstat nfs_stat
+#endif
+
+#include "nfs_mount4.h"
+
+#include "log.h"
+#include "dns.h"
+
+#ifndef NFS_PORT
+#define NFS_PORT 2049
+#endif
+#ifndef NFS_FHSIZE
+#define NFS_FHSIZE 32
+#endif
+
+static char *nfs_strerror(int stat);
+
+#define MAKE_VERSION(p,q,r) (65536*(p) + 256*(q) + (r))
+
+#define MAX_NFSPROT ((nfs_mount_version >= 4) ? 3 : 2)
+
+bool_t
+xdr_fhandle3 (XDR *xdrs, fhandle3 *objp)
+{
+ if (!xdr_bytes (xdrs, (char **)&objp->fhandle3_val, (u_int *) &objp->fhandle3_len, FHSIZE3))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_mountstat3 (XDR *xdrs, mountstat3 *objp)
+{
+ if (!xdr_enum (xdrs, (enum_t *) objp))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_mountres3_ok (XDR *xdrs, mountres3_ok *objp)
+{
+ if (!xdr_fhandle3 (xdrs, &objp->fhandle))
+ return FALSE;
+ if (!xdr_array (xdrs, (char **)&objp->auth_flavours.auth_flavours_val, (u_int *) &objp->auth_flavours.auth_flavours_len, ~0,
+ sizeof (int), (xdrproc_t) xdr_int))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_mountres3 (XDR *xdrs, mountres3 *objp)
+{
+ if (!xdr_mountstat3 (xdrs, &objp->fhs_status))
+ return FALSE;
+ switch (objp->fhs_status) {
+ case MNT_OK:
+ if (!xdr_mountres3_ok (xdrs, &objp->mountres3_u.mountinfo))
+ return FALSE;
+ break;
+ default:
+ break;
+ }
+ return TRUE;
+}
+
+bool_t
+xdr_dirpath (XDR *xdrs, dirpath *objp)
+{
+ if (!xdr_string (xdrs, objp, MNTPATHLEN))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_fhandle (XDR *xdrs, fhandle objp)
+{
+ if (!xdr_opaque (xdrs, objp, FHSIZE))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_fhstatus (XDR *xdrs, fhstatus *objp)
+{
+ if (!xdr_u_int (xdrs, &objp->fhs_status))
+ return FALSE;
+ switch (objp->fhs_status) {
+ case 0:
+ if (!xdr_fhandle (xdrs, objp->fhstatus_u.fhs_fhandle))
+ return FALSE;
+ break;
+ default:
+ break;
+ }
+ return TRUE;
+}
+
+
+static int
+linux_version_code(void) {
+ struct utsname my_utsname;
+ int p, q, r;
+
+ if (uname(&my_utsname) == 0) {
+ p = atoi(strtok(my_utsname.release, "."));
+ q = atoi(strtok(NULL, "."));
+ r = atoi(strtok(NULL, "."));
+ return MAKE_VERSION(p,q,r);
+ }
+ return 0;
+}
+
+/*
+ * Unfortunately, the kernel prints annoying console messages
+ * in case of an unexpected nfs mount version (instead of
+ * just returning some error). Therefore we'll have to try
+ * and figure out what version the kernel expects.
+ *
+ * Variables:
+ * NFS_MOUNT_VERSION: these nfsmount sources at compile time
+ * nfs_mount_version: version this source and running kernel can handle
+ */
+static int
+find_kernel_nfs_mount_version(void) {
+ static int kernel_version = -1;
+ int nfs_mount_version = NFS_MOUNT_VERSION;
+
+ if (kernel_version == -1)
+ kernel_version = linux_version_code();
+
+ if (kernel_version) {
+ if (kernel_version < MAKE_VERSION(2,1,32))
+ nfs_mount_version = 1;
+ else if (kernel_version < MAKE_VERSION(2,2,18))
+ nfs_mount_version = 3;
+ else if (kernel_version < MAKE_VERSION(2,3,0))
+ nfs_mount_version = 4; /* since 2.2.18pre9 */
+ else if (kernel_version < MAKE_VERSION(2,3,99))
+ nfs_mount_version = 3;
+ else
+ nfs_mount_version = 4; /* since 2.3.99pre4 */
+ }
+ if (nfs_mount_version > NFS_MOUNT_VERSION)
+ nfs_mount_version = NFS_MOUNT_VERSION;
+ log_message("nfsmount: kernel_nfs_mount_version: %d", nfs_mount_version);
+ return nfs_mount_version;
+}
+
+static struct pmap *
+get_mountport(struct sockaddr_in *server_addr,
+ long unsigned prog,
+ long unsigned version,
+ long unsigned proto,
+ long unsigned port,
+ int nfs_mount_version)
+{
+ struct pmaplist *pmap;
+ static struct pmap p = {0, 0, 0, 0};
+
+ if (version > MAX_NFSPROT)
+ version = MAX_NFSPROT;
+ if (!prog)
+ prog = MOUNTPROG;
+ p.pm_prog = prog;
+ p.pm_vers = version;
+ p.pm_prot = proto;
+ p.pm_port = port;
+
+ server_addr->sin_port = PMAPPORT;
+ pmap = pmap_getmaps(server_addr);
+
+ while (pmap) {
+ if (pmap->pml_map.pm_prog != prog)
+ goto next;
+ if (!version && p.pm_vers > pmap->pml_map.pm_vers)
+ goto next;
+ if (version > 2 && pmap->pml_map.pm_vers != version)
+ goto next;
+ if (version && version <= 2 && pmap->pml_map.pm_vers > 2)
+ goto next;
+ if (pmap->pml_map.pm_vers > MAX_NFSPROT ||
+ (proto && p.pm_prot && pmap->pml_map.pm_prot != proto) ||
+ (port && pmap->pml_map.pm_port != port))
+ goto next;
+ memcpy(&p, &pmap->pml_map, sizeof(p));
+ next:
+ pmap = pmap->pml_next;
+ }
+ if (!p.pm_vers)
+ p.pm_vers = MOUNTVERS;
+ if (!p.pm_prot)
+ p.pm_prot = IPPROTO_TCP;
+ return &p;
+}
+
+
+
+int nfsmount_prepare(const char *spec, char **mount_opts)
+{
+ char hostdir[1024];
+ CLIENT *mclient;
+ char *hostname, *dirname, *mounthost = NULL;
+ struct timeval total_timeout;
+ enum clnt_stat clnt_stat;
+ static struct nfs_mount_data data;
+ int nfs_mount_version;
+ int val;
+ struct sockaddr_in server_addr;
+ struct sockaddr_in mount_server_addr;
+ struct pmap *pm_mnt;
+ int msock, fsock;
+ struct timeval retry_timeout;
+ union {
+ struct fhstatus nfsv2;
+ struct mountres3 nfsv3;
+ } status;
+ char *s;
+ int port, mountport, proto, soft, intr;
+ int posix, nocto, noac, broken_suid, nolock;
+ int retry, tcp;
+ int mountprog, mountvers, nfsprog, nfsvers;
+ int retval;
+ time_t t;
+ time_t prevt;
+ time_t timeout;
+
+ nfs_mount_version = find_kernel_nfs_mount_version();
+
+ retval = -1;
+ msock = fsock = -1;
+ mclient = NULL;
+ if (strlen(spec) >= sizeof(hostdir)) {
+ log_message("nfsmount: excessively long host:dir argument");
+ goto fail;
+ }
+ strcpy(hostdir, spec);
+ if ((s = strchr(hostdir, ':'))) {
+ hostname = hostdir;
+ dirname = s + 1;
+ *s = '\0';
+ } else {
+ log_message("nfsmount: directory to mount not in host:dir format");
+ goto fail;
+ }
+
+ server_addr.sin_family = AF_INET;
+#ifdef HAVE_inet_aton
+ if (!inet_aton(hostname, &server_addr.sin_addr))
+#endif
+ {
+ if (mygethostbyname(hostname, &server_addr.sin_addr)) {
+ log_message("nfsmount: can't get address for %s", hostname);
+ goto fail;
+ }
+ }
+
+ memcpy (&mount_server_addr, &server_addr, sizeof (mount_server_addr));
+
+
+
+ /* Set default options.
+ * rsize/wsize are set to 8192 to enable nfs install on
+ * old i586 machines
+ * timeo is filled in after we know whether it'll be TCP or UDP. */
+ memset(&data, 0, sizeof(data));
+ data.rsize = 8192;
+ data.wsize = 8192;
+ data.retrans = 30;
+ data.acregmin = 3;
+ data.acregmax = 60;
+ data.acdirmin = 30;
+ data.acdirmax = 60;
+#if NFS_MOUNT_VERSION >= 2
+ data.namlen = NAME_MAX;
+#endif
+
+ soft = 1;
+ intr = 0;
+ posix = 0;
+ nocto = 0;
+ nolock = 1;
+ broken_suid = 0;
+ noac = 0;
+ retry = 10000; /* 10000 minutes ~ 1 week */
+ tcp = 0;
+
+ mountprog = MOUNTPROG;
+ mountvers = 0;
+ port = 0;
+ mountport = 0;
+ nfsprog = NFS_PROGRAM;
+ nfsvers = 0;
+
+
+
+retry_mount:
+ proto = (tcp) ? IPPROTO_TCP : IPPROTO_UDP;
+
+ data.flags = (soft ? NFS_MOUNT_SOFT : 0)
+ | (intr ? NFS_MOUNT_INTR : 0)
+ | (posix ? NFS_MOUNT_POSIX : 0)
+ | (nocto ? NFS_MOUNT_NOCTO : 0)
+ | (noac ? NFS_MOUNT_NOAC : 0);
+#if NFS_MOUNT_VERSION >= 2
+ if (nfs_mount_version >= 2)
+ data.flags |= (tcp ? NFS_MOUNT_TCP : 0);
+#endif
+#if NFS_MOUNT_VERSION >= 3
+ if (nfs_mount_version >= 3)
+ data.flags |= (nolock ? NFS_MOUNT_NONLM : 0);
+#endif
+#if NFS_MOUNT_VERSION >= 4
+ if (nfs_mount_version >= 4)
+ data.flags |= (broken_suid ? NFS_MOUNT_BROKEN_SUID : 0);
+#endif
+ if (nfsvers > MAX_NFSPROT) {
+ log_message("NFSv%d not supported!", nfsvers);
+ return 0;
+ }
+ if (mountvers > MAX_NFSPROT) {
+ log_message("NFSv%d not supported!", nfsvers);
+ return 0;
+ }
+ if (nfsvers && !mountvers)
+ mountvers = (nfsvers < 3) ? 1 : nfsvers;
+ if (nfsvers && nfsvers < mountvers)
+ mountvers = nfsvers;
+
+ /* Adjust options if none specified */
+ if (!data.timeo)
+ data.timeo = tcp ? 70 : 7;
+
+#ifdef NFS_MOUNT_DEBUG
+ log_message("rsize = %d, wsize = %d, timeo = %d, retrans = %d",
+ data.rsize, data.wsize, data.timeo, data.retrans);
+ log_message("acreg (min, max) = (%d, %d), acdir (min, max) = (%d, %d)",
+ data.acregmin, data.acregmax, data.acdirmin, data.acdirmax);
+ log_message("port = %d, retry = %d, flags = %.8x",
+ port, retry, data.flags);
+ log_message("mountprog = %d, mountvers = %d, nfsprog = %d, nfsvers = %d",
+ mountprog, mountvers, nfsprog, nfsvers);
+ log_message("soft = %d, intr = %d, posix = %d, nocto = %d, noac = %d",
+ (data.flags & NFS_MOUNT_SOFT) != 0,
+ (data.flags & NFS_MOUNT_INTR) != 0,
+ (data.flags & NFS_MOUNT_POSIX) != 0,
+ (data.flags & NFS_MOUNT_NOCTO) != 0,
+ (data.flags & NFS_MOUNT_NOAC) != 0);
+#if NFS_MOUNT_VERSION >= 2
+ log_message("tcp = %d",
+ (data.flags & NFS_MOUNT_TCP) != 0);
+#endif
+#endif
+
+ data.version = nfs_mount_version;
+ *mount_opts = (char *) &data;
+
+
+ /* create mount deamon client */
+ /* See if the nfs host = mount host. */
+ if (mounthost) {
+ if (mounthost[0] >= '0' && mounthost[0] <= '9') {
+ mount_server_addr.sin_family = AF_INET;
+ mount_server_addr.sin_addr.s_addr = inet_addr(hostname);
+ } else {
+ if (mygethostbyname(mounthost, &mount_server_addr.sin_addr)) {
+ log_message("nfsmount: can't get address for %s", mounthost);
+ goto fail;
+ }
+ }
+ }
+
+ /*
+ * The following loop implements the mount retries. On the first
+ * call, "running_bg" is 0. When the mount times out, and the
+ * "bg" option is set, the exit status EX_BG will be returned.
+ * For a backgrounded mount, there will be a second call by the
+ * child process with "running_bg" set to 1.
+ *
+ * The case where the mount point is not present and the "bg"
+ * option is set, is treated as a timeout. This is done to
+ * support nested mounts.
+ *
+ * The "retry" count specified by the user is the number of
+ * minutes to retry before giving up.
+ *
+ * Only the first error message will be displayed.
+ */
+ retry_timeout.tv_sec = 3;
+ retry_timeout.tv_usec = 0;
+ total_timeout.tv_sec = 20;
+ total_timeout.tv_usec = 0;
+ timeout = time(NULL) + 60 * retry;
+ prevt = 0;
+ t = 30;
+ val = 1;
+
+
+ /* be careful not to use too many CPU cycles */
+ if (t - prevt < 30)
+ sleep(30);
+
+ pm_mnt = get_mountport(&mount_server_addr,
+ mountprog,
+ mountvers,
+ proto,
+ mountport,
+ nfs_mount_version);
+
+ /* contact the mount daemon via TCP */
+ mount_server_addr.sin_port = htons(pm_mnt->pm_port);
+ msock = RPC_ANYSOCK;
+
+ switch (pm_mnt->pm_prot) {
+ case IPPROTO_UDP:
+ mclient = clntudp_create(&mount_server_addr,
+ pm_mnt->pm_prog,
+ pm_mnt->pm_vers,
+ retry_timeout,
+ &msock);
+ if (mclient)
+ break;
+ mount_server_addr.sin_port =
+ htons(pm_mnt->pm_port);
+ msock = RPC_ANYSOCK;
+ case IPPROTO_TCP:
+ mclient = clnttcp_create(&mount_server_addr,
+ pm_mnt->pm_prog,
+ pm_mnt->pm_vers,
+ &msock, 0, 0);
+ break;
+ default:
+ mclient = 0;
+ }
+
+ if (mclient) {
+ /* try to mount hostname:dirname */
+ mclient->cl_auth = authunix_create_default();
+
+ /* make pointers in xdr_mountres3 NULL so
+ * that xdr_array allocates memory for us
+ */
+ memset(&status, 0, sizeof(status));
+
+ log_message("nfsmount: doing client call in nfs version: %ld", pm_mnt->pm_vers);
+ if (pm_mnt->pm_vers == 3)
+ clnt_stat = clnt_call(mclient,
+ MOUNTPROC3_MNT,
+ (xdrproc_t) xdr_dirpath,
+ (caddr_t) &dirname,
+ (xdrproc_t) xdr_mountres3,
+ (caddr_t) &status,
+ total_timeout);
+ else
+ clnt_stat = clnt_call(mclient,
+ MOUNTPROC_MNT,
+ (xdrproc_t) xdr_dirpath,
+ (caddr_t) &dirname,
+ (xdrproc_t) xdr_fhstatus,
+ (caddr_t) &status,
+ total_timeout);
+
+ if (clnt_stat == RPC_SUCCESS)
+ goto succeeded;
+
+ if (prevt == 0)
+ log_message("could not call server: probably protocol or version error");
+ auth_destroy(mclient->cl_auth);
+ clnt_destroy(mclient);
+ mclient = 0;
+ close(msock);
+ } else {
+ log_message("could not create rpc client: host probably not found or NFS server is down");
+ }
+ prevt = t;
+
+ goto fail;
+
+ succeeded:
+ nfsvers = (pm_mnt->pm_vers < 2) ? 2 : pm_mnt->pm_vers;
+
+ if (nfsvers == 2) {
+ if (status.nfsv2.fhs_status != 0) {
+ log_message("nfsmount: %s:%s failed, reason given by server: %s",
+ hostname, dirname, nfs_strerror(status.nfsv2.fhs_status));
+ goto fail;
+ }
+ memcpy(data.root.data,
+ (char *) status.nfsv2.fhstatus_u.fhs_fhandle,
+ NFS_FHSIZE);
+#if NFS_MOUNT_VERSION >= 4
+ data.root.size = NFS_FHSIZE;
+ memcpy(data.old_root.data,
+ (char *) status.nfsv2.fhstatus_u.fhs_fhandle,
+ NFS_FHSIZE);
+#endif
+ } else {
+#if NFS_MOUNT_VERSION >= 4
+ fhandle3 *fhandle;
+ if (status.nfsv3.fhs_status != 0) {
+ log_message("nfsmount: %s:%s failed, reason given by server: %s",
+ hostname, dirname, nfs_strerror(status.nfsv3.fhs_status));
+ goto fail;
+ }
+ fhandle = &status.nfsv3.mountres3_u.mountinfo.fhandle;
+ memset(data.old_root.data, 0, NFS_FHSIZE);
+ memset(&data.root, 0, sizeof(data.root));
+ data.root.size = fhandle->fhandle3_len;
+ memcpy(data.root.data,
+ (char *) fhandle->fhandle3_val,
+ fhandle->fhandle3_len);
+
+ data.flags |= NFS_MOUNT_VER3;
+#endif
+ }
+
+ /* create nfs socket for kernel */
+
+ if (tcp) {
+ if (nfs_mount_version < 3) {
+ log_message("NFS over TCP is not supported.");
+ goto fail;
+ }
+ fsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ } else
+ fsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ if (fsock < 0) {
+ log_perror("nfs socket");
+ goto fail;
+ }
+ if (bindresvport(fsock, 0) < 0) {
+ log_perror("nfs bindresvport");
+ goto fail;
+ }
+ if (port == 0) {
+ server_addr.sin_port = PMAPPORT;
+ port = pmap_getport(&server_addr, nfsprog, nfsvers,
+ tcp ? IPPROTO_TCP : IPPROTO_UDP);
+#if 1
+ /* Here we check to see if user is mounting with the
+ * tcp option. If so, and if the portmap returns a
+ * '0' for port (service unavailable), we then notify
+ * the user, and retry with udp.
+ */
+ if (port == 0 && tcp == 1) {
+ log_message("NFS server reported TCP not available, retrying with UDP...");
+ tcp = 0;
+ goto retry_mount;
+ }
+#endif
+
+ if (port == 0)
+ port = NFS_PORT;
+#ifdef NFS_MOUNT_DEBUG
+ else
+ log_message("used portmapper to find NFS port");
+#endif
+ }
+#ifdef NFS_MOUNT_DEBUG
+ log_message("using port %d for nfs deamon", port);
+#endif
+ server_addr.sin_port = htons(port);
+ /*
+ * connect() the socket for kernels 1.3.10 and below only,
+ * to avoid problems with multihomed hosts.
+ * --Swen
+ */
+ if (linux_version_code() <= 66314
+ && connect(fsock, (struct sockaddr *) &server_addr,
+ sizeof (server_addr)) < 0) {
+ log_perror("nfs connect");
+ goto fail;
+ }
+
+ /* prepare data structure for kernel */
+
+ data.fd = fsock;
+ memcpy((char *) &data.addr, (char *) &server_addr, sizeof(data.addr));
+ strncpy(data.hostname, hostname, sizeof(data.hostname));
+
+ /* clean up */
+
+ auth_destroy(mclient->cl_auth);
+ clnt_destroy(mclient);
+ close(msock);
+ return 0;
+
+ /* abort */
+
+ fail:
+ if (msock != -1) {
+ if (mclient) {
+ auth_destroy(mclient->cl_auth);
+ clnt_destroy(mclient);
+ }
+ close(msock);
+ }
+ if (fsock != -1)
+ close(fsock);
+ return retval;
+}
+
+/*
+ * We need to translate between nfs status return values and
+ * the local errno values which may not be the same.
+ *
+ * Andreas Schwab <schwab@LS5.informatik.uni-dortmund.de>: change errno:
+ * "after #include <errno.h> the symbol errno is reserved for any use,
+ * it cannot even be used as a struct tag or field name".
+ */
+
+#ifndef EDQUOT
+#define EDQUOT ENOSPC
+#endif
+
+static struct {
+ enum nfsstat stat;
+ int errnum;
+} nfs_errtbl[] = {
+ { NFS_OK, 0 },
+ { NFSERR_PERM, EPERM },
+ { NFSERR_NOENT, ENOENT },
+ { NFSERR_IO, EIO },
+ { NFSERR_NXIO, ENXIO },
+ { NFSERR_ACCES, EACCES },
+ { NFSERR_EXIST, EEXIST },
+ { NFSERR_NODEV, ENODEV },
+ { NFSERR_NOTDIR, ENOTDIR },
+ { NFSERR_ISDIR, EISDIR },
+#ifdef NFSERR_INVAL
+ { NFSERR_INVAL, EINVAL }, /* that Sun forgot */
+#endif
+ { NFSERR_FBIG, EFBIG },
+ { NFSERR_NOSPC, ENOSPC },
+ { NFSERR_ROFS, EROFS },
+ { NFSERR_NAMETOOLONG, ENAMETOOLONG },
+ { NFSERR_NOTEMPTY, ENOTEMPTY },
+ { NFSERR_DQUOT, EDQUOT },
+ { NFSERR_STALE, ESTALE },
+#ifdef EWFLUSH
+ { NFSERR_WFLUSH, EWFLUSH },
+#endif
+ /* Throw in some NFSv3 values for even more fun (HP returns these) */
+ { 71, EREMOTE },
+
+ { -1, EIO }
+};
+
+static char *nfs_strerror(int stat)
+{
+ int i;
+ static char buf[256];
+
+ for (i = 0; nfs_errtbl[i].stat != (unsigned)-1; i++) {
+ if (nfs_errtbl[i].stat == (unsigned)stat)
+ return strerror(nfs_errtbl[i].errnum);
+ }
+ sprintf(buf, "unknown nfs status return value: %d", stat);
+ return buf;
+}
+
diff --git a/mdk-stage1/nfsmount.h b/mdk-stage1/nfsmount.h
new file mode 100644
index 000000000..a27e8a8d7
--- /dev/null
+++ b/mdk-stage1/nfsmount.h
@@ -0,0 +1,331 @@
+/*
+ * Please do not edit this file.
+ * It was generated using rpcgen.
+ */
+
+#ifndef _NFSMOUNT_H_RPCGEN
+#define _NFSMOUNT_H_RPCGEN
+
+#include <rpc/rpc.h>
+
+int nfsmount_prepare(const char *spec, char **mount_opts);
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user or with the express written consent of
+ * Sun Microsystems, Inc.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+/*
+ * Copyright (c) 1985, 1990 by Sun Microsystems, Inc.
+ */
+
+/* from @(#)mount.x 1.3 91/03/11 TIRPC 1.0 */
+#ifndef _rpcsvc_mount_h
+#define _rpcsvc_mount_h
+#include <asm/types.h>
+#define MNTPATHLEN 1024
+#define MNTNAMLEN 255
+#define FHSIZE 32
+#define FHSIZE3 64
+
+typedef char fhandle[FHSIZE];
+
+typedef struct {
+ u_int fhandle3_len;
+ char *fhandle3_val;
+} fhandle3;
+
+enum mountstat3 {
+ MNT_OK = 0,
+ MNT3ERR_PERM = 1,
+ MNT3ERR_NOENT = 2,
+ MNT3ERR_IO = 5,
+ MNT3ERR_ACCES = 13,
+ MNT3ERR_NOTDIR = 20,
+ MNT3ERR_INVAL = 22,
+ MNT3ERR_NAMETOOLONG = 63,
+ MNT3ERR_NOTSUPP = 10004,
+ MNT3ERR_SERVERFAULT = 10006,
+};
+typedef enum mountstat3 mountstat3;
+
+struct fhstatus {
+ u_int fhs_status;
+ union {
+ fhandle fhs_fhandle;
+ } fhstatus_u;
+};
+typedef struct fhstatus fhstatus;
+
+struct mountres3_ok {
+ fhandle3 fhandle;
+ struct {
+ u_int auth_flavours_len;
+ int *auth_flavours_val;
+ } auth_flavours;
+};
+typedef struct mountres3_ok mountres3_ok;
+
+struct mountres3 {
+ mountstat3 fhs_status;
+ union {
+ mountres3_ok mountinfo;
+ } mountres3_u;
+};
+typedef struct mountres3 mountres3;
+
+typedef char *dirpath;
+
+typedef char *name;
+
+typedef struct mountbody *mountlist;
+
+struct mountbody {
+ name ml_hostname;
+ dirpath ml_directory;
+ mountlist ml_next;
+};
+typedef struct mountbody mountbody;
+
+typedef struct groupnode *groups;
+
+struct groupnode {
+ name gr_name;
+ groups gr_next;
+};
+typedef struct groupnode groupnode;
+
+typedef struct exportnode *exports;
+
+struct exportnode {
+ dirpath ex_dir;
+ groups ex_groups;
+ exports ex_next;
+};
+typedef struct exportnode exportnode;
+
+struct ppathcnf {
+ int pc_link_max;
+ short pc_max_canon;
+ short pc_max_input;
+ short pc_name_max;
+ short pc_path_max;
+ short pc_pipe_buf;
+ u_char pc_vdisable;
+ char pc_xxx;
+ short pc_mask[2];
+};
+typedef struct ppathcnf ppathcnf;
+#endif /*!_rpcsvc_mount_h*/
+
+#define MOUNTPROG 100005
+#define MOUNTVERS 1
+
+#if defined(__STDC__) || defined(__cplusplus)
+#define MOUNTPROC_NULL 0
+extern void * mountproc_null_1(void *, CLIENT *);
+extern void * mountproc_null_1_svc(void *, struct svc_req *);
+#define MOUNTPROC_MNT 1
+extern fhstatus * mountproc_mnt_1(dirpath *, CLIENT *);
+extern fhstatus * mountproc_mnt_1_svc(dirpath *, struct svc_req *);
+#define MOUNTPROC_DUMP 2
+extern mountlist * mountproc_dump_1(void *, CLIENT *);
+extern mountlist * mountproc_dump_1_svc(void *, struct svc_req *);
+#define MOUNTPROC_UMNT 3
+extern void * mountproc_umnt_1(dirpath *, CLIENT *);
+extern void * mountproc_umnt_1_svc(dirpath *, struct svc_req *);
+#define MOUNTPROC_UMNTALL 4
+extern void * mountproc_umntall_1(void *, CLIENT *);
+extern void * mountproc_umntall_1_svc(void *, struct svc_req *);
+#define MOUNTPROC_EXPORT 5
+extern exports * mountproc_export_1(void *, CLIENT *);
+extern exports * mountproc_export_1_svc(void *, struct svc_req *);
+#define MOUNTPROC_EXPORTALL 6
+extern exports * mountproc_exportall_1(void *, CLIENT *);
+extern exports * mountproc_exportall_1_svc(void *, struct svc_req *);
+extern int mountprog_1_freeresult (SVCXPRT *, xdrproc_t, caddr_t);
+
+#else /* K&R C */
+#define MOUNTPROC_NULL 0
+extern void * mountproc_null_1();
+extern void * mountproc_null_1_svc();
+#define MOUNTPROC_MNT 1
+extern fhstatus * mountproc_mnt_1();
+extern fhstatus * mountproc_mnt_1_svc();
+#define MOUNTPROC_DUMP 2
+extern mountlist * mountproc_dump_1();
+extern mountlist * mountproc_dump_1_svc();
+#define MOUNTPROC_UMNT 3
+extern void * mountproc_umnt_1();
+extern void * mountproc_umnt_1_svc();
+#define MOUNTPROC_UMNTALL 4
+extern void * mountproc_umntall_1();
+extern void * mountproc_umntall_1_svc();
+#define MOUNTPROC_EXPORT 5
+extern exports * mountproc_export_1();
+extern exports * mountproc_export_1_svc();
+#define MOUNTPROC_EXPORTALL 6
+extern exports * mountproc_exportall_1();
+extern exports * mountproc_exportall_1_svc();
+extern int mountprog_1_freeresult ();
+#endif /* K&R C */
+#define MOUNTVERS_POSIX 2
+
+#if defined(__STDC__) || defined(__cplusplus)
+extern void * mountproc_null_2(void *, CLIENT *);
+extern void * mountproc_null_2_svc(void *, struct svc_req *);
+extern fhstatus * mountproc_mnt_2(dirpath *, CLIENT *);
+extern fhstatus * mountproc_mnt_2_svc(dirpath *, struct svc_req *);
+extern mountlist * mountproc_dump_2(void *, CLIENT *);
+extern mountlist * mountproc_dump_2_svc(void *, struct svc_req *);
+extern void * mountproc_umnt_2(dirpath *, CLIENT *);
+extern void * mountproc_umnt_2_svc(dirpath *, struct svc_req *);
+extern void * mountproc_umntall_2(void *, CLIENT *);
+extern void * mountproc_umntall_2_svc(void *, struct svc_req *);
+extern exports * mountproc_export_2(void *, CLIENT *);
+extern exports * mountproc_export_2_svc(void *, struct svc_req *);
+extern exports * mountproc_exportall_2(void *, CLIENT *);
+extern exports * mountproc_exportall_2_svc(void *, struct svc_req *);
+#define MOUNTPROC_PATHCONF 7
+extern ppathcnf * mountproc_pathconf_2(dirpath *, CLIENT *);
+extern ppathcnf * mountproc_pathconf_2_svc(dirpath *, struct svc_req *);
+extern int mountprog_2_freeresult (SVCXPRT *, xdrproc_t, caddr_t);
+
+#else /* K&R C */
+extern void * mountproc_null_2();
+extern void * mountproc_null_2_svc();
+extern fhstatus * mountproc_mnt_2();
+extern fhstatus * mountproc_mnt_2_svc();
+extern mountlist * mountproc_dump_2();
+extern mountlist * mountproc_dump_2_svc();
+extern void * mountproc_umnt_2();
+extern void * mountproc_umnt_2_svc();
+extern void * mountproc_umntall_2();
+extern void * mountproc_umntall_2_svc();
+extern exports * mountproc_export_2();
+extern exports * mountproc_export_2_svc();
+extern exports * mountproc_exportall_2();
+extern exports * mountproc_exportall_2_svc();
+#define MOUNTPROC_PATHCONF 7
+extern ppathcnf * mountproc_pathconf_2();
+extern ppathcnf * mountproc_pathconf_2_svc();
+extern int mountprog_2_freeresult ();
+#endif /* K&R C */
+#define MOUNT_V3 3
+
+#if defined(__STDC__) || defined(__cplusplus)
+#define MOUNTPROC3_NULL 0
+extern void * mountproc3_null_3(void *, CLIENT *);
+extern void * mountproc3_null_3_svc(void *, struct svc_req *);
+#define MOUNTPROC3_MNT 1
+extern mountres3 * mountproc3_mnt_3(dirpath *, CLIENT *);
+extern mountres3 * mountproc3_mnt_3_svc(dirpath *, struct svc_req *);
+#define MOUNTPROC3_DUMP 2
+extern mountlist * mountproc3_dump_3(void *, CLIENT *);
+extern mountlist * mountproc3_dump_3_svc(void *, struct svc_req *);
+#define MOUNTPROC3_UMNT 3
+extern void * mountproc3_umnt_3(dirpath *, CLIENT *);
+extern void * mountproc3_umnt_3_svc(dirpath *, struct svc_req *);
+#define MOUNTPROC3_UMNTALL 4
+extern void * mountproc3_umntall_3(void *, CLIENT *);
+extern void * mountproc3_umntall_3_svc(void *, struct svc_req *);
+#define MOUNTPROC3_EXPORT 5
+extern exports * mountproc3_export_3(void *, CLIENT *);
+extern exports * mountproc3_export_3_svc(void *, struct svc_req *);
+extern int mountprog_3_freeresult (SVCXPRT *, xdrproc_t, caddr_t);
+
+#else /* K&R C */
+#define MOUNTPROC3_NULL 0
+extern void * mountproc3_null_3();
+extern void * mountproc3_null_3_svc();
+#define MOUNTPROC3_MNT 1
+extern mountres3 * mountproc3_mnt_3();
+extern mountres3 * mountproc3_mnt_3_svc();
+#define MOUNTPROC3_DUMP 2
+extern mountlist * mountproc3_dump_3();
+extern mountlist * mountproc3_dump_3_svc();
+#define MOUNTPROC3_UMNT 3
+extern void * mountproc3_umnt_3();
+extern void * mountproc3_umnt_3_svc();
+#define MOUNTPROC3_UMNTALL 4
+extern void * mountproc3_umntall_3();
+extern void * mountproc3_umntall_3_svc();
+#define MOUNTPROC3_EXPORT 5
+extern exports * mountproc3_export_3();
+extern exports * mountproc3_export_3_svc();
+extern int mountprog_3_freeresult ();
+#endif /* K&R C */
+
+/* the xdr functions */
+
+#if defined(__STDC__) || defined(__cplusplus)
+extern bool_t xdr_fhandle (XDR *, fhandle);
+extern bool_t xdr_fhandle3 (XDR *, fhandle3*);
+extern bool_t xdr_mountstat3 (XDR *, mountstat3*);
+extern bool_t xdr_fhstatus (XDR *, fhstatus*);
+extern bool_t xdr_mountres3_ok (XDR *, mountres3_ok*);
+extern bool_t xdr_mountres3 (XDR *, mountres3*);
+extern bool_t xdr_dirpath (XDR *, dirpath*);
+extern bool_t xdr_name (XDR *, name*);
+extern bool_t xdr_mountlist (XDR *, mountlist*);
+extern bool_t xdr_mountbody (XDR *, mountbody*);
+extern bool_t xdr_groups (XDR *, groups*);
+extern bool_t xdr_groupnode (XDR *, groupnode*);
+extern bool_t xdr_exports (XDR *, exports*);
+extern bool_t xdr_exportnode (XDR *, exportnode*);
+extern bool_t xdr_ppathcnf (XDR *, ppathcnf*);
+
+#else /* K&R C */
+extern bool_t xdr_fhandle ();
+extern bool_t xdr_fhandle3 ();
+extern bool_t xdr_mountstat3 ();
+extern bool_t xdr_fhstatus ();
+extern bool_t xdr_mountres3_ok ();
+extern bool_t xdr_mountres3 ();
+extern bool_t xdr_dirpath ();
+extern bool_t xdr_name ();
+extern bool_t xdr_mountlist ();
+extern bool_t xdr_mountbody ();
+extern bool_t xdr_groups ();
+extern bool_t xdr_groupnode ();
+extern bool_t xdr_exports ();
+extern bool_t xdr_exportnode ();
+extern bool_t xdr_ppathcnf ();
+
+#endif /* K&R C */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !_NFSMOUNT_H_RPCGEN */
+
diff --git a/mdk-stage1/params.c b/mdk-stage1/params.c
new file mode 100644
index 000000000..38ac94956
--- /dev/null
+++ b/mdk-stage1/params.c
@@ -0,0 +1,175 @@
+/*
+ * Guillaume Cottenceau (gc@mandrakesoft.com)
+ *
+ * Copyright 2000 Mandrakesoft
+ *
+ * This software may be freely redistributed under the terms of the GNU
+ * public license.
+ *
+ * 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.
+ *
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include "params.h"
+#include "utils.h"
+#include "automatic.h"
+#include "log.h"
+#include "bootsplash.h"
+
+static struct param_elem params[50];
+static int param_number = 0;
+
+void process_cmdline(void)
+{
+ char buf[512];
+ int size, i;
+ int fd = -1;
+
+ if (IS_TESTING) {
+ log_message("TESTING: opening cmdline... ");
+
+ if ((fd = open("cmdline", O_RDONLY)) == -1)
+ log_message("TESTING: could not open cmdline");
+ }
+
+ if (fd == -1) {
+ log_message("opening /proc/cmdline... ");
+
+ if ((fd = open("/proc/cmdline", O_RDONLY)) == -1)
+ fatal_error("could not open /proc/cmdline");
+ }
+
+ size = read(fd, buf, sizeof(buf));
+ buf[size-1] = '\0'; // -1 to eat the \n
+ close(fd);
+
+ log_message("\t%s", buf);
+
+ i = 0;
+ while (buf[i] != '\0') {
+ char *name, *value = NULL;
+ int j = i;
+ while (buf[i] != ' ' && buf[i] != '=' && buf[i] != '\0')
+ i++;
+ if (i == j) {
+ i++;
+ continue;
+ }
+ name = memdup(&buf[j], i-j + 1);
+ name[i-j] = '\0';
+
+ if (buf[i] == '=') {
+ int k = i+1;
+ i++;
+ while (buf[i] != ' ' && buf[i] != '\0')
+ i++;
+ value = memdup(&buf[k], i-k + 1);
+ value[i-k] = '\0';
+ }
+
+ params[param_number].name = name;
+ params[param_number].value = value;
+ param_number++;
+ if (!strcmp(name, "changedisk")) set_param(MODE_CHANGEDISK);
+ if (!strcmp(name, "updatemodules") ||
+ !strcmp(name, "thirdparty")) set_param(MODE_THIRDPARTY);
+ if (!strcmp(name, "rescue")) set_param(MODE_RESCUE);
+ if (!strcmp(name, "keepmounted")) set_param(MODE_KEEP_MOUNTED);
+ if (!strcmp(name, "noauto")) set_param(MODE_NOAUTO);
+ if (!strcmp(name, "netauto")) set_param(MODE_NETAUTO);
+ if (!strcmp(name, "debugstage1")) set_param(MODE_DEBUGSTAGE1);
+ if (!strcmp(name, "automatic")) {
+ set_param(MODE_AUTOMATIC);
+ grab_automatic_params(value);
+ }
+ if (buf[i] == '\0')
+ break;
+ i++;
+ }
+
+ if (IS_AUTOMATIC && strcmp(get_auto_value("thirdparty"), "")) {
+ set_param(MODE_THIRDPARTY);
+ }
+
+ log_message("\tgot %d args", param_number);
+}
+
+
+int stage1_mode = 0;
+
+int get_param(int i)
+{
+#ifdef SPAWN_INTERACTIVE
+ static int fd = 0;
+ char buf[5000];
+ char * ptr;
+ int nb;
+
+ if (fd <= 0) {
+ fd = open(interactive_fifo, O_RDONLY);
+ if (fd == -1)
+ return (stage1_mode & i);
+ fcntl(fd, F_SETFL, O_NONBLOCK);
+ }
+
+ if (fd > 0) {
+ if ((nb = read(fd, buf, sizeof(buf))) > 0) {
+ buf[nb] = '\0';
+ ptr = buf;
+ while ((ptr = strstr(ptr, "+ "))) {
+ if (!strncmp(ptr+2, "rescue", 6)) set_param(MODE_RESCUE);
+ ptr++;
+ }
+ ptr = buf;
+ while ((ptr = strstr(ptr, "- "))) {
+ if (!strncmp(ptr+2, "rescue", 6)) unset_param(MODE_RESCUE);
+ ptr++;
+ }
+ }
+ }
+#endif
+
+ return (stage1_mode & i);
+}
+
+char * get_param_valued(char *param_name)
+{
+ int i;
+ for (i = 0; i < param_number ; i++)
+ if (!strcmp(params[i].name, param_name))
+ return params[i].value;
+
+ return NULL;
+}
+
+void set_param_valued(char *param_name, char *param_value)
+{
+ params[param_number].name = param_name;
+ params[param_number].value = param_value;
+ param_number++;
+}
+
+void set_param(int i)
+{
+ stage1_mode |= i;
+}
+
+void unset_param(int i)
+{
+ stage1_mode &= ~i;
+}
+
+void unset_automatic(void)
+{
+ log_message("unsetting automatic");
+ unset_param(MODE_AUTOMATIC);
+ exit_bootsplash();
+}
diff --git a/mdk-stage1/params.h b/mdk-stage1/params.h
new file mode 100644
index 000000000..2fe624143
--- /dev/null
+++ b/mdk-stage1/params.h
@@ -0,0 +1,31 @@
+/*
+ * Guillaume Cottenceau (gc@mandrakesoft.com)
+ *
+ * Copyright 2000 Mandrakesoft
+ *
+ * This software may be freely redistributed under the terms of the GNU
+ * public license.
+ *
+ * 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.
+ *
+ */
+
+#ifndef _PARAMS_H_
+#define _PARAMS_H_
+
+void process_cmdline(void);
+int get_param(int i);
+char * get_param_valued(char *param_name);
+void set_param(int i);
+void unset_param(int i);
+void unset_automatic(void);
+
+struct param_elem
+{
+ char * name;
+ char * value;
+};
+
+#endif
diff --git a/mdk-stage1/partition.c b/mdk-stage1/partition.c
new file mode 100644
index 000000000..d41fa7ebf
--- /dev/null
+++ b/mdk-stage1/partition.c
@@ -0,0 +1,170 @@
+/*
+ * Guillaume Cottenceau (gc@mandrakesoft.com)
+ *
+ * Copyright 2000 Mandrakesoft
+ *
+ * This software may be freely redistributed under the terms of the GNU
+ * public license.
+ *
+ * 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.
+ *
+ */
+
+/*
+ * Portions from Erik Troan (ewt@redhat.com)
+ *
+ * Copyright 1996 Red Hat Software
+ *
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <libgen.h>
+#include "stage1.h"
+#include "frontend.h"
+#include "modules.h"
+#include "probing.h"
+#include "log.h"
+#include "mount.h"
+#include "automatic.h"
+
+#include "disk.h"
+#include "partition.h"
+
+struct partition_detection_anchor {
+ off_t offset;
+ const char * anchor;
+};
+
+static int seek_and_compare(int fd, struct partition_detection_anchor anch)
+{
+ char buf[500];
+ size_t count;
+ if (lseek(fd, anch.offset, SEEK_SET) == (off_t)-1) {
+ log_perror("seek failed");
+ return -1;
+ }
+ count = read(fd, buf, strlen(anch.anchor));
+ if (count != strlen(anch.anchor)) {
+ log_perror("read failed");
+ return -1;
+ }
+ buf[count] = '\0';
+ if (strcmp(anch.anchor, buf))
+ return 1;
+ return 0;
+}
+
+static const char * detect_partition_type(char * dev)
+{
+ struct partition_detection_info {
+ const char * name;
+ struct partition_detection_anchor anchor0;
+ struct partition_detection_anchor anchor1;
+ struct partition_detection_anchor anchor2;
+ };
+ struct partition_detection_info partitions_signatures[] = {
+ { "Linux Swap", { 4086, "SWAP-SPACE" }, { 0, NULL }, { 0, NULL } },
+ { "Linux Swap", { 4086, "SWAPSPACE2" }, { 0, NULL }, { 0, NULL } },
+ { "Ext2", { 0x438, "\x53\xEF" }, { 0, NULL }, { 0, NULL } },
+ { "ReiserFS", { 0x10034, "ReIsErFs" }, { 0, NULL }, { 0, NULL } },
+ { "ReiserFS", { 0x10034, "ReIsEr2Fs" }, { 0, NULL }, { 0, NULL } },
+ { "XFS", { 0, "XFSB" }, { 0x200, "XAGF" }, { 0x400, "XAGI" } },
+ { "JFS", { 0x8000, "JFS1" }, { 0, NULL }, { 0, NULL } },
+ { "NTFS", { 0x1FE, "\x55\xAA" }, { 0x3, "NTFS" }, { 0, NULL } },
+ { "FAT32", { 0x1FE, "\x55\xAA" }, { 0x52, "FAT32" }, { 0, NULL } },
+ { "FAT", { 0x1FE, "\x55\xAA" }, { 0x36, "FAT" }, { 0, NULL } },
+ { "Linux LVM", { 0, "HM\1\0" }, { 0, NULL }, { 0, NULL } }
+ };
+ int partitions_signatures_nb = sizeof(partitions_signatures) / sizeof(struct partition_detection_info);
+ int i;
+ int fd;
+ const char *part_type = NULL;
+
+ char device_fullname[50];
+ strcpy(device_fullname, "/dev/");
+ strcat(device_fullname, dev);
+
+ if (ensure_dev_exists(device_fullname))
+ return NULL;
+ log_message("guessing type of %s", device_fullname);
+
+ if ((fd = open(device_fullname, O_RDONLY, 0)) < 0) {
+ log_perror("open");
+ return NULL;
+ }
+
+ for (i=0; i<partitions_signatures_nb; i++) {
+ int results = seek_and_compare(fd, partitions_signatures[i].anchor0);
+ if (results == -1)
+ goto detect_partition_type_end;
+ if (results == 1)
+ continue;
+ if (!partitions_signatures[i].anchor1.anchor)
+ goto detect_partition_found_it;
+
+ results = seek_and_compare(fd, partitions_signatures[i].anchor1);
+ if (results == -1)
+ goto detect_partition_type_end;
+ if (results == 1)
+ continue;
+ if (!partitions_signatures[i].anchor2.anchor)
+ goto detect_partition_found_it;
+
+ results = seek_and_compare(fd, partitions_signatures[i].anchor2);
+ if (results == -1)
+ goto detect_partition_type_end;
+ if (results == 1)
+ continue;
+
+ detect_partition_found_it:
+ part_type = partitions_signatures[i].name;
+ break;
+ }
+
+ detect_partition_type_end:
+ close(fd);
+ return part_type;
+}
+
+int list_partitions(char * dev_name, char ** parts, char ** comments)
+{
+ int major, minor, blocks;
+ char name[100];
+ FILE * f;
+ int i = 0;
+ char buf[512];
+
+ if (!(f = fopen("/proc/partitions", "rb")) || !fgets(buf, sizeof(buf), f) || !fgets(buf, sizeof(buf), f)) {
+ log_perror(dev_name);
+ return 1;
+ }
+
+ while (fgets(buf, sizeof(buf), f)) {
+ memset(name, 0, sizeof(name));
+ sscanf(buf, " %d %d %d %s", &major, &minor, &blocks, name);
+ if ((strstr(name, dev_name) == name) && (blocks > 1) && (name[strlen(dev_name)] != '\0')) {
+ const char * partition_type = detect_partition_type(name);
+ parts[i] = strdup(name);
+ comments[i] = (char *) malloc(sizeof(char) * 100);
+ sprintf(comments[i], "size: %d Mbytes", blocks >> 10);
+ if (partition_type) {
+ strcat(comments[i], ", type: ");
+ strcat(comments[i], partition_type);
+ }
+ i++;
+ }
+ }
+ parts[i] = NULL;
+ fclose(f);
+
+ return 0;
+}
diff --git a/mdk-stage1/partition.h b/mdk-stage1/partition.h
new file mode 100644
index 000000000..e901662df
--- /dev/null
+++ b/mdk-stage1/partition.h
@@ -0,0 +1,28 @@
+/*
+ * Olivier Blin (oblin@mandrakesoft.com)
+ *
+ * Copyright 2005 Mandrakesoft
+ *
+ * This software may be freely redistributed under the terms of the GNU
+ * public license.
+ *
+ * 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.
+ *
+ */
+
+/*
+ * Portions from Erik Troan (ewt@redhat.com)
+ *
+ * Copyright 1996 Red Hat Software
+ *
+ */
+
+#ifndef _PARTITION_H_
+#define _PARTITION_H_
+
+int list_partitions(char * dev_name, char ** parts, char ** comments);
+
+#endif
+
diff --git a/mdk-stage1/pci-resource/Makefile b/mdk-stage1/pci-resource/Makefile
new file mode 100644
index 000000000..3fea7db00
--- /dev/null
+++ b/mdk-stage1/pci-resource/Makefile
@@ -0,0 +1,25 @@
+ #******************************************************************************
+ #
+ # $Id: Makefile 213578 2005-08-25 11:41:51Z prigaux $
+ #
+ # Guillaume Cottenceau (gc@mandrakesoft.com)
+ #
+ # Copyright 2000 Mandrakesoft
+ #
+ # This software may be freely redistributed under the terms of the GNU
+ # public license.
+ #
+ # 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.
+ #
+ #*****************************************************************************
+
+
+all: pci-ids.h
+
+pci-ids.h: /usr/share/ldetect-lst/pcitable.gz update-pci-ids.pl
+ perl update-pci-ids.pl > $@ || { rm -f $@; exit 1; }
+
+clean:
+ rm -f pci-ids.h
diff --git a/mdk-stage1/pci-resource/update-pci-ids.pl b/mdk-stage1/pci-resource/update-pci-ids.pl
new file mode 100755
index 000000000..c6653a735
--- /dev/null
+++ b/mdk-stage1/pci-resource/update-pci-ids.pl
@@ -0,0 +1,27 @@
+#!/usr/bin/perl
+
+use lib '../kernel';
+use strict;
+use MDK::Common;
+
+
+my %t = (
+ network => 'network/main|gigabit|tokenring|wireless|pcmcia',
+ medias_ide => 'disk/ide',
+ medias_other => 'disk/scsi|hardware_raid|sata bus/firewire',
+);
+
+foreach my $type (keys %t) {
+ my @modules = chomp_(`perl ../../kernel/modules.pl pci_modules4stage1 "$t{$type}"`)
+ or die "unable to get PCI modules";
+
+ print "#ifndef DISABLE_".uc($type)."
+char* ${type}_pci_modules[] = {
+";
+ printf qq|\t"%s",\n|, $_ foreach @modules;
+ print "};
+unsigned int ${type}_pci_modules_len = sizeof(${type}_pci_modules) / sizeof(char *);
+#endif
+
+";
+}
diff --git a/mdk-stage1/pcmcia-resource/Makefile b/mdk-stage1/pcmcia-resource/Makefile
new file mode 100644
index 000000000..46dda9be1
--- /dev/null
+++ b/mdk-stage1/pcmcia-resource/Makefile
@@ -0,0 +1,24 @@
+ #******************************************************************************
+ #
+ # Olivier Blin (blino@mandriva.com)
+ #
+ # Copyright 2006 Mandriva
+ #
+ # This software may be freely redistributed under the terms of the GNU
+ # public license.
+ #
+ # 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.
+ #
+ #*****************************************************************************
+
+TARGET=pcmcia-ids.h
+
+all: $(TARGET)
+
+$(TARGET):
+ perl update-pcmcia-ids.pl > $@ || { rm -f $@; exit 1; }
+
+clean:
+ rm -f $(TARGET)
diff --git a/mdk-stage1/pcmcia-resource/update-pcmcia-ids.pl b/mdk-stage1/pcmcia-resource/update-pcmcia-ids.pl
new file mode 100755
index 000000000..67e0ca9a7
--- /dev/null
+++ b/mdk-stage1/pcmcia-resource/update-pcmcia-ids.pl
@@ -0,0 +1,42 @@
+#!/usr/bin/perl
+
+use lib '../kernel';
+use strict;
+use MDK::Common;
+
+my @aliases;
+my ($main) = `ls -t /lib/modules/*/modules.alias`;
+foreach (cat_(chomp_($main))) {
+ push @aliases, [ $1, $2 ] if /^alias\s+(pcmcia:\S+)\s+(\S+)$/; #- modalias, module
+}
+@aliases or die "unable to get PCMCIA aliases";
+
+print '
+struct pcmcia_alias {
+ const char *modalias;
+ const char *module;
+};
+
+';
+
+my %t = (
+ network => 'network/pcmcia',
+ medias => 'disk/pcmcia',
+);
+
+foreach my $type (keys %t) {
+ my @modules = chomp_(`perl ../../kernel/modules.pl pci_modules4stage1 "$t{$type}"`)
+ or die "unable to get PCMCIA modules";
+
+ print "#ifndef DISABLE_".uc($type)."
+struct pcmcia_alias ${type}_pcmcia_ids[] = {
+";
+ print qq|\t{ "$_->[0]", "$_->[1]" },\n| foreach grep { member($_->[1], @modules) } @aliases;
+ print "};
+unsigned int ${type}_pcmcia_num_ids = sizeof(${type}_pcmcia_ids) / sizeof(struct pcmcia_alias);
+
+#endif
+
+";
+
+}
diff --git a/mdk-stage1/pcmcia/Makefile b/mdk-stage1/pcmcia/Makefile
new file mode 100644
index 000000000..9e111f115
--- /dev/null
+++ b/mdk-stage1/pcmcia/Makefile
@@ -0,0 +1,52 @@
+ #******************************************************************************
+ #
+ # Guillaume Cottenceau (gc@mandrakesoft.com)
+ #
+ # Copyright 2001 Mandrakesoft
+ #
+ # This software may be freely redistributed under the terms of the GNU
+ # public license.
+ #
+ # 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.
+ #
+ #*****************************************************************************
+
+# startup.c is based on pcmcia-socket-startup from pcmciautils-013
+
+top_dir = ..
+
+include $(top_dir)/Makefile.common
+
+TARGET = libpcmcia.a
+YFLAGS := -d
+
+all: $(TARGET) pcmcia_probe.o
+
+clean:
+ rm -f *.o $(TARGET) lex_config.c yacc_config.c yacc_config.h
+
+FLAGS = -D__linux__ -Wall -Werror -Wno-deprecated-declarations -Os -fomit-frame-pointer -pipe -c -I.. -D_BSD_SOURCE
+# (blino) make sure yynewerror and yyerrlab are uselessly used
+FLAGS += -Dlint
+LFLAGS += --nounput
+
+
+OBJS = probe.o startup.o yacc_config.o lex_config.o
+
+
+%.c %.h : %.y
+ $(YACC) $(YFLAGS) $<
+ mv y.tab.c $*.c
+ mv y.tab.h $*.h
+
+$(TARGET): $(OBJS) yacc_config.h
+ ar -cru $@ $^
+ ranlib $@
+
+$(OBJS): %.o: %.c
+ $(DIET) gcc $(FLAGS) $(INCLUDES) -c $< -o $@
+
+pcmcia_probe.o: probe.c
+ $(DIET) gcc -fPIC $(FLAGS) $(INCLUDES) -c $< -o $@
diff --git a/mdk-stage1/pcmcia/bulkmem.h b/mdk-stage1/pcmcia/bulkmem.h
new file mode 100644
index 000000000..7748d4432
--- /dev/null
+++ b/mdk-stage1/pcmcia/bulkmem.h
@@ -0,0 +1,195 @@
+/*
+ * Definitions for bulk memory services
+ *
+ * bulkmem.h 1.13 2001/08/24 12:16:12
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License version 2 (the "GPL"), in
+ * which case the provisions of the GPL are applicable instead of the
+ * above. If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL. If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ * bulkmem.h 1.3 1995/05/27 04:49:49
+ */
+
+#ifndef _LINUX_BULKMEM_H
+#define _LINUX_BULKMEM_H
+
+/* For GetFirstRegion and GetNextRegion */
+typedef struct region_info_t {
+ u_int Attributes;
+ u_int CardOffset;
+ u_int RegionSize;
+ u_int AccessSpeed;
+ u_int BlockSize;
+ u_int PartMultiple;
+ u_char JedecMfr, JedecInfo;
+ memory_handle_t next;
+} region_info_t;
+
+#define REGION_TYPE 0x0001
+#define REGION_TYPE_CM 0x0000
+#define REGION_TYPE_AM 0x0001
+#define REGION_PREFETCH 0x0008
+#define REGION_CACHEABLE 0x0010
+#define REGION_BAR_MASK 0xe000
+#define REGION_BAR_SHIFT 13
+
+/* For OpenMemory */
+typedef struct open_mem_t {
+ u_int Attributes;
+ u_int Offset;
+} open_mem_t;
+
+/* Attributes for OpenMemory */
+#define MEMORY_TYPE 0x0001
+#define MEMORY_TYPE_CM 0x0000
+#define MEMORY_TYPE_AM 0x0001
+#define MEMORY_EXCLUSIVE 0x0002
+#define MEMORY_PREFETCH 0x0008
+#define MEMORY_CACHEABLE 0x0010
+#define MEMORY_BAR_MASK 0xe000
+#define MEMORY_BAR_SHIFT 13
+
+typedef struct eraseq_entry_t {
+ memory_handle_t Handle;
+ u_char State;
+ u_int Size;
+ u_int Offset;
+ void *Optional;
+} eraseq_entry_t;
+
+typedef struct eraseq_hdr_t {
+ int QueueEntryCnt;
+ eraseq_entry_t *QueueEntryArray;
+} eraseq_hdr_t;
+
+#define ERASE_QUEUED 0x00
+#define ERASE_IN_PROGRESS(n) (((n) > 0) && ((n) < 0x80))
+#define ERASE_IDLE 0xff
+#define ERASE_PASSED 0xe0
+#define ERASE_FAILED 0xe1
+
+#define ERASE_MISSING 0x80
+#define ERASE_MEDIA_WRPROT 0x84
+#define ERASE_NOT_ERASABLE 0x85
+#define ERASE_BAD_OFFSET 0xc1
+#define ERASE_BAD_TECH 0xc2
+#define ERASE_BAD_SOCKET 0xc3
+#define ERASE_BAD_VCC 0xc4
+#define ERASE_BAD_VPP 0xc5
+#define ERASE_BAD_SIZE 0xc6
+
+/* For CopyMemory */
+typedef struct copy_op_t {
+ u_int Attributes;
+ u_int SourceOffset;
+ u_int DestOffset;
+ u_int Count;
+} copy_op_t;
+
+/* For ReadMemory and WriteMemory */
+typedef struct mem_op_t {
+ u_int Attributes;
+ u_int Offset;
+ u_int Count;
+} mem_op_t;
+
+#define MEM_OP_BUFFER 0x01
+#define MEM_OP_BUFFER_USER 0x00
+#define MEM_OP_BUFFER_KERNEL 0x01
+#define MEM_OP_DISABLE_ERASE 0x02
+#define MEM_OP_VERIFY 0x04
+
+/* For RegisterMTD */
+typedef struct mtd_reg_t {
+ u_int Attributes;
+ u_int Offset;
+ u_long MediaID;
+} mtd_reg_t;
+
+/*
+ * Definitions for MTD requests
+ */
+
+typedef struct mtd_request_t {
+ u_int SrcCardOffset;
+ u_int DestCardOffset;
+ u_int TransferLength;
+ u_int Function;
+ u_long MediaID;
+ u_int Status;
+ u_int Timeout;
+} mtd_request_t;
+
+/* Fields in MTD Function */
+#define MTD_REQ_ACTION 0x003
+#define MTD_REQ_ERASE 0x000
+#define MTD_REQ_READ 0x001
+#define MTD_REQ_WRITE 0x002
+#define MTD_REQ_COPY 0x003
+#define MTD_REQ_NOERASE 0x004
+#define MTD_REQ_VERIFY 0x008
+#define MTD_REQ_READY 0x010
+#define MTD_REQ_TIMEOUT 0x020
+#define MTD_REQ_LAST 0x040
+#define MTD_REQ_FIRST 0x080
+#define MTD_REQ_KERNEL 0x100
+
+/* Status codes */
+#define MTD_WAITREQ 0x00
+#define MTD_WAITTIMER 0x01
+#define MTD_WAITRDY 0x02
+#define MTD_WAITPOWER 0x03
+
+/*
+ * Definitions for MTD helper functions
+ */
+
+/* For MTDModifyWindow */
+typedef struct mtd_mod_win_t {
+ u_int Attributes;
+ u_int AccessSpeed;
+ u_int CardOffset;
+} mtd_mod_win_t;
+
+/* For MTDSetVpp */
+typedef struct mtd_vpp_req_t {
+ u_char Vpp1, Vpp2;
+} mtd_vpp_req_t;
+
+/* For MTDRDYMask */
+typedef struct mtd_rdy_req_t {
+ u_int Mask;
+} mtd_rdy_req_t;
+
+enum mtd_helper {
+ MTDRequestWindow, MTDModifyWindow, MTDReleaseWindow,
+ MTDSetVpp, MTDRDYMask
+};
+
+#ifdef IN_CARD_SERVICES
+extern int MTDHelperEntry(int func, void *a1, void *a2);
+#else
+extern int MTDHelperEntry(int func, ...);
+#endif
+
+#endif /* _LINUX_BULKMEM_H */
diff --git a/mdk-stage1/pcmcia/cirrus.h b/mdk-stage1/pcmcia/cirrus.h
new file mode 100644
index 000000000..78f73b26d
--- /dev/null
+++ b/mdk-stage1/pcmcia/cirrus.h
@@ -0,0 +1,157 @@
+/*
+ * cirrus.h 1.10 2001/08/24 12:15:33
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License version 2 (the "GPL"), in
+ * which case the provisions of the GPL are applicable instead of the
+ * above. If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL. If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ */
+
+#ifndef _LINUX_CIRRUS_H
+#define _LINUX_CIRRUS_H
+
+#ifndef PCI_VENDOR_ID_CIRRUS
+#define PCI_VENDOR_ID_CIRRUS 0x1013
+#endif
+#ifndef PCI_DEVICE_ID_CIRRUS_6729
+#define PCI_DEVICE_ID_CIRRUS_6729 0x1100
+#endif
+#ifndef PCI_DEVICE_ID_CIRRUS_6832
+#define PCI_DEVICE_ID_CIRRUS_6832 0x1110
+#endif
+
+#define PD67_MISC_CTL_1 0x16 /* Misc control 1 */
+#define PD67_FIFO_CTL 0x17 /* FIFO control */
+#define PD67_MISC_CTL_2 0x1E /* Misc control 2 */
+#define PD67_CHIP_INFO 0x1f /* Chip information */
+#define PD67_ATA_CTL 0x026 /* 6730: ATA control */
+#define PD67_EXT_INDEX 0x2e /* Extension index */
+#define PD67_EXT_DATA 0x2f /* Extension data */
+
+/* PD6722 extension registers -- indexed in PD67_EXT_INDEX */
+#define PD67_DATA_MASK0 0x01 /* Data mask 0 */
+#define PD67_DATA_MASK1 0x02 /* Data mask 1 */
+#define PD67_DMA_CTL 0x03 /* DMA control */
+
+/* PD6730 extension registers -- indexed in PD67_EXT_INDEX */
+#define PD67_EXT_CTL_1 0x03 /* Extension control 1 */
+#define PD67_MEM_PAGE(n) ((n)+5) /* PCI window bits 31:24 */
+#define PD67_EXTERN_DATA 0x0a
+#define PD67_MISC_CTL_3 0x25
+#define PD67_SMB_PWR_CTL 0x26
+
+/* I/O window address offset */
+#define PD67_IO_OFF(w) (0x36+((w)<<1))
+
+/* Timing register sets */
+#define PD67_TIME_SETUP(n) (0x3a + 3*(n))
+#define PD67_TIME_CMD(n) (0x3b + 3*(n))
+#define PD67_TIME_RECOV(n) (0x3c + 3*(n))
+
+/* Flags for PD67_MISC_CTL_1 */
+#define PD67_MC1_5V_DET 0x01 /* 5v detect */
+#define PD67_MC1_MEDIA_ENA 0x01 /* 6730: Multimedia enable */
+#define PD67_MC1_VCC_3V 0x02 /* 3.3v Vcc */
+#define PD67_MC1_PULSE_MGMT 0x04
+#define PD67_MC1_PULSE_IRQ 0x08
+#define PD67_MC1_SPKR_ENA 0x10
+#define PD67_MC1_INPACK_ENA 0x80
+
+/* Flags for PD67_FIFO_CTL */
+#define PD67_FIFO_EMPTY 0x80
+
+/* Flags for PD67_MISC_CTL_2 */
+#define PD67_MC2_FREQ_BYPASS 0x01
+#define PD67_MC2_DYNAMIC_MODE 0x02
+#define PD67_MC2_SUSPEND 0x04
+#define PD67_MC2_5V_CORE 0x08
+#define PD67_MC2_LED_ENA 0x10 /* IRQ 12 is LED enable */
+#define PD67_MC2_FAST_PCI 0x10 /* 6729: PCI bus > 25 MHz */
+#define PD67_MC2_3STATE_BIT7 0x20 /* Floppy change bit */
+#define PD67_MC2_DMA_MODE 0x40
+#define PD67_MC2_IRQ15_RI 0x80 /* IRQ 15 is ring enable */
+
+/* Flags for PD67_CHIP_INFO */
+#define PD67_INFO_SLOTS 0x20 /* 0 = 1 slot, 1 = 2 slots */
+#define PD67_INFO_CHIP_ID 0xc0
+#define PD67_INFO_REV 0x1c
+
+/* Fields in PD67_TIME_* registers */
+#define PD67_TIME_SCALE 0xc0
+#define PD67_TIME_SCALE_1 0x00
+#define PD67_TIME_SCALE_16 0x40
+#define PD67_TIME_SCALE_256 0x80
+#define PD67_TIME_SCALE_4096 0xc0
+#define PD67_TIME_MULT 0x3f
+
+/* Fields in PD67_DMA_CTL */
+#define PD67_DMA_MODE 0xc0
+#define PD67_DMA_OFF 0x00
+#define PD67_DMA_DREQ_INPACK 0x40
+#define PD67_DMA_DREQ_WP 0x80
+#define PD67_DMA_DREQ_BVD2 0xc0
+#define PD67_DMA_PULLUP 0x20 /* Disable socket pullups? */
+
+/* Fields in PD67_EXT_CTL_1 */
+#define PD67_EC1_VCC_PWR_LOCK 0x01
+#define PD67_EC1_AUTO_PWR_CLEAR 0x02
+#define PD67_EC1_LED_ENA 0x04
+#define PD67_EC1_INV_CARD_IRQ 0x08
+#define PD67_EC1_INV_MGMT_IRQ 0x10
+#define PD67_EC1_PULLUP_CTL 0x20
+
+/* Fields in PD67_MISC_CTL_3 */
+#define PD67_MC3_IRQ_MASK 0x03
+#define PD67_MC3_IRQ_PCPCI 0x00
+#define PD67_MC3_IRQ_EXTERN 0x01
+#define PD67_MC3_IRQ_PCIWAY 0x02
+#define PD67_MC3_IRQ_PCI 0x03
+#define PD67_MC3_PWR_MASK 0x0c
+#define PD67_MC3_PWR_SERIAL 0x00
+#define PD67_MC3_PWR_TI2202 0x08
+#define PD67_MC3_PWR_SMB 0x0c
+
+/* Register definitions for Cirrus PD6832 PCI-to-CardBus bridge */
+
+/* PD6832 extension registers -- indexed in PD67_EXT_INDEX */
+#define PD68_EXT_CTL_2 0x0b
+#define PD68_PCI_SPACE 0x22
+#define PD68_PCCARD_SPACE 0x23
+#define PD68_WINDOW_TYPE 0x24
+#define PD68_EXT_CSC 0x2e
+#define PD68_MISC_CTL_4 0x2f
+#define PD68_MISC_CTL_5 0x30
+#define PD68_MISC_CTL_6 0x31
+
+/* Extra flags in PD67_MISC_CTL_3 */
+#define PD68_MC3_HW_SUSP 0x10
+#define PD68_MC3_MM_EXPAND 0x40
+#define PD68_MC3_MM_ARM 0x80
+
+/* Bridge Control Register */
+#define PD6832_BCR_MGMT_IRQ_ENA 0x0800
+
+/* Socket Number Register */
+#define PD6832_SOCKET_NUMBER 0x004c /* 8 bit */
+
+#endif /* _LINUX_CIRRUS_H */
diff --git a/mdk-stage1/pcmcia/cistpl.h b/mdk-stage1/pcmcia/cistpl.h
new file mode 100644
index 000000000..1d4cac20e
--- /dev/null
+++ b/mdk-stage1/pcmcia/cistpl.h
@@ -0,0 +1,604 @@
+/*
+ * cistpl.h 1.35 2001/08/24 12:16:12
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License version 2 (the "GPL"), in
+ * which case the provisions of the GPL are applicable instead of the
+ * above. If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL. If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ */
+
+#ifndef _LINUX_CISTPL_H
+#define _LINUX_CISTPL_H
+
+#define CISTPL_NULL 0x00
+#define CISTPL_DEVICE 0x01
+#define CISTPL_LONGLINK_CB 0x02
+#define CISTPL_INDIRECT 0x03
+#define CISTPL_CONFIG_CB 0x04
+#define CISTPL_CFTABLE_ENTRY_CB 0x05
+#define CISTPL_LONGLINK_MFC 0x06
+#define CISTPL_BAR 0x07
+#define CISTPL_PWR_MGMNT 0x08
+#define CISTPL_EXTDEVICE 0x09
+#define CISTPL_CHECKSUM 0x10
+#define CISTPL_LONGLINK_A 0x11
+#define CISTPL_LONGLINK_C 0x12
+#define CISTPL_LINKTARGET 0x13
+#define CISTPL_NO_LINK 0x14
+#define CISTPL_VERS_1 0x15
+#define CISTPL_ALTSTR 0x16
+#define CISTPL_DEVICE_A 0x17
+#define CISTPL_JEDEC_C 0x18
+#define CISTPL_JEDEC_A 0x19
+#define CISTPL_CONFIG 0x1a
+#define CISTPL_CFTABLE_ENTRY 0x1b
+#define CISTPL_DEVICE_OC 0x1c
+#define CISTPL_DEVICE_OA 0x1d
+#define CISTPL_DEVICE_GEO 0x1e
+#define CISTPL_DEVICE_GEO_A 0x1f
+#define CISTPL_MANFID 0x20
+#define CISTPL_FUNCID 0x21
+#define CISTPL_FUNCE 0x22
+#define CISTPL_SWIL 0x23
+#define CISTPL_END 0xff
+/* Layer 2 tuples */
+#define CISTPL_VERS_2 0x40
+#define CISTPL_FORMAT 0x41
+#define CISTPL_GEOMETRY 0x42
+#define CISTPL_BYTEORDER 0x43
+#define CISTPL_DATE 0x44
+#define CISTPL_BATTERY 0x45
+#define CISTPL_FORMAT_A 0x47
+/* Layer 3 tuples */
+#define CISTPL_ORG 0x46
+#define CISTPL_SPCL 0x90
+
+typedef struct cistpl_longlink_t {
+ u_int addr;
+} cistpl_longlink_t;
+
+typedef struct cistpl_checksum_t {
+ u_short addr;
+ u_short len;
+ u_char sum;
+} cistpl_checksum_t;
+
+#define CISTPL_MAX_FUNCTIONS 8
+#define CISTPL_MFC_ATTR 0x00
+#define CISTPL_MFC_COMMON 0x01
+
+typedef struct cistpl_longlink_mfc_t {
+ u_char nfn;
+ struct {
+ u_char space;
+ u_int addr;
+ } fn[CISTPL_MAX_FUNCTIONS];
+} cistpl_longlink_mfc_t;
+
+#define CISTPL_MAX_ALTSTR_STRINGS 4
+
+typedef struct cistpl_altstr_t {
+ u_char ns;
+ u_char ofs[CISTPL_MAX_ALTSTR_STRINGS];
+ char str[254];
+} cistpl_altstr_t;
+
+#define CISTPL_DTYPE_NULL 0x00
+#define CISTPL_DTYPE_ROM 0x01
+#define CISTPL_DTYPE_OTPROM 0x02
+#define CISTPL_DTYPE_EPROM 0x03
+#define CISTPL_DTYPE_EEPROM 0x04
+#define CISTPL_DTYPE_FLASH 0x05
+#define CISTPL_DTYPE_SRAM 0x06
+#define CISTPL_DTYPE_DRAM 0x07
+#define CISTPL_DTYPE_FUNCSPEC 0x0d
+#define CISTPL_DTYPE_EXTEND 0x0e
+
+#define CISTPL_MAX_DEVICES 4
+
+typedef struct cistpl_device_t {
+ u_char ndev;
+ struct {
+ u_char type;
+ u_char wp;
+ u_int speed;
+ u_int size;
+ } dev[CISTPL_MAX_DEVICES];
+} cistpl_device_t;
+
+#define CISTPL_DEVICE_MWAIT 0x01
+#define CISTPL_DEVICE_3VCC 0x02
+
+typedef struct cistpl_device_o_t {
+ u_char flags;
+ cistpl_device_t device;
+} cistpl_device_o_t;
+
+#define CISTPL_VERS_1_MAX_PROD_STRINGS 4
+
+typedef struct cistpl_vers_1_t {
+ u_char major;
+ u_char minor;
+ u_char ns;
+ u_char ofs[CISTPL_VERS_1_MAX_PROD_STRINGS];
+ char str[254];
+} cistpl_vers_1_t;
+
+typedef struct cistpl_jedec_t {
+ u_char nid;
+ struct {
+ u_char mfr;
+ u_char info;
+ } id[CISTPL_MAX_DEVICES];
+} cistpl_jedec_t;
+
+typedef struct cistpl_manfid_t {
+ u_short manf;
+ u_short card;
+} cistpl_manfid_t;
+
+#define CISTPL_FUNCID_MULTI 0x00
+#define CISTPL_FUNCID_MEMORY 0x01
+#define CISTPL_FUNCID_SERIAL 0x02
+#define CISTPL_FUNCID_PARALLEL 0x03
+#define CISTPL_FUNCID_FIXED 0x04
+#define CISTPL_FUNCID_VIDEO 0x05
+#define CISTPL_FUNCID_NETWORK 0x06
+#define CISTPL_FUNCID_AIMS 0x07
+#define CISTPL_FUNCID_SCSI 0x08
+
+#define CISTPL_SYSINIT_POST 0x01
+#define CISTPL_SYSINIT_ROM 0x02
+
+typedef struct cistpl_funcid_t {
+ u_char func;
+ u_char sysinit;
+} cistpl_funcid_t;
+
+typedef struct cistpl_funce_t {
+ u_char type;
+ u_char data[0];
+} cistpl_funce_t;
+
+/*======================================================================
+
+ Modem Function Extension Tuples
+
+======================================================================*/
+
+#define CISTPL_FUNCE_SERIAL_IF 0x00
+#define CISTPL_FUNCE_SERIAL_CAP 0x01
+#define CISTPL_FUNCE_SERIAL_SERV_DATA 0x02
+#define CISTPL_FUNCE_SERIAL_SERV_FAX 0x03
+#define CISTPL_FUNCE_SERIAL_SERV_VOICE 0x04
+#define CISTPL_FUNCE_SERIAL_CAP_DATA 0x05
+#define CISTPL_FUNCE_SERIAL_CAP_FAX 0x06
+#define CISTPL_FUNCE_SERIAL_CAP_VOICE 0x07
+#define CISTPL_FUNCE_SERIAL_IF_DATA 0x08
+#define CISTPL_FUNCE_SERIAL_IF_FAX 0x09
+#define CISTPL_FUNCE_SERIAL_IF_VOICE 0x0a
+
+/* UART identification */
+#define CISTPL_SERIAL_UART_8250 0x00
+#define CISTPL_SERIAL_UART_16450 0x01
+#define CISTPL_SERIAL_UART_16550 0x02
+#define CISTPL_SERIAL_UART_8251 0x03
+#define CISTPL_SERIAL_UART_8530 0x04
+#define CISTPL_SERIAL_UART_85230 0x05
+
+/* UART capabilities */
+#define CISTPL_SERIAL_UART_SPACE 0x01
+#define CISTPL_SERIAL_UART_MARK 0x02
+#define CISTPL_SERIAL_UART_ODD 0x04
+#define CISTPL_SERIAL_UART_EVEN 0x08
+#define CISTPL_SERIAL_UART_5BIT 0x01
+#define CISTPL_SERIAL_UART_6BIT 0x02
+#define CISTPL_SERIAL_UART_7BIT 0x04
+#define CISTPL_SERIAL_UART_8BIT 0x08
+#define CISTPL_SERIAL_UART_1STOP 0x10
+#define CISTPL_SERIAL_UART_MSTOP 0x20
+#define CISTPL_SERIAL_UART_2STOP 0x40
+
+typedef struct cistpl_serial_t {
+ u_char uart_type;
+ u_char uart_cap_0;
+ u_char uart_cap_1;
+} cistpl_serial_t;
+
+typedef struct cistpl_modem_cap_t {
+ u_char flow;
+ u_char cmd_buf;
+ u_char rcv_buf_0, rcv_buf_1, rcv_buf_2;
+ u_char xmit_buf_0, xmit_buf_1, xmit_buf_2;
+} cistpl_modem_cap_t;
+
+#define CISTPL_SERIAL_MOD_103 0x01
+#define CISTPL_SERIAL_MOD_V21 0x02
+#define CISTPL_SERIAL_MOD_V23 0x04
+#define CISTPL_SERIAL_MOD_V22 0x08
+#define CISTPL_SERIAL_MOD_212A 0x10
+#define CISTPL_SERIAL_MOD_V22BIS 0x20
+#define CISTPL_SERIAL_MOD_V26 0x40
+#define CISTPL_SERIAL_MOD_V26BIS 0x80
+#define CISTPL_SERIAL_MOD_V27BIS 0x01
+#define CISTPL_SERIAL_MOD_V29 0x02
+#define CISTPL_SERIAL_MOD_V32 0x04
+#define CISTPL_SERIAL_MOD_V32BIS 0x08
+#define CISTPL_SERIAL_MOD_V34 0x10
+
+#define CISTPL_SERIAL_ERR_MNP2_4 0x01
+#define CISTPL_SERIAL_ERR_V42_LAPM 0x02
+
+#define CISTPL_SERIAL_CMPR_V42BIS 0x01
+#define CISTPL_SERIAL_CMPR_MNP5 0x02
+
+#define CISTPL_SERIAL_CMD_AT1 0x01
+#define CISTPL_SERIAL_CMD_AT2 0x02
+#define CISTPL_SERIAL_CMD_AT3 0x04
+#define CISTPL_SERIAL_CMD_MNP_AT 0x08
+#define CISTPL_SERIAL_CMD_V25BIS 0x10
+#define CISTPL_SERIAL_CMD_V25A 0x20
+#define CISTPL_SERIAL_CMD_DMCL 0x40
+
+typedef struct cistpl_data_serv_t {
+ u_char max_data_0;
+ u_char max_data_1;
+ u_char modulation_0;
+ u_char modulation_1;
+ u_char error_control;
+ u_char compression;
+ u_char cmd_protocol;
+ u_char escape;
+ u_char encrypt;
+ u_char misc_features;
+ u_char ccitt_code[0];
+} cistpl_data_serv_t;
+
+typedef struct cistpl_fax_serv_t {
+ u_char max_data_0;
+ u_char max_data_1;
+ u_char modulation;
+ u_char encrypt;
+ u_char features_0;
+ u_char features_1;
+ u_char ccitt_code[0];
+} cistpl_fax_serv_t;
+
+typedef struct cistpl_voice_serv_t {
+ u_char max_data_0;
+ u_char max_data_1;
+} cistpl_voice_serv_t;
+
+/*======================================================================
+
+ LAN Function Extension Tuples
+
+======================================================================*/
+
+#define CISTPL_FUNCE_LAN_TECH 0x01
+#define CISTPL_FUNCE_LAN_SPEED 0x02
+#define CISTPL_FUNCE_LAN_MEDIA 0x03
+#define CISTPL_FUNCE_LAN_NODE_ID 0x04
+#define CISTPL_FUNCE_LAN_CONNECTOR 0x05
+
+/* LAN technologies */
+#define CISTPL_LAN_TECH_ARCNET 0x01
+#define CISTPL_LAN_TECH_ETHERNET 0x02
+#define CISTPL_LAN_TECH_TOKENRING 0x03
+#define CISTPL_LAN_TECH_LOCALTALK 0x04
+#define CISTPL_LAN_TECH_FDDI 0x05
+#define CISTPL_LAN_TECH_ATM 0x06
+#define CISTPL_LAN_TECH_WIRELESS 0x07
+
+typedef struct cistpl_lan_tech_t {
+ u_char tech;
+} cistpl_lan_tech_t;
+
+typedef struct cistpl_lan_speed_t {
+ u_int speed;
+} cistpl_lan_speed_t;
+
+/* LAN media definitions */
+#define CISTPL_LAN_MEDIA_UTP 0x01
+#define CISTPL_LAN_MEDIA_STP 0x02
+#define CISTPL_LAN_MEDIA_THIN_COAX 0x03
+#define CISTPL_LAN_MEDIA_THICK_COAX 0x04
+#define CISTPL_LAN_MEDIA_FIBER 0x05
+#define CISTPL_LAN_MEDIA_900MHZ 0x06
+#define CISTPL_LAN_MEDIA_2GHZ 0x07
+#define CISTPL_LAN_MEDIA_5GHZ 0x08
+#define CISTPL_LAN_MEDIA_DIFF_IR 0x09
+#define CISTPL_LAN_MEDIA_PTP_IR 0x0a
+
+typedef struct cistpl_lan_media_t {
+ u_char media;
+} cistpl_lan_media_t;
+
+typedef struct cistpl_lan_node_id_t {
+ u_char nb;
+ u_char id[16];
+} cistpl_lan_node_id_t;
+
+typedef struct cistpl_lan_connector_t {
+ u_char code;
+} cistpl_lan_connector_t;
+
+/*======================================================================
+
+ IDE Function Extension Tuples
+
+======================================================================*/
+
+#define CISTPL_IDE_INTERFACE 0x01
+
+typedef struct cistpl_ide_interface_t {
+ u_char interface;
+} cistpl_ide_interface_t;
+
+/* First feature byte */
+#define CISTPL_IDE_SILICON 0x04
+#define CISTPL_IDE_UNIQUE 0x08
+#define CISTPL_IDE_DUAL 0x10
+
+/* Second feature byte */
+#define CISTPL_IDE_HAS_SLEEP 0x01
+#define CISTPL_IDE_HAS_STANDBY 0x02
+#define CISTPL_IDE_HAS_IDLE 0x04
+#define CISTPL_IDE_LOW_POWER 0x08
+#define CISTPL_IDE_REG_INHIBIT 0x10
+#define CISTPL_IDE_HAS_INDEX 0x20
+#define CISTPL_IDE_IOIS16 0x40
+
+typedef struct cistpl_ide_feature_t {
+ u_char feature1;
+ u_char feature2;
+} cistpl_ide_feature_t;
+
+#define CISTPL_FUNCE_IDE_IFACE 0x01
+#define CISTPL_FUNCE_IDE_MASTER 0x02
+#define CISTPL_FUNCE_IDE_SLAVE 0x03
+
+/*======================================================================
+
+ Configuration Table Entries
+
+======================================================================*/
+
+#define CISTPL_BAR_SPACE 0x07
+#define CISTPL_BAR_SPACE_IO 0x10
+#define CISTPL_BAR_PREFETCH 0x20
+#define CISTPL_BAR_CACHEABLE 0x40
+#define CISTPL_BAR_1MEG_MAP 0x80
+
+typedef struct cistpl_bar_t {
+ u_char attr;
+ u_int size;
+} cistpl_bar_t;
+
+typedef struct cistpl_config_t {
+ u_char last_idx;
+ u_int base;
+ u_int rmask[4];
+ u_char subtuples;
+} cistpl_config_t;
+
+/* These are bits in the 'present' field, and indices in 'param' */
+#define CISTPL_POWER_VNOM 0
+#define CISTPL_POWER_VMIN 1
+#define CISTPL_POWER_VMAX 2
+#define CISTPL_POWER_ISTATIC 3
+#define CISTPL_POWER_IAVG 4
+#define CISTPL_POWER_IPEAK 5
+#define CISTPL_POWER_IDOWN 6
+
+#define CISTPL_POWER_HIGHZ_OK 0x01
+#define CISTPL_POWER_HIGHZ_REQ 0x02
+
+typedef struct cistpl_power_t {
+ u_char present;
+ u_char flags;
+ u_int param[7];
+} cistpl_power_t;
+
+typedef struct cistpl_timing_t {
+ u_int wait, waitscale;
+ u_int ready, rdyscale;
+ u_int reserved, rsvscale;
+} cistpl_timing_t;
+
+#define CISTPL_IO_LINES_MASK 0x1f
+#define CISTPL_IO_8BIT 0x20
+#define CISTPL_IO_16BIT 0x40
+#define CISTPL_IO_RANGE 0x80
+
+#define CISTPL_IO_MAX_WIN 16
+
+typedef struct cistpl_io_t {
+ u_char flags;
+ u_char nwin;
+ struct {
+ u_int base;
+ u_int len;
+ } win[CISTPL_IO_MAX_WIN];
+} cistpl_io_t;
+
+typedef struct cistpl_irq_t {
+ u_int IRQInfo1;
+ u_int IRQInfo2;
+} cistpl_irq_t;
+
+#define CISTPL_MEM_MAX_WIN 8
+
+typedef struct cistpl_mem_t {
+ u_char flags;
+ u_char nwin;
+ struct {
+ u_int len;
+ u_int card_addr;
+ u_int host_addr;
+ } win[CISTPL_MEM_MAX_WIN];
+} cistpl_mem_t;
+
+#define CISTPL_CFTABLE_DEFAULT 0x0001
+#define CISTPL_CFTABLE_BVDS 0x0002
+#define CISTPL_CFTABLE_WP 0x0004
+#define CISTPL_CFTABLE_RDYBSY 0x0008
+#define CISTPL_CFTABLE_MWAIT 0x0010
+#define CISTPL_CFTABLE_AUDIO 0x0800
+#define CISTPL_CFTABLE_READONLY 0x1000
+#define CISTPL_CFTABLE_PWRDOWN 0x2000
+
+typedef struct cistpl_cftable_entry_t {
+ u_char index;
+ u_short flags;
+ u_char interface;
+ cistpl_power_t vcc, vpp1, vpp2;
+ cistpl_timing_t timing;
+ cistpl_io_t io;
+ cistpl_irq_t irq;
+ cistpl_mem_t mem;
+ u_char subtuples;
+} cistpl_cftable_entry_t;
+
+#define CISTPL_CFTABLE_MASTER 0x000100
+#define CISTPL_CFTABLE_INVALIDATE 0x000200
+#define CISTPL_CFTABLE_VGA_PALETTE 0x000400
+#define CISTPL_CFTABLE_PARITY 0x000800
+#define CISTPL_CFTABLE_WAIT 0x001000
+#define CISTPL_CFTABLE_SERR 0x002000
+#define CISTPL_CFTABLE_FAST_BACK 0x004000
+#define CISTPL_CFTABLE_BINARY_AUDIO 0x010000
+#define CISTPL_CFTABLE_PWM_AUDIO 0x020000
+
+typedef struct cistpl_cftable_entry_cb_t {
+ u_char index;
+ u_int flags;
+ cistpl_power_t vcc, vpp1, vpp2;
+ u_char io;
+ cistpl_irq_t irq;
+ u_char mem;
+ u_char subtuples;
+} cistpl_cftable_entry_cb_t;
+
+typedef struct cistpl_device_geo_t {
+ u_char ngeo;
+ struct {
+ u_char buswidth;
+ u_int erase_block;
+ u_int read_block;
+ u_int write_block;
+ u_int partition;
+ u_int interleave;
+ } geo[CISTPL_MAX_DEVICES];
+} cistpl_device_geo_t;
+
+typedef struct cistpl_vers_2_t {
+ u_char vers;
+ u_char comply;
+ u_short dindex;
+ u_char vspec8, vspec9;
+ u_char nhdr;
+ u_char vendor, info;
+ char str[244];
+} cistpl_vers_2_t;
+
+typedef struct cistpl_org_t {
+ u_char data_org;
+ char desc[30];
+} cistpl_org_t;
+
+#define CISTPL_ORG_FS 0x00
+#define CISTPL_ORG_APPSPEC 0x01
+#define CISTPL_ORG_XIP 0x02
+
+typedef struct cistpl_format_t {
+ u_char type;
+ u_char edc;
+ u_int offset;
+ u_int length;
+} cistpl_format_t;
+
+#define CISTPL_FORMAT_DISK 0x00
+#define CISTPL_FORMAT_MEM 0x01
+
+#define CISTPL_EDC_NONE 0x00
+#define CISTPL_EDC_CKSUM 0x01
+#define CISTPL_EDC_CRC 0x02
+#define CISTPL_EDC_PCC 0x03
+
+typedef union cisparse_t {
+ cistpl_device_t device;
+ cistpl_checksum_t checksum;
+ cistpl_longlink_t longlink;
+ cistpl_longlink_mfc_t longlink_mfc;
+ cistpl_vers_1_t version_1;
+ cistpl_altstr_t altstr;
+ cistpl_jedec_t jedec;
+ cistpl_manfid_t manfid;
+ cistpl_funcid_t funcid;
+ cistpl_funce_t funce;
+ cistpl_bar_t bar;
+ cistpl_config_t config;
+ cistpl_cftable_entry_t cftable_entry;
+ cistpl_cftable_entry_cb_t cftable_entry_cb;
+ cistpl_device_geo_t device_geo;
+ cistpl_vers_2_t vers_2;
+ cistpl_org_t org;
+ cistpl_format_t format;
+} cisparse_t;
+
+typedef struct tuple_t {
+ u_int Attributes;
+ cisdata_t DesiredTuple;
+ u_int Flags; /* internal use */
+ u_int LinkOffset; /* internal use */
+ u_int CISOffset; /* internal use */
+ cisdata_t TupleCode;
+ cisdata_t TupleLink;
+ cisdata_t TupleOffset;
+ cisdata_t TupleDataMax;
+ cisdata_t TupleDataLen;
+ cisdata_t *TupleData;
+} tuple_t;
+
+/* Special cisdata_t value */
+#define RETURN_FIRST_TUPLE 0xff
+
+/* Attributes for tuple calls */
+#define TUPLE_RETURN_LINK 0x01
+#define TUPLE_RETURN_COMMON 0x02
+
+/* For ValidateCIS */
+typedef struct cisinfo_t {
+ u_int Chains;
+} cisinfo_t;
+
+#define CISTPL_MAX_CIS_SIZE 0x200
+
+/* For ReplaceCIS */
+typedef struct cisdump_t {
+ u_int Length;
+ cisdata_t Data[CISTPL_MAX_CIS_SIZE];
+} cisdump_t;
+
+#endif /* LINUX_CISTPL_H */
diff --git a/mdk-stage1/pcmcia/cs.h b/mdk-stage1/pcmcia/cs.h
new file mode 100644
index 000000000..9abeac216
--- /dev/null
+++ b/mdk-stage1/pcmcia/cs.h
@@ -0,0 +1,433 @@
+/*
+ * cs.h 1.73 2001/08/24 12:16:12
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License version 2 (the "GPL"), in
+ * which case the provisions of the GPL are applicable instead of the
+ * above. If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL. If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ */
+
+#ifndef _LINUX_CS_H
+#define _LINUX_CS_H
+
+/* For AccessConfigurationRegister */
+typedef struct conf_reg_t {
+ u_char Function;
+ u_int Action;
+ off_t Offset;
+ u_int Value;
+} conf_reg_t;
+
+/* Actions */
+#define CS_READ 1
+#define CS_WRITE 2
+
+/* for AdjustResourceInfo */
+typedef struct adjust_t {
+ u_int Action;
+ u_int Resource;
+ u_int Attributes;
+ union {
+ struct memory {
+ unsigned long Base;
+ unsigned long Size;
+ } memory;
+ struct io {
+ ioaddr_t BasePort;
+ ioaddr_t NumPorts;
+ u_int IOAddrLines;
+ } io;
+ struct irq {
+ u_int IRQ;
+ } irq;
+ } resource;
+} adjust_t;
+
+/* Action field */
+#define REMOVE_MANAGED_RESOURCE 1
+#define ADD_MANAGED_RESOURCE 2
+#define GET_FIRST_MANAGED_RESOURCE 3
+#define GET_NEXT_MANAGED_RESOURCE 4
+/* Resource field */
+#define RES_MEMORY_RANGE 1
+#define RES_IO_RANGE 2
+#define RES_IRQ 3
+/* Attribute field */
+#define RES_IRQ_TYPE 0x03
+#define RES_IRQ_TYPE_EXCLUSIVE 0
+#define RES_IRQ_TYPE_TIME 1
+#define RES_IRQ_TYPE_DYNAMIC 2
+#define RES_IRQ_CSC 0x04
+#define RES_SHARED 0x08
+#define RES_RESERVED 0x10
+#define RES_ALLOCATED 0x20
+#define RES_REMOVED 0x40
+
+typedef struct servinfo_t {
+ char Signature[2];
+ u_int Count;
+ u_int Revision;
+ u_int CSLevel;
+ char *VendorString;
+} servinfo_t;
+
+typedef struct event_callback_args_t {
+ client_handle_t client_handle;
+ void *info;
+ void *mtdrequest;
+ void *buffer;
+ void *misc;
+ void *client_data;
+ struct bus_operations *bus;
+} event_callback_args_t;
+
+/* for GetConfigurationInfo */
+typedef struct config_info_t {
+ u_char Function;
+ u_int Attributes;
+ u_int Vcc, Vpp1, Vpp2;
+ u_int IntType;
+ u_int ConfigBase;
+ u_char Status, Pin, Copy, Option, ExtStatus;
+ u_int Present;
+ u_int CardValues;
+ u_int AssignedIRQ;
+ u_int IRQAttributes;
+ ioaddr_t BasePort1;
+ ioaddr_t NumPorts1;
+ u_int Attributes1;
+ ioaddr_t BasePort2;
+ ioaddr_t NumPorts2;
+ u_int Attributes2;
+ u_int IOAddrLines;
+} config_info_t;
+
+/* For CardValues field */
+#define CV_OPTION_VALUE 0x01
+#define CV_STATUS_VALUE 0x02
+#define CV_PIN_REPLACEMENT 0x04
+#define CV_COPY_VALUE 0x08
+#define CV_EXT_STATUS 0x10
+
+/* For GetFirst/NextClient */
+typedef struct client_req_t {
+ socket_t Socket;
+ u_int Attributes;
+} client_req_t;
+
+#define CLIENT_THIS_SOCKET 0x01
+
+/* For RegisterClient */
+typedef struct client_reg_t {
+ dev_info_t *dev_info;
+ u_int Attributes;
+ u_int EventMask;
+ int (*event_handler)(event_t event, int priority,
+ event_callback_args_t *);
+ event_callback_args_t event_callback_args;
+ u_int Version;
+} client_reg_t;
+
+/* ModifyConfiguration */
+typedef struct modconf_t {
+ u_int Attributes;
+ u_int Vcc, Vpp1, Vpp2;
+} modconf_t;
+
+/* Attributes for ModifyConfiguration */
+#define CONF_IRQ_CHANGE_VALID 0x100
+#define CONF_VCC_CHANGE_VALID 0x200
+#define CONF_VPP1_CHANGE_VALID 0x400
+#define CONF_VPP2_CHANGE_VALID 0x800
+
+/* For RequestConfiguration */
+typedef struct config_req_t {
+ u_int Attributes;
+ u_int Vcc, Vpp1, Vpp2;
+ u_int IntType;
+ u_int ConfigBase;
+ u_char Status, Pin, Copy, ExtStatus;
+ u_char ConfigIndex;
+ u_int Present;
+} config_req_t;
+
+/* Attributes for RequestConfiguration */
+#define CONF_ENABLE_IRQ 0x01
+#define CONF_ENABLE_DMA 0x02
+#define CONF_ENABLE_SPKR 0x04
+#define CONF_VALID_CLIENT 0x100
+
+/* IntType field */
+#define INT_MEMORY 0x01
+#define INT_MEMORY_AND_IO 0x02
+#define INT_CARDBUS 0x04
+#define INT_ZOOMED_VIDEO 0x08
+
+/* For RequestIO and ReleaseIO */
+typedef struct io_req_t {
+ ioaddr_t BasePort1;
+ ioaddr_t NumPorts1;
+ u_int Attributes1;
+ ioaddr_t BasePort2;
+ ioaddr_t NumPorts2;
+ u_int Attributes2;
+ u_int IOAddrLines;
+} io_req_t;
+
+/* Attributes for RequestIO and ReleaseIO */
+#define IO_SHARED 0x01
+#define IO_FIRST_SHARED 0x02
+#define IO_FORCE_ALIAS_ACCESS 0x04
+#define IO_DATA_PATH_WIDTH 0x18
+#define IO_DATA_PATH_WIDTH_8 0x00
+#define IO_DATA_PATH_WIDTH_16 0x08
+#define IO_DATA_PATH_WIDTH_AUTO 0x10
+
+/* For RequestIRQ and ReleaseIRQ */
+typedef struct irq_req_t {
+ u_int Attributes;
+ u_int AssignedIRQ;
+ u_int IRQInfo1, IRQInfo2;
+ void *Handler;
+ void *Instance;
+} irq_req_t;
+
+/* Attributes for RequestIRQ and ReleaseIRQ */
+#define IRQ_TYPE 0x03
+#define IRQ_TYPE_EXCLUSIVE 0x00
+#define IRQ_TYPE_TIME 0x01
+#define IRQ_TYPE_DYNAMIC_SHARING 0x02
+#define IRQ_FORCED_PULSE 0x04
+#define IRQ_FIRST_SHARED 0x08
+#define IRQ_HANDLE_PRESENT 0x10
+#define IRQ_PULSE_ALLOCATED 0x100
+
+/* Bits in IRQInfo1 field */
+#define IRQ_MASK 0x0f
+#define IRQ_NMI_ID 0x01
+#define IRQ_IOCK_ID 0x02
+#define IRQ_BERR_ID 0x04
+#define IRQ_VEND_ID 0x08
+#define IRQ_INFO2_VALID 0x10
+#define IRQ_LEVEL_ID 0x20
+#define IRQ_PULSE_ID 0x40
+#define IRQ_SHARE_ID 0x80
+
+typedef struct eventmask_t {
+ u_int Attributes;
+ u_int EventMask;
+} eventmask_t;
+
+#define CONF_EVENT_MASK_VALID 0x01
+
+/* Configuration registers present */
+#define PRESENT_OPTION 0x001
+#define PRESENT_STATUS 0x002
+#define PRESENT_PIN_REPLACE 0x004
+#define PRESENT_COPY 0x008
+#define PRESENT_EXT_STATUS 0x010
+#define PRESENT_IOBASE_0 0x020
+#define PRESENT_IOBASE_1 0x040
+#define PRESENT_IOBASE_2 0x080
+#define PRESENT_IOBASE_3 0x100
+#define PRESENT_IOSIZE 0x200
+
+/* For GetMemPage, MapMemPage */
+typedef struct memreq_t {
+ u_int CardOffset;
+ page_t Page;
+} memreq_t;
+
+/* For ModifyWindow */
+typedef struct modwin_t {
+ u_int Attributes;
+ u_int AccessSpeed;
+} modwin_t;
+
+/* For RequestWindow */
+typedef struct win_req_t {
+ u_int Attributes;
+ unsigned long Base;
+ u_int Size;
+ u_int AccessSpeed;
+} win_req_t;
+
+/* Attributes for RequestWindow */
+#define WIN_ADDR_SPACE 0x0001
+#define WIN_ADDR_SPACE_MEM 0x0000
+#define WIN_ADDR_SPACE_IO 0x0001
+#define WIN_MEMORY_TYPE 0x0002
+#define WIN_MEMORY_TYPE_CM 0x0000
+#define WIN_MEMORY_TYPE_AM 0x0002
+#define WIN_ENABLE 0x0004
+#define WIN_DATA_WIDTH 0x0018
+#define WIN_DATA_WIDTH_8 0x0000
+#define WIN_DATA_WIDTH_16 0x0008
+#define WIN_DATA_WIDTH_32 0x0010
+#define WIN_PAGED 0x0020
+#define WIN_SHARED 0x0040
+#define WIN_FIRST_SHARED 0x0080
+#define WIN_USE_WAIT 0x0100
+#define WIN_STRICT_ALIGN 0x0200
+#define WIN_MAP_BELOW_1MB 0x0400
+#define WIN_PREFETCH 0x0800
+#define WIN_CACHEABLE 0x1000
+#define WIN_BAR_MASK 0xe000
+#define WIN_BAR_SHIFT 13
+
+/* Attributes for RegisterClient */
+#define INFO_MASTER_CLIENT 0x01
+#define INFO_IO_CLIENT 0x02
+#define INFO_MTD_CLIENT 0x04
+#define INFO_MEM_CLIENT 0x08
+#define MAX_NUM_CLIENTS 3
+
+#define INFO_CARD_SHARE 0x10
+#define INFO_CARD_EXCL 0x20
+
+typedef struct cs_status_t {
+ u_char Function;
+ event_t CardState;
+ event_t SocketState;
+} cs_status_t;
+
+typedef struct error_info_t {
+ int func;
+ int retcode;
+} error_info_t;
+
+/* Special stuff for binding drivers to sockets */
+typedef struct bind_req_t {
+ socket_t Socket;
+ u_char Function;
+ dev_info_t *dev_info;
+} bind_req_t;
+
+/* Flag to bind to all functions */
+#define BIND_FN_ALL 0xff
+
+typedef struct mtd_bind_t {
+ socket_t Socket;
+ u_int Attributes;
+ u_int CardOffset;
+ dev_info_t *dev_info;
+} mtd_bind_t;
+
+/* Events */
+#define CS_EVENT_PRI_LOW 0
+#define CS_EVENT_PRI_HIGH 1
+
+#define CS_EVENT_WRITE_PROTECT 0x000001
+#define CS_EVENT_CARD_LOCK 0x000002
+#define CS_EVENT_CARD_INSERTION 0x000004
+#define CS_EVENT_CARD_REMOVAL 0x000008
+#define CS_EVENT_BATTERY_DEAD 0x000010
+#define CS_EVENT_BATTERY_LOW 0x000020
+#define CS_EVENT_READY_CHANGE 0x000040
+#define CS_EVENT_CARD_DETECT 0x000080
+#define CS_EVENT_RESET_REQUEST 0x000100
+#define CS_EVENT_RESET_PHYSICAL 0x000200
+#define CS_EVENT_CARD_RESET 0x000400
+#define CS_EVENT_REGISTRATION_COMPLETE 0x000800
+#define CS_EVENT_RESET_COMPLETE 0x001000
+#define CS_EVENT_PM_SUSPEND 0x002000
+#define CS_EVENT_PM_RESUME 0x004000
+#define CS_EVENT_INSERTION_REQUEST 0x008000
+#define CS_EVENT_EJECTION_REQUEST 0x010000
+#define CS_EVENT_MTD_REQUEST 0x020000
+#define CS_EVENT_ERASE_COMPLETE 0x040000
+#define CS_EVENT_REQUEST_ATTENTION 0x080000
+#define CS_EVENT_CB_DETECT 0x100000
+#define CS_EVENT_3VCARD 0x200000
+#define CS_EVENT_XVCARD 0x400000
+
+/* Return codes */
+#define CS_SUCCESS 0x00
+#define CS_BAD_ADAPTER 0x01
+#define CS_BAD_ATTRIBUTE 0x02
+#define CS_BAD_BASE 0x03
+#define CS_BAD_EDC 0x04
+#define CS_BAD_IRQ 0x06
+#define CS_BAD_OFFSET 0x07
+#define CS_BAD_PAGE 0x08
+#define CS_READ_FAILURE 0x09
+#define CS_BAD_SIZE 0x0a
+#define CS_BAD_SOCKET 0x0b
+#define CS_BAD_TYPE 0x0d
+#define CS_BAD_VCC 0x0e
+#define CS_BAD_VPP 0x0f
+#define CS_BAD_WINDOW 0x11
+#define CS_WRITE_FAILURE 0x12
+#define CS_NO_CARD 0x14
+#define CS_UNSUPPORTED_FUNCTION 0x15
+#define CS_UNSUPPORTED_MODE 0x16
+#define CS_BAD_SPEED 0x17
+#define CS_BUSY 0x18
+#define CS_GENERAL_FAILURE 0x19
+#define CS_WRITE_PROTECTED 0x1a
+#define CS_BAD_ARG_LENGTH 0x1b
+#define CS_BAD_ARGS 0x1c
+#define CS_CONFIGURATION_LOCKED 0x1d
+#define CS_IN_USE 0x1e
+#define CS_NO_MORE_ITEMS 0x1f
+#define CS_OUT_OF_RESOURCE 0x20
+#define CS_BAD_HANDLE 0x21
+
+#define CS_BAD_TUPLE 0x40
+
+#ifdef __KERNEL__
+
+/*
+ * The main Card Services entry point
+ */
+
+enum service {
+ AccessConfigurationRegister, AddSocketServices,
+ AdjustResourceInfo, CheckEraseQueue, CloseMemory, CopyMemory,
+ DeregisterClient, DeregisterEraseQueue, GetCardServicesInfo,
+ GetClientInfo, GetConfigurationInfo, GetEventMask,
+ GetFirstClient, GetFirstPartion, GetFirstRegion, GetFirstTuple,
+ GetNextClient, GetNextPartition, GetNextRegion, GetNextTuple,
+ GetStatus, GetTupleData, MapLogSocket, MapLogWindow, MapMemPage,
+ MapPhySocket, MapPhyWindow, ModifyConfiguration, ModifyWindow,
+ OpenMemory, ParseTuple, ReadMemory, RegisterClient,
+ RegisterEraseQueue, RegisterMTD, RegisterTimer,
+ ReleaseConfiguration, ReleaseExclusive, ReleaseIO, ReleaseIRQ,
+ ReleaseSocketMask, ReleaseWindow, ReplaceSocketServices,
+ RequestConfiguration, RequestExclusive, RequestIO, RequestIRQ,
+ RequestSocketMask, RequestWindow, ResetCard, ReturnSSEntry,
+ SetEventMask, SetRegion, ValidateCIS, VendorSpecific,
+ WriteMemory, BindDevice, BindMTD, ReportError,
+ SuspendCard, ResumeCard, EjectCard, InsertCard, ReplaceCIS,
+ GetFirstWindow, GetNextWindow, GetMemPage
+};
+
+#ifdef IN_CARD_SERVICES
+extern int CardServices(int func, void *a1, void *a2, void *a3);
+#else
+extern int CardServices(int func, ...);
+#endif
+
+#endif /* __KERNEL__ */
+
+#endif /* _LINUX_CS_H */
diff --git a/mdk-stage1/pcmcia/cs_types.h b/mdk-stage1/pcmcia/cs_types.h
new file mode 100644
index 000000000..4598d7f48
--- /dev/null
+++ b/mdk-stage1/pcmcia/cs_types.h
@@ -0,0 +1,70 @@
+/*
+ * cs_types.h 1.19 2001/08/24 12:16:12
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License version 2 (the "GPL"), in
+ * which case the provisions of the GPL are applicable instead of the
+ * above. If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL. If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ */
+
+#ifndef _LINUX_CS_TYPES_H
+#define _LINUX_CS_TYPES_H
+
+#ifdef __linux__
+#ifdef __KERNEL__
+#include <linux/types.h>
+#else
+#include <sys/types.h>
+#endif
+#endif
+
+#ifdef __arm__
+typedef u_int ioaddr_t;
+#else
+typedef u_short ioaddr_t;
+#endif
+
+typedef u_short socket_t;
+typedef u_int event_t;
+typedef u_char cisdata_t;
+typedef u_short page_t;
+
+struct client_t;
+typedef struct client_t *client_handle_t;
+
+struct window_t;
+typedef struct window_t *window_handle_t;
+
+struct region_t;
+typedef struct region_t *memory_handle_t;
+
+struct eraseq_t;
+typedef struct eraseq_t *eraseq_handle_t;
+
+#ifndef DEV_NAME_LEN
+#define DEV_NAME_LEN 32
+#endif
+
+typedef char dev_info_t[DEV_NAME_LEN];
+
+#endif /* _LINUX_CS_TYPES_H */
diff --git a/mdk-stage1/pcmcia/driver_ops.h b/mdk-stage1/pcmcia/driver_ops.h
new file mode 100644
index 000000000..2f0a066d3
--- /dev/null
+++ b/mdk-stage1/pcmcia/driver_ops.h
@@ -0,0 +1,73 @@
+/*
+ * driver_ops.h 1.16 2001/08/24 12:16:13
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License version 2 (the "GPL"), in
+ * which case the provisions of the GPL are applicable instead of the
+ * above. If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL. If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ */
+
+#ifndef _LINUX_DRIVER_OPS_H
+#define _LINUX_DRIVER_OPS_H
+
+#ifndef DEV_NAME_LEN
+#define DEV_NAME_LEN 32
+#endif
+
+#ifdef __KERNEL__
+
+typedef struct dev_node_t {
+ char dev_name[DEV_NAME_LEN];
+ u_short major, minor;
+ struct dev_node_t *next;
+} dev_node_t;
+
+typedef struct dev_locator_t {
+ enum { LOC_ISA, LOC_PCI } bus;
+ union {
+ struct {
+ u_short io_base_1, io_base_2;
+ u_long mem_base;
+ u_char irq, dma;
+ } isa;
+ struct {
+ u_char bus;
+ u_char devfn;
+ } pci;
+ } b;
+} dev_locator_t;
+
+typedef struct driver_operations {
+ char *name;
+ dev_node_t *(*attach) (dev_locator_t *loc);
+ void (*suspend) (dev_node_t *dev);
+ void (*resume) (dev_node_t *dev);
+ void (*detach) (dev_node_t *dev);
+} driver_operations;
+
+int register_driver(struct driver_operations *ops);
+void unregister_driver(struct driver_operations *ops);
+
+#endif /* __KERNEL__ */
+
+#endif /* _LINUX_DRIVER_OPS_H */
diff --git a/mdk-stage1/pcmcia/ds.h b/mdk-stage1/pcmcia/ds.h
new file mode 100644
index 000000000..29db7b415
--- /dev/null
+++ b/mdk-stage1/pcmcia/ds.h
@@ -0,0 +1,148 @@
+/*
+ * ds.h 1.57 2001/08/24 12:16:13
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License version 2 (the "GPL"), in
+ * which case the provisions of the GPL are applicable instead of the
+ * above. If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL. If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ */
+
+#ifndef _LINUX_DS_H
+#define _LINUX_DS_H
+
+#include <pcmcia_/driver_ops.h>
+#include <pcmcia_/bulkmem.h>
+
+typedef struct tuple_parse_t {
+ tuple_t tuple;
+ cisdata_t data[255];
+ cisparse_t parse;
+} tuple_parse_t;
+
+typedef struct win_info_t {
+ window_handle_t handle;
+ win_req_t window;
+ memreq_t map;
+} win_info_t;
+
+typedef struct bind_info_t {
+ dev_info_t dev_info;
+ u_char function;
+ struct dev_link_t *instance;
+ char name[DEV_NAME_LEN];
+ u_short major, minor;
+ void *next;
+} bind_info_t;
+
+typedef struct mtd_info_t {
+ dev_info_t dev_info;
+ u_int Attributes;
+ u_int CardOffset;
+} mtd_info_t;
+
+typedef union ds_ioctl_arg_t {
+ servinfo_t servinfo;
+ adjust_t adjust;
+ config_info_t config;
+ tuple_t tuple;
+ tuple_parse_t tuple_parse;
+ client_req_t client_req;
+ cs_status_t status;
+ conf_reg_t conf_reg;
+ cisinfo_t cisinfo;
+ region_info_t region;
+ bind_info_t bind_info;
+ mtd_info_t mtd_info;
+ win_info_t win_info;
+ cisdump_t cisdump;
+} ds_ioctl_arg_t;
+
+#define DS_GET_CARD_SERVICES_INFO _IOR ('d', 1, servinfo_t)
+#define DS_ADJUST_RESOURCE_INFO _IOWR('d', 2, adjust_t)
+#define DS_GET_CONFIGURATION_INFO _IOWR('d', 3, config_info_t)
+#define DS_GET_FIRST_TUPLE _IOWR('d', 4, tuple_t)
+#define DS_GET_NEXT_TUPLE _IOWR('d', 5, tuple_t)
+#define DS_GET_TUPLE_DATA _IOWR('d', 6, tuple_parse_t)
+#define DS_PARSE_TUPLE _IOWR('d', 7, tuple_parse_t)
+#define DS_RESET_CARD _IO ('d', 8)
+#define DS_GET_STATUS _IOWR('d', 9, cs_status_t)
+#define DS_ACCESS_CONFIGURATION_REGISTER _IOWR('d', 10, conf_reg_t)
+#define DS_VALIDATE_CIS _IOR ('d', 11, cisinfo_t)
+#define DS_SUSPEND_CARD _IO ('d', 12)
+#define DS_RESUME_CARD _IO ('d', 13)
+#define DS_EJECT_CARD _IO ('d', 14)
+#define DS_INSERT_CARD _IO ('d', 15)
+#define DS_GET_FIRST_REGION _IOWR('d', 16, region_info_t)
+#define DS_GET_NEXT_REGION _IOWR('d', 17, region_info_t)
+#define DS_REPLACE_CIS _IOWR('d', 18, cisdump_t)
+#define DS_GET_FIRST_WINDOW _IOR ('d', 19, win_info_t)
+#define DS_GET_NEXT_WINDOW _IOWR('d', 20, win_info_t)
+#define DS_GET_MEM_PAGE _IOWR('d', 21, win_info_t)
+
+#define DS_BIND_REQUEST _IOWR('d', 60, bind_info_t)
+#define DS_GET_DEVICE_INFO _IOWR('d', 61, bind_info_t)
+#define DS_GET_NEXT_DEVICE _IOWR('d', 62, bind_info_t)
+#define DS_UNBIND_REQUEST _IOW ('d', 63, bind_info_t)
+#define DS_BIND_MTD _IOWR('d', 64, mtd_info_t)
+
+#ifdef __KERNEL__
+
+typedef struct dev_link_t {
+ dev_node_t *dev;
+ u_int state, open;
+ wait_queue_head_t pending;
+ struct timer_list release;
+ client_handle_t handle;
+ io_req_t io;
+ irq_req_t irq;
+ config_req_t conf;
+ window_handle_t win;
+ void *priv;
+ struct dev_link_t *next;
+} dev_link_t;
+
+/* Flags for device state */
+#define DEV_PRESENT 0x01
+#define DEV_CONFIG 0x02
+#define DEV_STALE_CONFIG 0x04 /* release on close */
+#define DEV_STALE_LINK 0x08 /* detach on release */
+#define DEV_CONFIG_PENDING 0x10
+#define DEV_RELEASE_PENDING 0x20
+#define DEV_SUSPEND 0x40
+#define DEV_BUSY 0x80
+
+#define DEV_OK(l) \
+ ((l) && ((l->state & ~DEV_BUSY) == (DEV_CONFIG|DEV_PRESENT)))
+
+int register_pccard_driver(dev_info_t *dev_info,
+ dev_link_t *(*attach)(void),
+ void (*detach)(dev_link_t *));
+
+int unregister_pccard_driver(dev_info_t *dev_info);
+
+#define register_pcmcia_driver register_pccard_driver
+#define unregister_pcmcia_driver unregister_pccard_driver
+
+#endif /* __KERNEL__ */
+
+#endif /* _LINUX_DS_H */
diff --git a/mdk-stage1/pcmcia/i82365.h b/mdk-stage1/pcmcia/i82365.h
new file mode 100644
index 000000000..38ff167fb
--- /dev/null
+++ b/mdk-stage1/pcmcia/i82365.h
@@ -0,0 +1,135 @@
+/*
+ * i82365.h 1.21 2001/08/24 12:15:33
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License version 2 (the "GPL"), in
+ * which case the provisions of the GPL are applicable instead of the
+ * above. If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL. If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ */
+
+#ifndef _LINUX_I82365_H
+#define _LINUX_I82365_H
+
+/* register definitions for the Intel 82365SL PCMCIA controller */
+
+/* Offsets for PCIC registers */
+#define I365_IDENT 0x00 /* Identification and revision */
+#define I365_STATUS 0x01 /* Interface status */
+#define I365_POWER 0x02 /* Power and RESETDRV control */
+#define I365_INTCTL 0x03 /* Interrupt and general control */
+#define I365_CSC 0x04 /* Card status change */
+#define I365_CSCINT 0x05 /* Card status change interrupt control */
+#define I365_ADDRWIN 0x06 /* Address window enable */
+#define I365_IOCTL 0x07 /* I/O control */
+#define I365_GENCTL 0x16 /* Card detect and general control */
+#define I365_GBLCTL 0x1E /* Global control register */
+
+/* Offsets for I/O and memory window registers */
+#define I365_IO(map) (0x08+((map)<<2))
+#define I365_MEM(map) (0x10+((map)<<3))
+#define I365_W_START 0
+#define I365_W_STOP 2
+#define I365_W_OFF 4
+
+/* Flags for I365_STATUS */
+#define I365_CS_BVD1 0x01
+#define I365_CS_STSCHG 0x01
+#define I365_CS_BVD2 0x02
+#define I365_CS_SPKR 0x02
+#define I365_CS_DETECT 0x0C
+#define I365_CS_WRPROT 0x10
+#define I365_CS_READY 0x20 /* Inverted */
+#define I365_CS_POWERON 0x40
+#define I365_CS_GPI 0x80
+
+/* Flags for I365_POWER */
+#define I365_PWR_OFF 0x00 /* Turn off the socket */
+#define I365_PWR_OUT 0x80 /* Output enable */
+#define I365_PWR_NORESET 0x40 /* Disable RESETDRV on resume */
+#define I365_PWR_AUTO 0x20 /* Auto pwr switch enable */
+#define I365_VCC_MASK 0x18 /* Mask for turning off Vcc */
+/* There are different layouts for B-step and DF-step chips: the B
+ step has independent Vpp1/Vpp2 control, and the DF step has only
+ Vpp1 control, plus 3V control */
+#define I365_VCC_5V 0x10 /* Vcc = 5.0v */
+#define I365_VCC_3V 0x18 /* Vcc = 3.3v */
+#define I365_VPP2_MASK 0x0c /* Mask for turning off Vpp2 */
+#define I365_VPP2_5V 0x04 /* Vpp2 = 5.0v */
+#define I365_VPP2_12V 0x08 /* Vpp2 = 12.0v */
+#define I365_VPP1_MASK 0x03 /* Mask for turning off Vpp1 */
+#define I365_VPP1_5V 0x01 /* Vpp2 = 5.0v */
+#define I365_VPP1_12V 0x02 /* Vpp2 = 12.0v */
+
+/* Flags for I365_INTCTL */
+#define I365_RING_ENA 0x80
+#define I365_PC_RESET 0x40
+#define I365_PC_IOCARD 0x20
+#define I365_INTR_ENA 0x10
+#define I365_IRQ_MASK 0x0F
+
+/* Flags for I365_CSC and I365_CSCINT*/
+#define I365_CSC_BVD1 0x01
+#define I365_CSC_STSCHG 0x01
+#define I365_CSC_BVD2 0x02
+#define I365_CSC_READY 0x04
+#define I365_CSC_DETECT 0x08
+#define I365_CSC_ANY 0x0F
+#define I365_CSC_GPI 0x10
+
+/* Flags for I365_ADDRWIN */
+#define I365_ENA_IO(map) (0x40 << (map))
+#define I365_ENA_MEM(map) (0x01 << (map))
+
+/* Flags for I365_IOCTL */
+#define I365_IOCTL_MASK(map) (0x0F << (map<<2))
+#define I365_IOCTL_WAIT(map) (0x08 << (map<<2))
+#define I365_IOCTL_0WS(map) (0x04 << (map<<2))
+#define I365_IOCTL_IOCS16(map) (0x02 << (map<<2))
+#define I365_IOCTL_16BIT(map) (0x01 << (map<<2))
+
+/* Flags for I365_GENCTL */
+#define I365_CTL_16DELAY 0x01
+#define I365_CTL_RESET 0x02
+#define I365_CTL_GPI_ENA 0x04
+#define I365_CTL_GPI_CTL 0x08
+#define I365_CTL_RESUME 0x10
+#define I365_CTL_SW_IRQ 0x20
+
+/* Flags for I365_GBLCTL */
+#define I365_GBL_PWRDOWN 0x01
+#define I365_GBL_CSC_LEV 0x02
+#define I365_GBL_WRBACK 0x04
+#define I365_GBL_IRQ_0_LEV 0x08
+#define I365_GBL_IRQ_1_LEV 0x10
+
+/* Flags for memory window registers */
+#define I365_MEM_16BIT 0x8000 /* In memory start high byte */
+#define I365_MEM_0WS 0x4000
+#define I365_MEM_WS1 0x8000 /* In memory stop high byte */
+#define I365_MEM_WS0 0x4000
+#define I365_MEM_WRPROT 0x8000 /* In offset high byte */
+#define I365_MEM_REG 0x4000
+
+#define I365_REG(slot, reg) (((slot) << 6) + reg)
+
+#endif /* _LINUX_I82365_H */
diff --git a/mdk-stage1/pcmcia/lex_config.l b/mdk-stage1/pcmcia/lex_config.l
new file mode 100644
index 000000000..54500c446
--- /dev/null
+++ b/mdk-stage1/pcmcia/lex_config.l
@@ -0,0 +1,224 @@
+/* Special state for handling include files */
+%x src
+
+%{
+/*
+ * Startup tool for non statically mapped PCMCIA sockets
+ *
+ * (C) 2005 Dominik Brodowski <linux@brodo.de>
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
+ *
+ * License: GPL v2
+ */
+
+#undef src
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <syslog.h>
+
+#ifdef HAS_WORDEXP
+#include <wordexp.h>
+#else
+#include <glob.h>
+#endif
+
+#define src 1
+
+#include "yacc_config.h"
+
+#define YY_NO_INPUT 1 /* mdk-stage1 */
+#define YY_NO_UNPUT 1 /* mdk-stage1 */
+extern int yyparse(void); /* mdk-stage1 */
+
+/* For assembling nice error messages */
+char *current_file;
+int current_lineno;
+
+static int lex_number(char *s);
+static int lex_string(char *s);
+static void do_source(char *fn);
+static int do_eof(void);
+
+%}
+
+int [0-9]+
+hex 0x[0-9a-fA-F]+
+str \"([^"]|\\.)*\"
+
+%%
+
+source[ \t]+ BEGIN(src); return SOURCE;
+<src>[^\n]+ do_source(yytext); BEGIN(INITIAL);
+<<EOF>> if (do_eof()) yyterminate();
+
+\n current_lineno++;
+[ \t]* /* skip */ ;
+[ ]*[#;].* /* skip */ ;
+
+exclude return EXCLUDE;
+include return INCLUDE;
+irq return IRQ_NO;
+port return PORT;
+memory return MEMORY;
+module /* skip */ ;
+
+{int} return lex_number(yytext);
+
+{hex} return lex_number(yytext);
+
+{str} return lex_string(yytext);
+
+. return yytext[0];
+
+%%
+
+#ifndef yywrap
+int yywrap() { return 1; }
+#endif
+
+/*======================================================================
+
+ Stuff to parse basic data types
+
+======================================================================*/
+
+static int lex_number(char *s)
+{
+ yylval.num = strtoul(s, NULL, 0);
+ return NUMBER;
+}
+
+static int lex_string(char *s)
+{
+ int n = strlen(s);
+ yylval.str = malloc(n-1);
+ strncpy(yylval.str, s+1, n-2);
+ yylval.str[n-2] = '\0';
+ return STRING;
+}
+
+/*======================================================================
+
+ Code to support nesting of configuration files
+
+======================================================================*/
+
+#define MAX_SOURCE_DEPTH 4
+struct source_stack {
+ YY_BUFFER_STATE buffer;
+ char *filename;
+ int lineno, fileno;
+ FILE *file;
+#ifdef HAS_WORDEXP
+ wordexp_t word;
+#else
+ glob_t glob;
+#endif
+} source_stack[MAX_SOURCE_DEPTH];
+static int source_stack_ptr = 0;
+static int parse_env = 0;
+
+static int get_glob(void)
+{
+ struct source_stack *s = &source_stack[source_stack_ptr];
+#ifdef HAS_WORDEXP
+ while (s->fileno < s->word.we_wordc) {
+ char *fn = s->word.we_wordv[s->fileno];
+#else
+ while (s->fileno < s->glob.gl_pathc) {
+ char *fn = s->glob.gl_pathv[s->fileno];
+#endif
+ s->file = fopen(fn, "r");
+ if (s->file == NULL) {
+ if (strpbrk(fn, "?*[") == NULL)
+ syslog(LOG_ERR, "could not open '%s': %m", fn);
+ s->fileno++;
+ } else {
+ current_lineno = 1;
+ current_file = strdup(fn);
+ yy_switch_to_buffer(yy_create_buffer(s->file, YY_BUF_SIZE));
+ source_stack_ptr++;
+ s->fileno++;
+ return 0;
+ }
+ }
+ return -1;
+}
+
+static void do_source(char *fn)
+{
+ struct source_stack *s = &source_stack[source_stack_ptr];
+
+ if (source_stack_ptr >= MAX_SOURCE_DEPTH) {
+ syslog(LOG_ERR, "source depth limit exceeded");
+ return;
+ }
+#ifdef HAS_WORDEXP
+ wordexp(fn, &s->word, 0);
+#else
+ glob(fn, GLOB_NOCHECK, NULL, &s->glob);
+#endif
+ s->fileno = 0;
+ s->buffer = YY_CURRENT_BUFFER;
+ s->lineno = current_lineno;
+ s->filename = current_file;
+ get_glob();
+}
+
+static int do_eof(void)
+{
+ struct source_stack *s = &source_stack[--source_stack_ptr];
+ if (source_stack_ptr < 0) {
+ if (parse_env == 0) {
+ char *t = getenv("PCMCIA_OPTS");
+ if (t == NULL) return -1;
+ parse_env = 1;
+ source_stack_ptr = 0;
+ current_file = "PCMCIA_OPTS";
+ current_lineno = 1;
+ yy_scan_string(t);
+ return 0;
+ } else
+ return -1;
+ }
+ fclose(s->file);
+ free(current_file);
+ yy_delete_buffer(YY_CURRENT_BUFFER);
+ if (get_glob() != 0) {
+ yy_switch_to_buffer(s->buffer);
+ current_lineno = s->lineno;
+ current_file = s->filename;
+ }
+ return 0;
+}
+
+/*======================================================================
+
+ The main entry point... returns -1 if the file can't be accessed.
+
+======================================================================*/
+
+int parse_configfile(char *fn)
+{
+ FILE *f;
+
+ f = fopen(fn, "r");
+ if (!f) {
+ syslog(LOG_ERR, "could not open '%s': %m", fn);
+ return -1;
+ }
+ current_lineno = 1;
+ current_file = fn;
+ source_stack_ptr = 0;
+ yyrestart(f);
+ yyparse();
+ fclose(f);
+ return 0;
+}
+
diff --git a/mdk-stage1/pcmcia/merge_from_pcitable b/mdk-stage1/pcmcia/merge_from_pcitable
new file mode 100755
index 000000000..3b88a1cd8
--- /dev/null
+++ b/mdk-stage1/pcmcia/merge_from_pcitable
@@ -0,0 +1,47 @@
+#!/usr/bin/perl
+
+# This program will show on stdout yenta_socket stuff from pcitable
+# which is not in probe.c
+
+use MDK::Common;
+
+my %probes;
+foreach (cat_('probe.c')) {
+ if (/^pci_id_t pci_id\[\] = {/ ... /^};/) {
+ /^\s*{\s*0x([\da-f]+),\s*0x([\da-f]+),\s*"([^"]*)",\s*"([^"]*)"\s*}/
+ and $probes{"$1$2"} = { vendor => $1, device => $2, driver => $3, name => $4 };
+ }
+}
+
+require '/usr/bin/merge2pcitable.pl';
+my $drivers = read_pcitable("/usr/share/ldetect-lst/pcitable");
+
+my %pcitable = map_each {
+ $::a =~ /^(....)(....)/ or die;
+ "$1$2" => { vendor => $1, device => $2, driver => $::b->[0], name => $::b->[1] };
+} %$drivers;
+
+my @yenta_socket_ids = grep { $pcitable{$_}{driver} eq 'yenta_socket' } keys %pcitable;
+
+if (my @missing_in_probe_c = difference2(\@yenta_socket_ids, [ keys %probes ])) {
+ print "Missing in `probe.c':\n",
+ map {
+ my $p = $pcitable{$_};
+ qq( { 0x$p->{vendor}, 0x$p->{device}, "yenta_socket", "$p->{name}" },\n);
+ } sort @missing_in_probe_c;
+}
+
+my @res;
+foreach my $id (keys %probes) {
+ my $p = $probes{$id};
+ my $r = $pcitable{$id};
+ if (!$r || $r->{driver} ne 'yenta_socket') {
+ push @res, qq(0x$p->{vendor}\t0x$p->{device}\t"yenta_socket"\t") . ($r ? $r->{name} : '(COMPLETELY MISSING)') . qq("\n);
+ }
+ if ($r && $r->{driver} ne 'unknown' && $r->{driver} ne $p->{driver}) {
+ warn "WARNING: $id: pcitable:$r->{driver} vs probe.c:$p->{driver}\n";
+ }
+}
+if (@res) {
+ print "\n", "Missing in pcitable:\n", sort @res;
+}
diff --git a/mdk-stage1/pcmcia/pcmcia.h b/mdk-stage1/pcmcia/pcmcia.h
new file mode 100644
index 000000000..ea0bccc2a
--- /dev/null
+++ b/mdk-stage1/pcmcia/pcmcia.h
@@ -0,0 +1,21 @@
+/*
+ * Guillaume Cottenceau (gc@mandrakesoft.com)
+ *
+ * Copyright 2000 Mandrakesoft
+ *
+ * This software may be freely redistributed under the terms of the GNU
+ * public license.
+ *
+ * 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.
+ *
+ */
+
+#ifndef _PCMCIA_CARDMGR_INTERFACE_H_
+#define _PCMCIA_CARDMGR_INTERFACE_H_
+
+char * pcmcia_probe(void);
+void pcmcia_socket_startup(int socket_no);
+
+#endif
diff --git a/mdk-stage1/pcmcia/probe.c b/mdk-stage1/pcmcia/probe.c
new file mode 100644
index 000000000..8f8a4bc8e
--- /dev/null
+++ b/mdk-stage1/pcmcia/probe.c
@@ -0,0 +1,524 @@
+/*
+ * Guillaume Cottenceau (gc@mandrakesoft.com)
+ *
+ * Copyright 2000-2001 Mandrakesoft
+ *
+ * This software may be freely redistributed under the terms of the GNU
+ * public license.
+ *
+ * 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.
+ *
+ *
+ * Code comes from /anonymous@projects.sourceforge.net:/pub/pcmcia-cs/pcmcia-cs-3.1.29.tar.bz2
+ */
+
+/*======================================================================
+
+ PCMCIA controller probe
+
+ probe.c 1.55 2001/08/24 12:19:20
+
+ The contents of this file are subject to the Mozilla Public
+ License Version 1.1 (the "License"); you may not use this file
+ except in compliance with the License. You may obtain a copy of
+ the License at http://www.mozilla.org/MPL/
+
+ Software distributed under the License is distributed on an "AS
+ IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ implied. See the License for the specific language governing
+ rights and limitations under the License.
+
+ The initial developer of the original code is David A. Hinds
+ <dahinds@users.sourceforge.net>. Portions created by David A. Hinds
+ are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
+
+ Alternatively, the contents of this file may be used under the
+ terms of the GNU General Public License version 2 (the "GPL"), in
+ which case the provisions of the GPL are applicable instead of the
+ above. If you wish to allow the use of your version of this file
+ only under the terms of the GPL and not to allow others to use
+ your version of this file under the MPL, indicate your decision
+ by deleting the provisions above and replace them with the notice
+ and other provisions required by the GPL. If you do not delete
+ the provisions above, a recipient may use your version of this
+ file under either the MPL or the GPL.
+
+======================================================================*/
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+
+//mdk-stage1// #include <pcmcia/config.h>
+#include "log.h"
+#include "pcmcia.h"
+
+/*====================================================================*/
+
+//mdk-stage1// #ifdef CONFIG_PCI
+
+typedef struct {
+ u_short vendor, device;
+ char *modname;
+ char *name;
+} pci_id_t;
+
+pci_id_t pci_id[] = {
+ { 0x1013, 0x1100, "i82365", "Cirrus Logic CL 6729" },
+ { 0x1013, 0x1110, "yenta_socket", "Cirrus Logic PD 6832" },
+ { 0x10b3, 0xb106, "yenta_socket", "SMC 34C90" },
+ { 0x1180, 0x0465, "yenta_socket", "Ricoh RL5C465" },
+ { 0x1180, 0x0466, "yenta_socket", "Ricoh RL5C466" },
+ { 0x1180, 0x0475, "yenta_socket", "Ricoh RL5C475" },
+ { 0x1180, 0x0476, "yenta_socket", "Ricoh RL5C476" },
+ { 0x1180, 0x0477, "yenta_socket", "Ricoh RL5C477" },
+ { 0x1180, 0x0478, "yenta_socket", "Ricoh RL5C478" },
+ { 0x104c, 0xac12, "yenta_socket", "Texas Instruments PCI1130" },
+ { 0x104c, 0xac13, "yenta_socket", "Texas Instruments PCI1031" },
+ { 0x104c, 0xac15, "yenta_socket", "Texas Instruments PCI1131" },
+ { 0x104c, 0xac1a, "yenta_socket", "Texas Instruments PCI1210" },
+ { 0x104c, 0xac1e, "yenta_socket", "Texas Instruments PCI1211" },
+ { 0x104c, 0xac17, "yenta_socket", "Texas Instruments PCI1220" },
+ { 0x104c, 0xac19, "yenta_socket", "Texas Instruments PCI1221" },
+ { 0x104c, 0xac1c, "yenta_socket", "Texas Instruments PCI1225" },
+ { 0x104c, 0xac16, "yenta_socket", "Texas Instruments PCI1250" },
+ { 0x104c, 0xac1d, "yenta_socket", "Texas Instruments PCI1251A" },
+ { 0x104c, 0xac1f, "yenta_socket", "Texas Instruments PCI1251B" },
+ { 0x104c, 0xac50, "yenta_socket", "Texas Instruments PCI1410" },
+ { 0x104c, 0xac51, "yenta_socket", "Texas Instruments PCI1420" },
+ { 0x104c, 0xac1b, "yenta_socket", "Texas Instruments PCI1450" },
+ { 0x104c, 0xac52, "yenta_socket", "Texas Instruments PCI1451" },
+ { 0x104c, 0xac56, "yenta_socket", "Texas Instruments PCI1510" },
+ { 0x104c, 0xac55, "yenta_socket", "Texas Instruments PCI1520" },
+ { 0x104c, 0xac54, "yenta_socket", "Texas Instruments PCI1620" },
+ { 0x104c, 0xac41, "yenta_socket", "Texas Instruments PCI4410" },
+ { 0x104c, 0xac40, "yenta_socket", "Texas Instruments PCI4450" },
+ { 0x104c, 0xac42, "yenta_socket", "Texas Instruments PCI4451" },
+ { 0x104c, 0xac44, "yenta_socket", "Texas Instruments PCI4510" },
+ { 0x104c, 0xac46, "yenta_socket", "Texas Instruments PCI4520" },
+ { 0x104c, 0xac49, "yenta_socket", "Texas Instruments PCI7410" },
+ { 0x104c, 0xac47, "yenta_socket", "Texas Instruments PCI7510" },
+ { 0x104c, 0xac48, "yenta_socket", "Texas Instruments PCI7610" },
+ { 0x104c, 0xac8e, "yenta_socket", "Texas Instruments PCI7420" },
+ { 0x1217, 0x6729, "i82365", "O2 Micro 6729" },
+ { 0x1217, 0x673a, "i82365", "O2 Micro 6730" },
+ { 0x1217, 0x6832, "yenta_socket", "O2 Micro 6832/6833" },
+ { 0x1217, 0x6836, "yenta_socket", "O2 Micro 6836/6860" },
+ { 0x1217, 0x6872, "yenta_socket", "O2 Micro 6812" },
+ { 0x1217, 0x6925, "yenta_socket", "O2 Micro 6922" },
+ { 0x1217, 0x6933, "yenta_socket", "O2 Micro 6933" },
+ { 0x1217, 0x6972, "yenta_socket", "O2 Micro 6912" },
+ { 0x1217, 0x7114, "yenta_socket", "O2 Micro 711M1" },
+ { 0x1179, 0x0603, "i82365", "Toshiba ToPIC95-A" },
+ { 0x1179, 0x060a, "yenta_socket", "Toshiba ToPIC95-B" },
+ { 0x1179, 0x060f, "yenta_socket", "Toshiba ToPIC97" },
+ { 0x1179, 0x0617, "yenta_socket", "Toshiba ToPIC100" },
+ { 0x119b, 0x1221, "i82365", "Omega Micro 82C092G" },
+ { 0x8086, 0x1221, "i82092", "Intel 82092AA_0" },
+ { 0x8086, 0x1222, "i82092", "Intel 82092AA_1" },
+ { 0x1524, 0x1211, "yenta_socket", "ENE 1211" },
+ { 0x1524, 0x1225, "yenta_socket", "ENE 1225" },
+ { 0x1524, 0x1410, "yenta_socket", "ENE 1410" },
+ { 0x1524, 0x1411, "yenta_socket", "ENE Technology CB1411" },
+ { 0x1524, 0x1420, "yenta_socket", "ENE 1420" },
+};
+#define PCI_COUNT (sizeof(pci_id)/sizeof(pci_id_t))
+
+char * driver = NULL;
+
+static int pci_probe(void)
+{
+ char s[256], *name = NULL;
+ u_int device, vendor, i;
+ FILE *f;
+
+//mdk-stage1// if (!module)
+ log_message("PCMCIA: probing PCI bus..");
+
+ if ((f = fopen("/proc/bus/pci/devices", "r")) != NULL) {
+ while (fgets(s, 256, f) != NULL) {
+ u_int n = strtoul(s+5, NULL, 16);
+ vendor = (n >> 16); device = (n & 0xffff);
+ for (i = 0; i < PCI_COUNT; i++)
+ if ((vendor == pci_id[i].vendor) &&
+ (device == pci_id[i].device)) break;
+ if (i < PCI_COUNT) {
+ name = pci_id[i].name;
+ driver = pci_id[i].modname;
+ }
+ }
+ }
+//mdk-stage1// else if ((f = fopen("/proc/pci", "r")) != NULL) {
+//mdk-stage1// while (fgets(s, 256, f) != NULL) {
+//mdk-stage1// t = strstr(s, "Device id=");
+//mdk-stage1// if (t) {
+//mdk-stage1// device = strtoul(t+10, NULL, 16);
+//mdk-stage1// t = strstr(s, "Vendor id=");
+//mdk-stage1// vendor = strtoul(t+10, NULL, 16);
+//mdk-stage1// for (i = 0; i < PCI_COUNT; i++)
+//mdk-stage1// if ((vendor == pci_id[i].vendor) &&
+//mdk-stage1// (device == pci_id[i].device)) break;
+//mdk-stage1// } else
+//mdk-stage1// for (i = 0; i < PCI_COUNT; i++)
+//mdk-stage1// if (strstr(s, pci_id[i].tag) != NULL) break;
+//mdk-stage1// if (i != PCI_COUNT) {
+//mdk-stage1// name = pci_id[i].name;
+//mdk-stage1// break;
+//mdk-stage1// } else {
+//mdk-stage1// t = strstr(s, "CardBus bridge");
+//mdk-stage1// if (t != NULL) {
+//mdk-stage1// name = t + 16;
+//mdk-stage1// t = strchr(s, '(');
+//mdk-stage1// t[-1] = '\0';
+//mdk-stage1// break;
+//mdk-stage1// }
+//mdk-stage1// }
+//mdk-stage1// }
+//mdk-stage1// }
+ fclose(f);
+
+ if (name) {
+//mdk-stage1// if (module)
+//mdk-stage1// printf("i82365\n");
+//mdk-stage1// else
+ log_message("\t%s found, 2 sockets (driver %s).", name, driver);
+ return 0;
+ } else {
+//mdk-stage1// if (!module)
+ log_message("\tnot found.");
+ return -ENODEV;
+ }
+}
+//mdk-stage1// #endif
+
+/*====================================================================*/
+
+//mdk-stage1// #ifdef CONFIG_ISA
+//mdk-stage1//
+//mdk-stage1// #ifdef __GLIBC__
+#include <sys/io.h>
+//mdk-stage1// #else
+//mdk-stage1// #include <asm/io.h>
+//mdk-stage1// #endif
+typedef u_short ioaddr_t;
+
+#include "i82365.h"
+#include "cirrus.h"
+#include "vg468.h"
+
+static ioaddr_t i365_base = 0x03e0;
+
+static u_char i365_get(u_short sock, u_short reg)
+{
+ u_char val = I365_REG(sock, reg);
+ outb(val, i365_base); val = inb(i365_base+1);
+ return val;
+}
+
+static void i365_set(u_short sock, u_short reg, u_char data)
+{
+ u_char val = I365_REG(sock, reg);
+ outb(val, i365_base); outb(data, i365_base+1);
+}
+
+static void i365_bset(u_short sock, u_short reg, u_char mask)
+{
+ u_char d = i365_get(sock, reg);
+ d |= mask;
+ i365_set(sock, reg, d);
+}
+
+static void i365_bclr(u_short sock, u_short reg, u_char mask)
+{
+ u_char d = i365_get(sock, reg);
+ d &= ~mask;
+ i365_set(sock, reg, d);
+}
+
+int i365_probe(void)
+{
+ int val, sock, done;
+ char *name = "i82365sl";
+
+//mdk-stage1// if (!module)
+ log_message("PCMCIA: probing for Intel PCIC (ISA)..");
+//mdk-stage1// if (verbose) printf("\n");
+
+ sock = done = 0;
+ if (ioperm(i365_base, 4, 1)) {
+ log_perror("PCMCIA: ioperm");
+ return -1;
+ }
+ ioperm(0x80, 1, 1);
+ for (; sock < 2; sock++) {
+ val = i365_get(sock, I365_IDENT);
+//mdk-stage1// if (verbose)
+//mdk-stage1// printf(" ident(%d)=%#2.2x", sock, val);
+ switch (val) {
+ case 0x82:
+ name = "i82365sl A step";
+ break;
+ case 0x83:
+ name = "i82365sl B step";
+ break;
+ case 0x84:
+ name = "VLSI 82C146";
+ break;
+ case 0x88: case 0x89: case 0x8a:
+ name = "IBM Clone";
+ break;
+ case 0x8b: case 0x8c:
+ break;
+ default:
+ done = 1;
+ }
+ if (done) break;
+ }
+
+//mdk-stage1// if (verbose) printf("\n ");
+ if (sock == 0) {
+//mdk-stage1// if (!module)
+ log_message("\tnot found.");
+ return -ENODEV;
+ }
+
+ if ((sock == 2) && (strcmp(name, "VLSI 82C146") == 0))
+ name = "i82365sl DF";
+
+ /* Check for Vadem chips */
+ outb(0x0e, i365_base);
+ outb(0x37, i365_base);
+ i365_bset(0, VG468_MISC, VG468_MISC_VADEMREV);
+ val = i365_get(0, I365_IDENT);
+ if (val & I365_IDENT_VADEM) {
+ if ((val & 7) < 4)
+ name = "Vadem VG-468";
+ else
+ name = "Vadem VG-469";
+ i365_bclr(0, VG468_MISC, VG468_MISC_VADEMREV);
+ }
+
+ /* Check for Cirrus CL-PD67xx chips */
+ i365_set(0, PD67_CHIP_INFO, 0);
+ val = i365_get(0, PD67_CHIP_INFO);
+ if ((val & PD67_INFO_CHIP_ID) == PD67_INFO_CHIP_ID) {
+ val = i365_get(0, PD67_CHIP_INFO);
+ if ((val & PD67_INFO_CHIP_ID) == 0) {
+ if (val & PD67_INFO_SLOTS)
+ name = "Cirrus CL-PD672x";
+ else {
+ name = "Cirrus CL-PD6710";
+ sock = 1;
+ }
+ i365_set(0, PD67_EXT_INDEX, 0xe5);
+ if (i365_get(0, PD67_EXT_INDEX) != 0xe5)
+ name = "VIA VT83C469";
+ }
+ }
+
+//mdk-stage1// if (module)
+//mdk-stage1// printf("i82365\n");
+//mdk-stage1// else
+ printf("\t%s found, %d sockets.\n", name, sock);
+ return 0;
+
+} /* i365_probe */
+
+//mdk-stage1//#endif /* CONFIG_ISA */
+
+/*====================================================================*/
+
+//mdk-stage1//#ifdef CONFIG_ISA
+
+#include "tcic.h"
+
+//mdk-stage1//static ioaddr_t tcic_base = TCIC_BASE;
+
+static u_char tcic_getb(ioaddr_t base, u_char reg)
+{
+ u_char val = inb(base+reg);
+ return val;
+}
+
+static void tcic_setb(ioaddr_t base, u_char reg, u_char data)
+{
+ outb(data, base+reg);
+}
+
+static u_short tcic_getw(ioaddr_t base, u_char reg)
+{
+ u_short val = inw(base+reg);
+ return val;
+}
+
+static void tcic_setw(ioaddr_t base, u_char reg, u_short data)
+{
+ outw(data, base+reg);
+}
+
+static u_short tcic_aux_getw(ioaddr_t base, u_short reg)
+{
+ u_char mode = (tcic_getb(base, TCIC_MODE) & TCIC_MODE_PGMMASK) | reg;
+ tcic_setb(base, TCIC_MODE, mode);
+ return tcic_getw(base, TCIC_AUX);
+}
+
+static void tcic_aux_setw(ioaddr_t base, u_short reg, u_short data)
+{
+ u_char mode = (tcic_getb(base, TCIC_MODE) & TCIC_MODE_PGMMASK) | reg;
+ tcic_setb(base, TCIC_MODE, mode);
+ tcic_setw(base, TCIC_AUX, data);
+}
+
+static int get_tcic_id(ioaddr_t base)
+{
+ u_short id;
+ tcic_aux_setw(base, TCIC_AUX_TEST, TCIC_TEST_DIAG);
+ id = tcic_aux_getw(base, TCIC_AUX_ILOCK);
+ id = (id & TCIC_ILOCKTEST_ID_MASK) >> TCIC_ILOCKTEST_ID_SH;
+ tcic_aux_setw(base, TCIC_AUX_TEST, 0);
+ return id;
+}
+
+int tcic_probe_at(ioaddr_t base)
+{
+ int i;
+ u_short old;
+
+ /* Anything there?? */
+ for (i = 0; i < 0x10; i += 2)
+ if (tcic_getw(base, i) == 0xffff)
+ return -1;
+
+//mdk-stage1// if (!module)
+ log_message("\tat %#3.3x: ", base); fflush(stdout);
+
+ /* Try to reset the chip */
+ tcic_setw(base, TCIC_SCTRL, TCIC_SCTRL_RESET);
+ tcic_setw(base, TCIC_SCTRL, 0);
+
+ /* Can we set the addr register? */
+ old = tcic_getw(base, TCIC_ADDR);
+ tcic_setw(base, TCIC_ADDR, 0);
+ if (tcic_getw(base, TCIC_ADDR) != 0) {
+ tcic_setw(base, TCIC_ADDR, old);
+ return -2;
+ }
+
+ tcic_setw(base, TCIC_ADDR, 0xc3a5);
+ if (tcic_getw(base, TCIC_ADDR) != 0xc3a5)
+ return -3;
+
+ return 2;
+}
+
+int tcic_probe(void)
+{
+ int sock, id;
+
+//mdk-stage1// if (!module)
+ log_message("PCMCIA: probing for Databook TCIC-2 (ISA).."); fflush(stdout);
+
+ if (ioperm(TCIC_BASE, 16, 1)) {
+ log_perror("PCMCIA: ioperm");
+ return -1;
+ }
+ ioperm(0x80, 1, 1);
+ sock = tcic_probe_at(TCIC_BASE);
+
+ if (sock <= 0) {
+//mdk-stage1// if (!module)
+ log_message("\tnot found.");
+ return -ENODEV;
+ }
+
+//mdk-stage1// if (module)
+//mdk-stage1// printf("tcic\n");
+//mdk-stage1// else {
+ id = get_tcic_id(TCIC_BASE);
+ switch (id) {
+ case TCIC_ID_DB86082:
+ log_message("DB86082"); break;
+ case TCIC_ID_DB86082A:
+ log_message("DB86082A"); break;
+ case TCIC_ID_DB86084:
+ log_message("DB86084"); break;
+ case TCIC_ID_DB86084A:
+ log_message("DB86084A"); break;
+ case TCIC_ID_DB86072:
+ log_message("DB86072"); break;
+ case TCIC_ID_DB86184:
+ log_message("DB86184"); break;
+ case TCIC_ID_DB86082B:
+ log_message("DB86082B"); break;
+ default:
+ log_message("Unknown TCIC-2 ID 0x%02x", id);
+ }
+ log_message(" found at %#6x, %d sockets.", TCIC_BASE, sock);
+//mdk-stage1// }
+ return 0;
+
+} /* tcic_probe */
+
+//mdk-stage1// #endif /* CONFIG_ISA */
+
+//mdk-stage1// /*====================================================================*/
+//mdk-stage1//
+//mdk-stage1// int main(int argc, char *argv[])
+//mdk-stage1// {
+//mdk-stage1// int optch, errflg;
+//mdk-stage1// extern char *optarg;
+//mdk-stage1// int verbose = 0, module = 0;
+//mdk-stage1//
+//mdk-stage1// errflg = 0;
+//mdk-stage1// while ((optch = getopt(argc, argv, "t:vxm")) != -1) {
+//mdk-stage1// switch (optch) {
+//mdk-stage1// #ifdef CONFIG_ISA
+//mdk-stage1// case 't':
+//mdk-stage1// tcic_base = strtoul(optarg, NULL, 0); break;
+//mdk-stage1// #endif
+//mdk-stage1// case 'v':
+//mdk-stage1// verbose = 1; break;
+//mdk-stage1// case 'm':
+//mdk-stage1// module = 1; break;
+//mdk-stage1// default:
+//mdk-stage1// errflg = 1; break;
+//mdk-stage1// }
+//mdk-stage1// }
+//mdk-stage1// if (errflg || (optind < argc)) {
+//mdk-stage1// fprintf(stderr, "usage: %s [-t tcic_base] [-v] [-m]\n", argv[0]);
+//mdk-stage1// exit(EXIT_FAILURE);
+//mdk-stage1// }
+//mdk-stage1//
+//mdk-stage1// #ifdef CONFIG_PCI
+//mdk-stage1// if (pci_probe(verbose, module) == 0)
+//mdk-stage1// exit(EXIT_SUCCESS);
+//mdk-stage1// #endif
+//mdk-stage1// #ifdef CONFIG_ISA
+//mdk-stage1// if (i365_probe(verbose, module) == 0)
+//mdk-stage1// exit(EXIT_SUCCESS);
+//mdk-stage1// else if (tcic_probe(verbose, module, tcic_base) == 0)
+//mdk-stage1// exit(EXIT_SUCCESS);
+//mdk-stage1// #endif
+//mdk-stage1// exit(EXIT_FAILURE);
+//mdk-stage1// return 0;
+//mdk-stage1// }
+
+
+char * pcmcia_probe(void)
+{
+ if (!pci_probe())
+ return driver;
+ else if (!i365_probe())
+ return "i82365";
+ else if (!tcic_probe())
+ return "tcic";
+ else
+ return NULL;
+}
diff --git a/mdk-stage1/pcmcia/startup.c b/mdk-stage1/pcmcia/startup.c
new file mode 100644
index 000000000..e9004484a
--- /dev/null
+++ b/mdk-stage1/pcmcia/startup.c
@@ -0,0 +1,271 @@
+/*
+ * Startup tool for non statically mapped PCMCIA sockets
+ *
+ * (C) 2005 Dominik Brodowski <linux@brodo.de>
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
+ *
+ * License: GPL v2
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#include <sysfs/libsysfs.h>
+
+#include "startup.h"
+
+/* uncomment for debug output */
+#ifdef DEBUG
+#define dprintf printf
+#else
+#define dprintf(...) do { } while(0);
+#endif
+
+/* Linked list of resource adjustments */
+struct adjust_list_t *root_adjust = NULL;
+
+/* path for config file, device scripts */
+static char *configpath = "/etc/pcmcia";
+
+enum {
+ RESOURCE_MEM,
+ RESOURCE_IO,
+ MAX_RESOURCE_FILES
+};
+
+
+static const char *resource_files[MAX_RESOURCE_FILES] = {
+ [RESOURCE_MEM] = "available_resources_mem",
+ [RESOURCE_IO] = "available_resources_io",
+};
+
+#define PATH_TO_SOCKET "/sys/class/pcmcia_socket/"
+
+
+static int add_available_resource(unsigned int socket_no, unsigned int type,
+ unsigned int action,
+ unsigned long start, unsigned long end)
+{
+ char file[SYSFS_PATH_MAX];
+ char content[SYSFS_PATH_MAX];
+ struct sysfs_attribute *attr;
+ int ret;
+ size_t len;
+
+ if (type >= MAX_RESOURCE_FILES)
+ return -EINVAL;
+
+ if (end <= start)
+ return -EINVAL;
+
+ dprintf("%d %d %d 0x%lx 0x%lx\n", socket_no, type, action, start, end);
+
+ snprintf(file, SYSFS_PATH_MAX, PATH_TO_SOCKET "pcmcia_socket%u/%s",
+ socket_no, resource_files[type]);
+
+ switch(action) {
+ case ADD_MANAGED_RESOURCE:
+ len = snprintf(content, SYSFS_PATH_MAX,
+ "0x%08lx - 0x%08lx", start, end);
+ break;
+
+ case REMOVE_MANAGED_RESOURCE:
+ len = snprintf(content, SYSFS_PATH_MAX,
+ "- 0x%08lx - 0x%08lx", start, end);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ dprintf("content is %s\n", content);
+
+ dprintf("file is %s\n", file);
+
+ attr = sysfs_open_attribute(file);
+ if (!attr)
+ return -ENODEV;
+
+ dprintf("open, len %d\n", len);
+
+ ret = sysfs_write_attribute(attr, content, len);
+
+ dprintf("ret is %d\n", ret);
+
+ sysfs_close_attribute(attr);
+
+ return (ret);
+}
+
+static int setup_done(unsigned int socket_no)
+{
+ int ret;
+ char file[SYSFS_PATH_MAX];
+ struct sysfs_attribute *attr;
+
+ snprintf(file, SYSFS_PATH_MAX, PATH_TO_SOCKET
+ "pcmcia_socket%u/available_resources_setup_done",
+ socket_no);
+
+ attr = sysfs_open_attribute(file);
+ if (!attr)
+ return -ENODEV;
+
+ ret = sysfs_write_attribute(attr, "42", 2);
+
+ sysfs_close_attribute(attr);
+
+ return (ret);
+}
+
+
+static int disallow_irq(unsigned int socket_no, unsigned int irq)
+{
+ char file[SYSFS_PATH_MAX];
+ char content[SYSFS_PATH_MAX];
+ struct sysfs_attribute *attr;
+ unsigned int mask = 0xfff;
+ unsigned int new_mask;
+ int ret;
+ size_t len;
+
+ if (irq >= 32)
+ return -EINVAL;
+
+ len = snprintf(file, SYSFS_PATH_MAX, PATH_TO_SOCKET
+ "pcmcia_socket%u/card_irq_mask",
+ socket_no);
+ dprintf("file is %s\n", file);
+
+ attr = sysfs_open_attribute(file);
+ if (!attr)
+ return -ENODEV;
+
+ dprintf("open, len %d\n", len);
+
+ ret = sysfs_read_attribute(attr);
+ if (ret) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (!attr->value || (attr->len < 6)) {
+ ret = -EIO;
+ goto out;
+ }
+
+ ret = sscanf(attr->value, "0x%x\n", &mask);
+
+ new_mask = 1 << irq;
+
+ mask &= ~new_mask;
+
+ len = snprintf(content, SYSFS_PATH_MAX, "0x%04x", mask);
+
+ dprintf("content is %s\n", content);
+
+ ret = sysfs_write_attribute(attr, content, len);
+
+ out:
+ sysfs_close_attribute(attr);
+
+ return (ret);
+}
+
+
+static void load_config(void)
+{
+ if (chdir(configpath) != 0) {
+ syslog(LOG_ERR, "chdir to %s failed: %m", configpath);
+ exit(EXIT_FAILURE);
+ }
+ parse_configfile("config.opts");
+ return;
+}
+
+
+static void adjust_resources(unsigned int socket_no)
+{
+ adjust_list_t *al;
+
+ for (al = root_adjust; al; al = al->next) {
+ switch (al->adj.Resource) {
+ case RES_MEMORY_RANGE:
+ add_available_resource(socket_no, RESOURCE_MEM,
+ al->adj.Action,
+ al->adj.resource.memory.Base,
+ al->adj.resource.memory.Base +
+ al->adj.resource.memory.Size - 1);
+ break;
+ case RES_IO_RANGE:
+ add_available_resource(socket_no, RESOURCE_IO,
+ al->adj.Action,
+ al->adj.resource.io.BasePort,
+ al->adj.resource.io.BasePort +
+ al->adj.resource.io.NumPorts - 1);
+ break;
+ case RES_IRQ:
+ if(al->adj.Action == REMOVE_MANAGED_RESOURCE)
+ disallow_irq(socket_no, al->adj.resource.irq.IRQ);
+ break;
+ }
+ }
+}
+
+/* mdk-stage1
+int main(int argc, char *argv[])
+{
+ char *socket_no;
+ unsigned long socket, i;
+ unsigned int all_sockets = 0;
+
+
+ if ((socket_no = getenv("SOCKET_NO"))) {
+ socket = strtoul(socket_no, NULL, 0);
+ } else if (argc == 2) {
+ socket = strtoul(argv[1], NULL, 0);
+ } else if (argc == 1) {
+ socket = 0;
+ all_sockets = 1;
+ } else {
+ return -EINVAL;
+ }
+
+ load_config();
+
+ for (i = 0; i < MAX_SOCKS; i++) {
+ if ((socket != i) && (!all_sockets))
+ continue;
+
+ adjust_resources(i);
+ setup_done(i);
+ }
+
+ return 0;
+}
+*/
+
+void pcmcia_socket_startup(int socket_no) {
+ unsigned long i;
+ unsigned int all_sockets = 0;
+
+ if (socket_no == -1)
+ all_sockets = 1;
+
+ load_config();
+
+ for (i = 0; i < MAX_SOCKS; i++) {
+ if ((socket_no != i) && (!all_sockets))
+ continue;
+
+ adjust_resources(i);
+ setup_done(i);
+ }
+}
diff --git a/mdk-stage1/pcmcia/startup.h b/mdk-stage1/pcmcia/startup.h
new file mode 100644
index 000000000..ba6af2c15
--- /dev/null
+++ b/mdk-stage1/pcmcia/startup.h
@@ -0,0 +1,54 @@
+/*
+ * Startup tool for non statically mapped PCMCIA sockets
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
+ *
+ * License: GPL v2
+ *
+ */
+
+#define MAX_SOCKS 8
+#define MAX_BINDINGS 4
+#define MAX_MODULES 4
+
+/* for AdjustResourceInfo */
+typedef struct adjust_t {
+ unsigned int Action;
+ unsigned int Resource;
+ unsigned int Attributes;
+ union {
+ struct memory {
+ unsigned long Base;
+ unsigned long Size;
+ } memory;
+ struct io {
+ unsigned long BasePort;
+ unsigned long NumPorts;
+ unsigned int IOAddrLines;
+ } io;
+ struct irq {
+ unsigned int IRQ;
+ } irq;
+ } resource;
+} adjust_t;
+
+
+typedef struct adjust_list_t {
+ adjust_t adj;
+ struct adjust_list_t *next;
+} adjust_list_t;
+
+
+extern adjust_list_t *root_adjust;
+
+int parse_configfile(char *fn);
+
+
+#define RES_MEMORY_RANGE 1
+#define RES_IO_RANGE 2
+#define RES_IRQ 3
+#define RES_RESERVED 0x10
+#define REMOVE_MANAGED_RESOURCE 1
+#define ADD_MANAGED_RESOURCE 2
diff --git a/mdk-stage1/pcmcia/tcic.h b/mdk-stage1/pcmcia/tcic.h
new file mode 100644
index 000000000..cad193885
--- /dev/null
+++ b/mdk-stage1/pcmcia/tcic.h
@@ -0,0 +1,266 @@
+/*
+ * tcic.h 1.15 2001/08/24 12:15:34
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License version 2 (the "GPL"), in
+ * which case the provisions of the GPL are applicable instead of the
+ * above. If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL. If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ */
+
+#ifndef _LINUX_TCIC_H
+#define _LINUX_TCIC_H
+
+#define TCIC_BASE 0x240
+
+/* offsets of registers from TCIC_BASE */
+#define TCIC_DATA 0x00
+#define TCIC_ADDR 0x02
+#define TCIC_SCTRL 0x06
+#define TCIC_SSTAT 0x07
+#define TCIC_MODE 0x08
+#define TCIC_PWR 0x09
+#define TCIC_EDC 0x0A
+#define TCIC_ICSR 0x0C
+#define TCIC_IENA 0x0D
+#define TCIC_AUX 0x0E
+
+#define TCIC_SS_SHFT 12
+#define TCIC_SS_MASK 0x7000
+
+/* Flags for TCIC_ADDR */
+#define TCIC_ADR2_REG 0x8000
+#define TCIC_ADR2_INDREG 0x0800
+
+#define TCIC_ADDR_REG 0x80000000
+#define TCIC_ADDR_SS_SHFT (TCIC_SS_SHFT+16)
+#define TCIC_ADDR_SS_MASK (TCIC_SS_MASK<<16)
+#define TCIC_ADDR_INDREG 0x08000000
+#define TCIC_ADDR_IO 0x04000000
+#define TCIC_ADDR_MASK 0x03ffffff
+
+/* Flags for TCIC_SCTRL */
+#define TCIC_SCTRL_ENA 0x01
+#define TCIC_SCTRL_INCMODE 0x18
+#define TCIC_SCTRL_INCMODE_HOLD 0x00
+#define TCIC_SCTRL_INCMODE_WORD 0x08
+#define TCIC_SCTRL_INCMODE_REG 0x10
+#define TCIC_SCTRL_INCMODE_AUTO 0x18
+#define TCIC_SCTRL_EDCSUM 0x20
+#define TCIC_SCTRL_RESET 0x80
+
+/* Flags for TCIC_SSTAT */
+#define TCIC_SSTAT_6US 0x01
+#define TCIC_SSTAT_10US 0x02
+#define TCIC_SSTAT_PROGTIME 0x04
+#define TCIC_SSTAT_LBAT1 0x08
+#define TCIC_SSTAT_LBAT2 0x10
+#define TCIC_SSTAT_RDY 0x20 /* Inverted */
+#define TCIC_SSTAT_WP 0x40
+#define TCIC_SSTAT_CD 0x80 /* Card detect */
+
+/* Flags for TCIC_MODE */
+#define TCIC_MODE_PGMMASK 0x1f
+#define TCIC_MODE_NORMAL 0x00
+#define TCIC_MODE_PGMWR 0x01
+#define TCIC_MODE_PGMRD 0x02
+#define TCIC_MODE_PGMCE 0x04
+#define TCIC_MODE_PGMDBW 0x08
+#define TCIC_MODE_PGMWORD 0x10
+#define TCIC_MODE_AUXSEL_MASK 0xe0
+
+/* Registers accessed through TCIC_AUX, by setting TCIC_MODE */
+#define TCIC_AUX_TCTL (0<<5)
+#define TCIC_AUX_PCTL (1<<5)
+#define TCIC_AUX_WCTL (2<<5)
+#define TCIC_AUX_EXTERN (3<<5)
+#define TCIC_AUX_PDATA (4<<5)
+#define TCIC_AUX_SYSCFG (5<<5)
+#define TCIC_AUX_ILOCK (6<<5)
+#define TCIC_AUX_TEST (7<<5)
+
+/* Flags for TCIC_PWR */
+#define TCIC_PWR_VCC(sock) (0x01<<(sock))
+#define TCIC_PWR_VCC_MASK 0x03
+#define TCIC_PWR_VPP(sock) (0x08<<(sock))
+#define TCIC_PWR_VPP_MASK 0x18
+#define TCIC_PWR_CLIMENA 0x40
+#define TCIC_PWR_CLIMSTAT 0x80
+
+/* Flags for TCIC_ICSR */
+#define TCIC_ICSR_CLEAR 0x01
+#define TCIC_ICSR_SET 0x02
+#define TCIC_ICSR_JAM (TCIC_ICSR_CLEAR|TCIC_ICSR_SET)
+#define TCIC_ICSR_STOPCPU 0x04
+#define TCIC_ICSR_ILOCK 0x08
+#define TCIC_ICSR_PROGTIME 0x10
+#define TCIC_ICSR_ERR 0x20
+#define TCIC_ICSR_CDCHG 0x40
+#define TCIC_ICSR_IOCHK 0x80
+
+/* Flags for TCIC_IENA */
+#define TCIC_IENA_CFG_MASK 0x03
+#define TCIC_IENA_CFG_OFF 0x00 /* disabled */
+#define TCIC_IENA_CFG_OD 0x01 /* active low, open drain */
+#define TCIC_IENA_CFG_LOW 0x02 /* active low, totem pole */
+#define TCIC_IENA_CFG_HIGH 0x03 /* active high, totem pole */
+#define TCIC_IENA_ILOCK 0x08
+#define TCIC_IENA_PROGTIME 0x10
+#define TCIC_IENA_ERR 0x20 /* overcurrent or iochk */
+#define TCIC_IENA_CDCHG 0x40
+
+/* Flags for TCIC_AUX_WCTL */
+#define TCIC_WAIT_COUNT_MASK 0x001f
+#define TCIC_WAIT_ASYNC 0x0020
+#define TCIC_WAIT_SENSE 0x0040
+#define TCIC_WAIT_SRC 0x0080
+#define TCIC_WCTL_WR 0x0100
+#define TCIC_WCTL_RD 0x0200
+#define TCIC_WCTL_CE 0x0400
+#define TCIC_WCTL_LLBAT1 0x0800
+#define TCIC_WCTL_LLBAT2 0x1000
+#define TCIC_WCTL_LRDY 0x2000
+#define TCIC_WCTL_LWP 0x4000
+#define TCIC_WCTL_LCD 0x8000
+
+/* Flags for TCIC_AUX_SYSCFG */
+#define TCIC_SYSCFG_IRQ_MASK 0x000f
+#define TCIC_SYSCFG_MCSFULL 0x0010
+#define TCIC_SYSCFG_IO1723 0x0020
+#define TCIC_SYSCFG_MCSXB 0x0040
+#define TCIC_SYSCFG_ICSXB 0x0080
+#define TCIC_SYSCFG_NOPDN 0x0100
+#define TCIC_SYSCFG_MPSEL_SHFT 9
+#define TCIC_SYSCFG_MPSEL_MASK 0x0e00
+#define TCIC_SYSCFG_MPSENSE 0x2000
+#define TCIC_SYSCFG_AUTOBUSY 0x4000
+#define TCIC_SYSCFG_ACC 0x8000
+
+#define TCIC_ILOCK_OUT 0x01
+#define TCIC_ILOCK_SENSE 0x02
+#define TCIC_ILOCK_CRESET 0x04
+#define TCIC_ILOCK_CRESENA 0x08
+#define TCIC_ILOCK_CWAIT 0x10
+#define TCIC_ILOCK_CWAITSNS 0x20
+#define TCIC_ILOCK_HOLD_MASK 0xc0
+#define TCIC_ILOCK_HOLD_CCLK 0xc0
+
+#define TCIC_ILOCKTEST_ID_SH 8
+#define TCIC_ILOCKTEST_ID_MASK 0x7f00
+#define TCIC_ILOCKTEST_MCIC_1 0x8000
+
+#define TCIC_ID_DB86082 0x02
+#define TCIC_ID_DB86082A 0x03
+#define TCIC_ID_DB86084 0x04
+#define TCIC_ID_DB86084A 0x08
+#define TCIC_ID_DB86072 0x15
+#define TCIC_ID_DB86184 0x14
+#define TCIC_ID_DB86082B 0x17
+
+#define TCIC_TEST_DIAG 0x8000
+
+/*
+ * Indirectly addressed registers
+ */
+
+#define TCIC_SCF1(sock) ((sock)<<3)
+#define TCIC_SCF2(sock) (((sock)<<3)+2)
+
+/* Flags for SCF1 */
+#define TCIC_SCF1_IRQ_MASK 0x000f
+#define TCIC_SCF1_IRQ_OFF 0x0000
+#define TCIC_SCF1_IRQOC 0x0010
+#define TCIC_SCF1_PCVT 0x0020
+#define TCIC_SCF1_IRDY 0x0040
+#define TCIC_SCF1_ATA 0x0080
+#define TCIC_SCF1_DMA_SHIFT 8
+#define TCIC_SCF1_DMA_MASK 0x0700
+#define TCIC_SCF1_DMA_OFF 0
+#define TCIC_SCF1_DREQ2 2
+#define TCIC_SCF1_IOSTS 0x0800
+#define TCIC_SCF1_SPKR 0x1000
+#define TCIC_SCF1_FINPACK 0x2000
+#define TCIC_SCF1_DELWR 0x4000
+#define TCIC_SCF1_HD7IDE 0x8000
+
+/* Flags for SCF2 */
+#define TCIC_SCF2_RI 0x0001
+#define TCIC_SCF2_IDBR 0x0002
+#define TCIC_SCF2_MDBR 0x0004
+#define TCIC_SCF2_MLBAT1 0x0008
+#define TCIC_SCF2_MLBAT2 0x0010
+#define TCIC_SCF2_MRDY 0x0020
+#define TCIC_SCF2_MWP 0x0040
+#define TCIC_SCF2_MCD 0x0080
+#define TCIC_SCF2_MALL 0x00f8
+
+/* Indirect addresses for memory window registers */
+#define TCIC_MWIN(sock,map) (0x100+(((map)+((sock)<<2))<<3))
+#define TCIC_MBASE_X 2
+#define TCIC_MMAP_X 4
+#define TCIC_MCTL_X 6
+
+#define TCIC_MBASE_4K_BIT 0x4000
+#define TCIC_MBASE_HA_SHFT 12
+#define TCIC_MBASE_HA_MASK 0x0fff
+
+#define TCIC_MMAP_REG 0x8000
+#define TCIC_MMAP_CA_SHFT 12
+#define TCIC_MMAP_CA_MASK 0x3fff
+
+#define TCIC_MCTL_WSCNT_MASK 0x001f
+#define TCIC_MCTL_WCLK 0x0020
+#define TCIC_MCTL_WCLK_CCLK 0x0000
+#define TCIC_MCTL_WCLK_BCLK 0x0020
+#define TCIC_MCTL_QUIET 0x0040
+#define TCIC_MCTL_WP 0x0080
+#define TCIC_MCTL_ACC 0x0100
+#define TCIC_MCTL_KE 0x0200
+#define TCIC_MCTL_EDC 0x0400
+#define TCIC_MCTL_B8 0x0800
+#define TCIC_MCTL_SS_SHFT TCIC_SS_SHFT
+#define TCIC_MCTL_SS_MASK TCIC_SS_MASK
+#define TCIC_MCTL_ENA 0x8000
+
+/* Indirect addresses for I/O window registers */
+#define TCIC_IWIN(sock,map) (0x200+(((map)+((sock)<<1))<<2))
+#define TCIC_IBASE_X 0
+#define TCIC_ICTL_X 2
+
+#define TCIC_ICTL_WSCNT_MASK TCIC_MCTL_WSCNT_MASK
+#define TCIC_ICTL_QUIET TCIC_MCTL_QUIET
+#define TCIC_ICTL_1K 0x0080
+#define TCIC_ICTL_PASS16 0x0100
+#define TCIC_ICTL_ACC TCIC_MCTL_ACC
+#define TCIC_ICTL_TINY 0x0200
+#define TCIC_ICTL_B16 0x0400
+#define TCIC_ICTL_B8 TCIC_MCTL_B8
+#define TCIC_ICTL_BW_MASK (TCIC_ICTL_B16|TCIC_ICTL_B8)
+#define TCIC_ICTL_BW_DYN 0
+#define TCIC_ICTL_BW_8 TCIC_ICTL_B8
+#define TCIC_ICTL_BW_16 TCIC_ICTL_B16
+#define TCIC_ICTL_BW_ATA (TCIC_ICTL_B16|TCIC_ICTL_B8)
+#define TCIC_ICTL_SS_SHFT TCIC_SS_SHFT
+#define TCIC_ICTL_SS_MASK TCIC_SS_MASK
+#define TCIC_ICTL_ENA TCIC_MCTL_ENA
+
+#endif /* _LINUX_TCIC_H */
diff --git a/mdk-stage1/pcmcia/version.h b/mdk-stage1/pcmcia/version.h
new file mode 100644
index 000000000..3be8f28bc
--- /dev/null
+++ b/mdk-stage1/pcmcia/version.h
@@ -0,0 +1,4 @@
+/* version.h 1.101 2001/08/09 12:29:14 (David Hinds) */
+
+#define CS_RELEASE "3.1.29"
+#define CS_RELEASE_CODE 0x311d
diff --git a/mdk-stage1/pcmcia/vg468.h b/mdk-stage1/pcmcia/vg468.h
new file mode 100644
index 000000000..23890cd07
--- /dev/null
+++ b/mdk-stage1/pcmcia/vg468.h
@@ -0,0 +1,106 @@
+/*
+ * vg468.h 1.14 2001/08/24 12:15:34
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License version 2 (the "GPL"), in
+ * which case the provisions of the GPL are applicable instead of the
+ * above. If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL. If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ */
+
+#ifndef _LINUX_VG468_H
+#define _LINUX_VG468_H
+
+/* Special bit in I365_IDENT used for Vadem chip detection */
+#define I365_IDENT_VADEM 0x08
+
+/* Special definitions in I365_POWER */
+#define VG468_VPP2_MASK 0x0c
+#define VG468_VPP2_5V 0x04
+#define VG468_VPP2_12V 0x08
+
+/* Unique Vadem registers */
+#define VG469_VSENSE 0x1f /* Card voltage sense */
+#define VG469_VSELECT 0x2f /* Card voltage select */
+#define VG468_CTL 0x38 /* Control register */
+#define VG468_TIMER 0x39 /* Timer control */
+#define VG468_MISC 0x3a /* Miscellaneous */
+#define VG468_GPIO_CFG 0x3b /* GPIO configuration */
+#define VG469_EXT_MODE 0x3c /* Extended mode register */
+#define VG468_SELECT 0x3d /* Programmable chip select */
+#define VG468_SELECT_CFG 0x3e /* Chip select configuration */
+#define VG468_ATA 0x3f /* ATA control */
+
+/* Flags for VG469_VSENSE */
+#define VG469_VSENSE_A_VS1 0x01
+#define VG469_VSENSE_A_VS2 0x02
+#define VG469_VSENSE_B_VS1 0x04
+#define VG469_VSENSE_B_VS2 0x08
+
+/* Flags for VG469_VSELECT */
+#define VG469_VSEL_VCC 0x03
+#define VG469_VSEL_5V 0x00
+#define VG469_VSEL_3V 0x03
+#define VG469_VSEL_MAX 0x0c
+#define VG469_VSEL_EXT_STAT 0x10
+#define VG469_VSEL_EXT_BUS 0x20
+#define VG469_VSEL_MIXED 0x40
+#define VG469_VSEL_ISA 0x80
+
+/* Flags for VG468_CTL */
+#define VG468_CTL_SLOW 0x01 /* 600ns memory timing */
+#define VG468_CTL_ASYNC 0x02 /* Asynchronous bus clocking */
+#define VG468_CTL_TSSI 0x08 /* Tri-state some outputs */
+#define VG468_CTL_DELAY 0x10 /* Card detect debounce */
+#define VG468_CTL_INPACK 0x20 /* Obey INPACK signal? */
+#define VG468_CTL_POLARITY 0x40 /* VCCEN polarity */
+#define VG468_CTL_COMPAT 0x80 /* Compatibility stuff */
+
+#define VG469_CTL_WS_COMPAT 0x04 /* Wait state compatibility */
+#define VG469_CTL_STRETCH 0x10 /* LED stretch */
+
+/* Flags for VG468_TIMER */
+#define VG468_TIMER_ZEROPWR 0x10 /* Zero power control */
+#define VG468_TIMER_SIGEN 0x20 /* Power up */
+#define VG468_TIMER_STATUS 0x40 /* Activity timer status */
+#define VG468_TIMER_RES 0x80 /* Timer resolution */
+#define VG468_TIMER_MASK 0x0f /* Activity timer timeout */
+
+/* Flags for VG468_MISC */
+#define VG468_MISC_GPIO 0x04 /* General-purpose IO */
+#define VG468_MISC_DMAWSB 0x08 /* DMA wait state control */
+#define VG469_MISC_LEDENA 0x10 /* LED enable */
+#define VG468_MISC_VADEMREV 0x40 /* Vadem revision control */
+#define VG468_MISC_UNLOCK 0x80 /* Unique register lock */
+
+/* Flags for VG469_EXT_MODE_A */
+#define VG469_MODE_VPPST 0x03 /* Vpp steering control */
+#define VG469_MODE_INT_SENSE 0x04 /* Internal voltage sense */
+#define VG469_MODE_CABLE 0x08
+#define VG469_MODE_COMPAT 0x10 /* i82365sl B or DF step */
+#define VG469_MODE_TEST 0x20
+#define VG469_MODE_RIO 0x40 /* Steer RIO to INTR? */
+
+/* Flags for VG469_EXT_MODE_B */
+#define VG469_MODE_B_3V 0x01 /* 3.3v for socket B */
+
+#endif /* _LINUX_VG468_H */
diff --git a/mdk-stage1/pcmcia/yacc_config.y b/mdk-stage1/pcmcia/yacc_config.y
new file mode 100644
index 000000000..be5ef98fe
--- /dev/null
+++ b/mdk-stage1/pcmcia/yacc_config.y
@@ -0,0 +1,133 @@
+%{
+/*
+ * Startup tool for non statically mapped PCMCIA sockets - config file parsing
+ *
+ * (C) 2005 Dominik Brodowski <linux@brodo.de>
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
+ *
+ * License: GPL v2
+ */
+
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <syslog.h>
+#include <sys/types.h>
+
+#include "startup.h"
+
+/* If bison: generate nicer error messages */
+#define YYERROR_VERBOSE 1
+
+/* from lex_config, for nice error messages */
+extern char *current_file;
+extern int current_lineno;
+
+extern int yylex(void); /* mdk-stage1 */
+
+void yyerror(char *msg, ...);
+
+%}
+
+%token DEVICE CARD ANONYMOUS TUPLE MANFID VERSION FUNCTION PCI
+%token BIND CIS TO NEEDS_MTD MODULE OPTS CLASS
+%token REGION JEDEC DTYPE DEFAULT MTD
+%token INCLUDE EXCLUDE RESERVE IRQ_NO PORT MEMORY
+%token STRING NUMBER SOURCE
+
+%union {
+ char *str;
+ u_long num;
+ struct adjust_list_t *adjust;
+}
+
+%type <str> STRING
+%type <num> NUMBER
+%type <adjust> adjust resource
+%%
+list: /* nothing */
+ | list adjust
+ {
+ adjust_list_t **tail = &root_adjust;
+ while (*tail != NULL) tail = &(*tail)->next;
+ *tail = $2;
+ }
+ ;
+
+adjust: INCLUDE resource
+ {
+ $2->adj.Action = ADD_MANAGED_RESOURCE;
+ $$ = $2;
+ }
+ | EXCLUDE resource
+ {
+ $2->adj.Action = REMOVE_MANAGED_RESOURCE;
+ $$ = $2;
+ }
+ | RESERVE resource
+ {
+ $2->adj.Action = ADD_MANAGED_RESOURCE;
+ $2->adj.Attributes |= RES_RESERVED;
+ $$ = $2;
+ }
+ | adjust ',' resource
+ {
+ $3->adj.Action = $1->adj.Action;
+ $3->adj.Attributes = $1->adj.Attributes;
+ $3->next = $1;
+ $$ = $3;
+ }
+ ;
+
+resource: IRQ_NO NUMBER
+ {
+ $$ = calloc(sizeof(adjust_list_t), 1);
+ $$->adj.Resource = RES_IRQ;
+ $$->adj.resource.irq.IRQ = $2;
+ }
+ | PORT NUMBER '-' NUMBER
+ {
+ if (($4 < $2) || ($4 > 0xffff)) {
+ yyerror("invalid port range 0x%x-0x%x", $2, $4);
+ YYERROR;
+ }
+ $$ = calloc(sizeof(adjust_list_t), 1);
+ $$->adj.Resource = RES_IO_RANGE;
+ $$->adj.resource.io.BasePort = $2;
+ $$->adj.resource.io.NumPorts = $4 - $2 + 1;
+ }
+ | MEMORY NUMBER '-' NUMBER
+ {
+ if ($4 < $2) {
+ yyerror("invalid address range 0x%x-0x%x", $2, $4);
+ YYERROR;
+ }
+ $$ = calloc(sizeof(adjust_list_t), 1);
+ $$->adj.Resource = RES_MEMORY_RANGE;
+ $$->adj.resource.memory.Base = $2;
+ $$->adj.resource.memory.Size = $4 - $2 + 1;
+ }
+ ;
+
+%%
+void yyerror(char *msg, ...)
+{
+ va_list ap;
+ char str[256];
+
+ va_start(ap, msg);
+ sprintf(str, "error in file '%s' line %d: ",
+ current_file, current_lineno);
+ vsprintf(str+strlen(str), msg, ap);
+#if YYDEBUG
+ fprintf(stderr, "%s\n", str);
+#else
+ syslog(LOG_ERR, "%s", str);
+#endif
+ va_end(ap);
+}
+
diff --git a/mdk-stage1/ppp/Changes-2.3 b/mdk-stage1/ppp/Changes-2.3
new file mode 100644
index 000000000..f5c954b4b
--- /dev/null
+++ b/mdk-stage1/ppp/Changes-2.3
@@ -0,0 +1,441 @@
+What was new in ppp-2.3.11.
+***************************
+
+* Support for Solaris 8 has been added, including support for
+ replumbing and IPV6.
+
+* The Solaris `snoop' utility should now work on ppp interfaces.
+
+* New hooks have been added - pap_logout_hook, ip_up_hook, and
+ ip_down_hook.
+
+* A new `passprompt' plugin is included, thanks to Alan Curry, which
+ makes it possible for pppd to call an external program to get the
+ PAP password to send to the peer.
+
+* The error messages for the situation where authentication is
+ required because the system has a default route have been improved.
+
+* There is a new connect_delay option which specifies how long pppd
+ should pause after the connect script finishes. Previously this
+ delay was fixed at 1 second. (This delay terminates as soon as pppd
+ sees a valid PPP frame from the peer.)
+
+* The `hide-password' option is now the default, and there is a new
+ `show-password' option to enable the printing of password strings in
+ the debug output.
+
+* A fairly complete list of the names of PPP protocols has been added
+ so that when pppd rejects a frame because its protocol is not
+ supported, it can print the name of the unsupported protocol.
+
+* Synchronous serial lines are supported under Linux 2.3.x.
+
+* The bug where pppd would not recognize a modem hangup under Linux
+ 2.3.x kernels has been fixed.
+
+
+What was new in ppp-2.3.10.
+***************************
+
+* Pppd now supports `plugins', which are pieces of code (packaged as
+ shared libraries) which can be loaded into pppd at runtime and which
+ can affect its behaviour. The intention is that plugins provide a
+ way for people to customize the behaviour of pppd for their own
+ needs without needing to change the base pppd source. I have added
+ some hooks into pppd (places where pppd will call a function
+ pointer, if non-zero, to replace some of pppd's code) and I will be
+ receptive to suggestions about places to add more hooks. Plugins
+ are supported under Linux and Solaris at present.
+
+* We have a new maintainer for the Solaris port, Adi Masputra of Sun
+ Microsystems, and he has updated the Solaris port so that it should
+ work on 64-bit machines under Solaris 7 and later.
+
+* Pppd now has an `allow-ip' option, which takes an argument which is
+ an IP address (or subnet) which peers are permitted to use without
+ authenticating themselves. The argument takes the same form as each
+ element of the allowed IP address list in the secrets files. The
+ allow-ip option is privileged and may be specified multiple times.
+ Using the allow-ip option should be cleaner than putting a line like
+ `"" * "" address' in /etc/ppp/pap-secrets.
+
+* Chat can now substitute environment variables into the script. This
+ is enabled by the -E flag. (Thanks to Andreas Arens for the patch.)
+
+* If the PAP username and password from the peer contains unprintable
+ characters, they will be translated to a printable form before
+ looking in the pap-secrets file. Characters >= 0x80 are translated
+ to a M- form, and characters from 0 to 0x1f (and 0x7f as well) are
+ translated to a ^X form. If this change causes you grief, let me
+ know what would be a better translation. It appears that some peers
+ send nulls or other control characters in their usernames and
+ passwords.
+
+* Pppd has new `ktune' and `noktune' options, which enable/disable
+ it to change kernel settings as appropriate. This is only
+ implemented under Linux, and requires the /proc filesystem to be
+ mounted. Under Linux, with the ktune option, pppd will enable IP
+ forwarding in the kernel if the proxyarp option is used, and will
+ enable the dynamic IP address kernel option in demand mode if the
+ local IP address changes.
+
+* Pppd no longer requires a remote address to be specified for demand
+ dialling. If none is specified, it will use a default value of
+ 10.112.112.112+unit_number. (It will not propose this default to
+ the peer.)
+
+* The default holdoff is now 0 if no connect script is given.
+
+* The IPV6 code from Tommi Komulainen, which I unfortunately only
+ partially merged in to ppp-2.3.9, has been fixed and updated.
+
+* The linux compilation glitches should be fixed now.
+
+
+What was new in ppp-2.3.9.
+**************************
+
+* Support for the new generic PPP layer under development for the
+ Linux kernel.
+
+* You can now place extra options to apply to specific users at the
+ end of the line with their password in the pap-secrets or
+ chap-secrets file, separated from the IP address(es) with a "--"
+ separator. These options are parsed after the peer is authenticated
+ but before network protocol (IPCP, IPXCP) or CCP negotiation
+ commences.
+
+* Pppd will apply the holdoff period if the link was terminated by the
+ peer. It doesn't apply it if the link was terminated because the
+ local pppd thought it was idle.
+
+* Synchronous support for Solaris has been added, thanks to John
+ Morrison, and for FreeBSD, thanks to Paul Fulghum.
+
+* IPV6 support has been merged in, from Tommi Komulainen. At the
+ moment it only supports Linux and it is not tested by me.
+
+* The `nodefaultip' option can be used in demand mode to say that pppd
+ should not suggest its local IP address to the peer.
+
+* The `init' option has been added; this causes pppd to run a script
+ to initialize the serial device (e.g. by sending an init string to
+ the modem). Unlike the connect option, this can be used in a
+ dial-in situation. (Thanks to Tobias Ringstrom.)
+
+* There is a new `logfile' option to send log messages to a file as
+ well as syslog.
+
+* There is a new, privileged `linkname' option which sets a logical
+ name for the link. Pppd will create a /var/run/ppp-<linkname>.pid
+ file containing its process ID.
+
+* There is a new `maxfail' option which specifies how many consecutive
+ failed connection attempts are permitted before pppd will exit. The
+ default value is 10, and 0 means infinity. :-)
+
+* Sundry bugs fixed.
+
+
+What was new in ppp-2.3.8.
+**************************
+
+* The exit status of pppd will now indicate whether the link was
+ successfully established, or if not, what error was encountered.
+
+* Pppd has two new options: fdlog <n> will send log messages to file
+ descriptor <n> instead of standard output, and nofdlog will stop log
+ messages from being sent to any file descriptor (they will still be
+ sent to syslog). Pppd now will not send log messages to a file
+ descriptor if the serial port is open on that file descriptor.
+
+* Pppd sets an environment variable called PPPLOGNAME for scripts that
+ it runs, indicating the login name of the user who invoked pppd.
+
+* Pppd sets environment variables CONNECT_TIME, BYTES_SENT and
+ BYTES_RCVD for the ip-down and auth-down scripts indicating the
+ statistics for the connection just terminated. (CONNECT_TIME is in
+ seconds.)
+
+* If the user has the serial device open on standard input and
+ specifies a symbolic link to the serial device on the command line,
+ pppd will detect this and behave correctly (i.e. not detach from its
+ controlling terminal). Furthermore, if the serial port is open for
+ reading and writing on standard input, pppd will assume that it is
+ locked by its invoker and not lock it itself.
+
+* Chat now has a feature where if a string to be sent begins with an
+ at sign (@), the rest of the string is taken as the name of a file
+ (regular file or named pipe), and the actual string to send is taken
+ from that file.
+
+* Support for FreeBSD-2.2.8 and 3.0 has been added, thanks to Paul
+ Fulghum.
+
+* The Tru64 (aka Digital Unix aka OSF/1) port has been updated.
+
+* The system panics on Solaris SMP systems related to PPP connections
+ being established and terminated should no longer occur.
+
+* Fixed quite a few bugs.
+
+
+What was new in ppp-2.3.7.
+**************************
+
+* Pppd can now automatically allocate itself a pseudo-tty to use as
+ the serial device. This has made three new options possible:
+
+ - `pty script' will run `script' with its standard input and output
+ connected to the master side of the pty. For example:
+ pppd pty 'ssh -t server.my.net pppd'
+ is a basic command for setting up a PPP link (tunnel) over ssh.
+ (In practice you may need to specify other options such as IP
+ addresses, etc.)
+
+ - `notty' tells pppd to communicate over its standard input and
+ output, which do not have to be a terminal device.
+
+ - `record filename' tells pppd to record all of the characters sent
+ and received over the serial device to a file called `filename'.
+ The data is recorded in a tagged format with timestamps, which can
+ be printed in a readable form with the pppdump program, which is
+ included in this distribution.
+
+* Pppd now logs the connect time and number of bytes sent and received
+ (at the level of the serial device) when the connection is
+ terminated.
+
+* If you use the updetach or nodetach option, pppd will print its
+ messages to standard output as well as logging them with syslog
+ (provided of course pppd isn't using its standard input or output as
+ its serial device).
+
+* There is a new `privgroup groupname' option (a privileged option).
+ If the user running pppd is in group `groupname', s/he can use
+ privileged options without restriction.
+
+* There is a new `receive-all' option, which causes pppd to accept all
+ control characters, even the ones that the peer should be escaping
+ (i.e. the receive asyncmap is 0). This is useful with some buggy
+ peers.
+
+* The default asyncmap is now 0.
+
+* There is a new `sync' option, currently only implemented under
+ Linux, which allows pppd to run on synchronous HDLC devices.
+
+* If a value for the device name or for the connect, disconnect,
+ welcome or pty option is given in a privileged option file
+ (i.e. /etc/ppp/options or a file loaded with the `call' option), it
+ cannot be overridden by a non-privileged user.
+
+* Many bugs have been fixed, notably:
+ - signals are not blocked unnecessarily, as they were in 2.3.6.
+ - the usepeerdns option should work now.
+ - the SPEED environment variable for scripts is set correctly.
+ - the /etc/ppp/auth-down script is not run until auth-up completes.
+ - the device is opened as root if it is the device on standard
+ input.
+ - pppd doesn't die with the ioctl(PPPIOCSASYNCMAP) error under linux
+ if a hangup occurs at the wrong time.
+
+* Some error messages have been changed to be clearer (I hope :-)
+
+
+What was new in ppp-2.3.6.
+**************************
+
+* Pppd now opens the tty device as the user (rather than as root) if
+ the device name was given by the user, i.e. on the command line or
+ in the ~/.ppprc file. If the device name was given in
+ /etc/ppp/options or in a file loaded with the `call' option, the
+ device is opened as root.
+
+* The default behaviour of pppd is now to let a peer which has not
+ authenticated itself (e.g. your ISP) use any IP address to which the
+ system does not already have a route. (This is currently only
+ supported under Linux, Solaris and Digital Unix; on the other
+ systems, the peer must now authenticate itself unless the noauth
+ option is used.)
+
+* Added new option `usepeerdns', thanks to Nick Walker
+ <nickwalker@email.com>. If the peer supplies DNS addresses, these
+ will be written to /etc/ppp/resolv.conf. The ip-up script can then
+ be used to add these addresses to /etc/resolv.conf if desired (see
+ the ip-up.local.add and ip-down.local.add files in the scripts
+ directory).
+
+* The Solaris ppp driver should now work correctly on SMP systems.
+
+* Minor corrections so that the code can compile under Solaris 7,
+ and under Linux with glibc-2.1.
+
+* The Linux kernel driver has been restructured for improved
+ performance.
+
+* Pppd now won't start the ip-down script until the ip-up script has
+ finished.
+
+
+What was new in ppp-2.3.5.
+**************************
+
+* Minor corrections to the Digital UNIX and NetBSD ports.
+
+* A workaround to avoid tickling a bug in the `se' serial port driver
+on Sun PCI Ultra machines running Solaris.
+
+* Fixed a bug in the negotiation of the Microsoft WINS server address
+option.
+
+* Fixed a bug in the Linux port where it would fail for kernel
+versions above 2.1.99.
+
+
+What was new in ppp-2.3.4.
+**************************
+
+* The NeXT port has been updated, thanks to Steve Perkins.
+
+* ppp-2.3.4 compiles and works under Solaris 2.6, using either gcc or
+cc.
+
+* With the Solaris, SVR4 and SunOS ports, you can control the choice
+of C compiler, C compiler options, and installation directories by
+editing the svr4/Makedefs or sunos4/Makedefs file.
+
+* Until now, we have been using the number 24 to identify Deflate
+compression in the CCP negotiations, which was the number in the draft
+RFC describing Deflate. The number actually assigned to Deflate is
+26. The code has been changed to use 26, but to allow the use of 24
+for now for backwards compatibility. (This can be disabled with the
+`nodeflatedraft' option to pppd.)
+
+* Fixed some bugs in the linux driver and deflate compressor which
+were causing compression problems, including corrupting long
+incompressible packets sometimes.
+
+* Fixes to the PAM and shadow password support in pppd, from Al
+Longyear and others.
+
+* Pppd now sets some environment variables for scripts it invokes
+(ip-up/down, auth-ip/down), giving information about the connection.
+The variables it sets are PEERNAME, IPLOCAL, IPREMOTE, UID, DEVICE,
+SPEED, and IFNAME.
+
+* Pppd now has an `updetach' option, which will cause it to detach
+from its controlling terminal once the link has come up (i.e. once it
+is available for IP traffic).
+
+
+What was new in ppp-2.3.3.
+**************************
+
+* Fixed compilation problems under SunOS.
+
+* Fixed a bug introduced into chat in 2.3.2, and compilation problems
+introduced into the MS-CHAP implementation in 2.3.2.
+
+* The linux kernel driver has been updated for recent 2.1-series
+kernel changes, and it now will ask kerneld to load compression
+modules when required, if the kernel is configured to support kerneld.
+
+* Pppd should now compile correctly under linux on systems with glibc.
+
+
+What was new in ppp-2.3.2.
+**************************
+
+* In 2.3.1, I made a change which was intended to make pppd able to
+detect loss of CD during or immediately after the connection script
+runs. Unfortunately, this had the side-effect that the connection
+script wouldn't work at all on some systems. This change has been
+reversed.
+
+* Fix compilation problems in the Linux kernel driver.
+
+
+What was new in ppp-2.3.1.
+**************************
+
+* Enhancements to chat, thanks to Francis Demierre. Chat can now
+accept comments in the chat script file, and has new SAY, HANGUP,
+CLR_ABORT and CLR_REPORT keywords.
+
+* Fixed a bug which causes 2.3.0 to crash Solaris systems.
+
+* Bug-fixes and restructuring of the Linux kernel driver.
+
+* The holdoff behaviour of pppd has been changed slightly: now, if
+the link comes up for IP (or other network protocol) traffic, we
+consider that the link has been successfully established, and don't
+enforce the holdoff period after the link goes down.
+
+* Pppd should now correctly wait for CD (carrier detect) from the
+modem, even when the serial port initially had CLOCAL set, and it
+should also detect loss of CD during or immediately after the
+connection script runs.
+
+* Under linux, pppd will work with older 2.2.0* version kernel
+drivers, although demand-dialling is not supported with them.
+
+* Minor bugfixes for pppd.
+
+
+What was new in ppp-2.3.
+************************
+
+* Demand-dialling. Pppd now has a mode where it will establish the
+network interface immediately when it starts, but not actually bring
+the link up until it sees some data to be sent. Look for the demand
+option description in the pppd man page. Demand-dialling is not
+supported under Ultrix or NeXTStep.
+
+* Idle timeout. Pppd will optionally terminate the link if no data
+packets are sent or received within a certain time interval.
+
+* Pppd now runs the /etc/ppp/auth-up script, if it exists, when the
+peer successfully authenticates itself, and /etc/ppp/auth-down when
+the connection is subsequently terminated. This can be useful for
+accounting purposes.
+
+* A new packet compression scheme, Deflate, has been implemented.
+This uses the same compression method as `gzip'. This method is free
+of patent or copyright restrictions, and it achieves better
+compression than BSD-Compress. It does consume more CPU cycles for
+compression than BSD-Compress, but this shouldn't be a problem for
+links running at 100kbit/s or less.
+
+* There is no code in this distribution which is covered by Brad
+Clements' restrictive copyright notice. The STREAMS modules for SunOS
+and OSF/1 have been rewritten, based on the Solaris 2 modules, which
+were written from scratch without any Clements code.
+
+* Pppstats has been reworked to clean up the output format somewhat.
+It also has a new -d option which displays data rate in kbyte/s for
+those columns which would normally display bytes.
+
+* Pppd options beginning with - or + have been renamed, e.g. -ip
+became noip, +chap became require-chap, etc. The old options are
+still accepted for compatibility but may be removed in future.
+
+* Pppd now has some options (such as the new `noauth' option) which
+can only be specified if it is being run by root, or in an
+"privileged" options file: /etc/ppp/options or an options file in the
+/etc/ppp/peers directory. There is a new "call" option to read
+options from a file in /etc/ppp/peers, making it possible for non-root
+users to make unauthenticated connections, but only to certain trusted
+peers. My intention is to make the `auth' option the default in a
+future release.
+
+* Several minor new features have been added to pppd, including the
+maxconnect and welcome options. Pppd will now terminate the
+connection when there are no network control protocols running. The
+allowed IP address(es) field in the secrets files can now specify
+subnets (with a notation like 123.45.67.89/24) and addresses which are
+not acceptable (put a ! on the front).
+
+* Numerous bugs have been fixed (no doubt some have been introduced :-)
+Thanks to those who reported bugs in ppp-2.2.
diff --git a/mdk-stage1/ppp/FAQ b/mdk-stage1/ppp/FAQ
new file mode 100644
index 000000000..96bc5c708
--- /dev/null
+++ b/mdk-stage1/ppp/FAQ
@@ -0,0 +1,634 @@
+This is a list of Frequently Asked Questions about using ppp-2.x and
+their answers.
+
+
+------------------------------------------------------------------------
+
+Q: Can you give me an example of how I might set up my machine to dial
+out to an ISP?
+
+A: Here's an example for dialling out to an ISP via a modem on
+/dev/tty02. The modem uses hardware (CTS/RTS) flow control, and the
+serial port is run at 38400 baud. The ISP assigns our IP address.
+
+To configure pppd for this connection, create a file under
+/etc/ppp/peers called (say) my-isp containing the following:
+
+tty02 crtscts 38400
+connect 'chat -v -f /etc/ppp/chat/my-isp'
+defaultroute
+
+The ppp connection is then initiated using the following command:
+
+pppd call my-isp
+
+Of course, if the directory containing pppd is not in your path, you
+will need to give the full pathname for pppd, for example,
+/usr/sbin/pppd.
+
+When you run this, pppd will use the chat program to dial the ISP and
+invoke its ppp service. Chat will read the file specified with -f,
+namely /etc/ppp/chat/my-isp, to find a list of strings to expect to
+receive, and strings to send. This file would contain something like
+this:
+
+ABORT "NO CARRIER"
+ABORT "NO DIALTONE"
+ABORT "ERROR"
+ABORT "NO ANSWER"
+ABORT "BUSY"
+ABORT "Username/Password Incorrect"
+"" "at"
+OK "at&d2&c1"
+OK "atdt2479381"
+"name:" "^Uusername"
+"word:" "\qpassword"
+"annex" "\q^Uppp"
+"Switching to PPP-ppp-Switching to PPP"
+
+You will need to change the details here. The first string on each
+line is a string to expect to receive; the second is the string to
+send. You can add or delete lines according to the dialog required to
+access your ISP's system. This example is for a modem with a standard
+AT command set, dialling out to an Annex terminal server. The \q
+toggles "quiet" mode; when quiet mode is on, the strings to be sent
+are replaced by ?????? in the log. You may need to go through the
+dialog manually using kermit or tip first to determine what should go
+in the script.
+
+To terminate the link, run the following script, called (say)
+kill-ppp:
+
+#!/bin/sh
+unit=ppp${1-0}
+piddir=/var/run
+if [ -f $piddir/$unit.pid ]; then
+ kill -1 `cat $piddir/$unit.pid`
+fi
+
+On some systems (SunOS, Solaris, Ultrix), you will need to change
+/var/run to /etc/ppp.
+
+
+------------------------------------------------------------------------
+
+Q: Can you give me an example of how I could set up my office machine
+so I can dial in to it from home?
+
+A: Let's assume that the office machine is called "office" and is on a
+local ethernet subnet. Call the home machine "home" and give it an IP
+address on the same subnet as "office". We'll require both machines
+to authenticate themselves to each other.
+
+Set up the files on "office" as follows:
+
+/etc/ppp/options contains:
+
+auth # require the peer to authenticate itself
+lock
+# other options can go here if desired
+
+/etc/ppp/chap-secrets contains:
+
+home office "beware the frub-jub" home
+office home "bird, my son!%&*" -
+
+Set up a modem on a serial port so that users can dial in to the
+modem and get a login prompt.
+
+On "home", set up the files as follows:
+
+/etc/ppp/options contains the same as on "office".
+
+/etc/ppp/chap-secrets contains:
+
+home office "beware the frub-jub" -
+office home "bird, my son!%&*" office
+
+Create a file called /etc/ppp/peers/office containing the following:
+
+tty02 crtscts 38400
+connect 'chat -v -f /etc/ppp/chat/office'
+defaultroute
+
+(You may need to change some of the details here.)
+
+Create the /etc/ppp/chat/office file containing the following:
+
+ABORT "NO CARRIER"
+ABORT "NO DIALTONE"
+ABORT "ERROR"
+ABORT "NO ANSWER"
+ABORT "BUSY"
+ABORT "ogin incorrect"
+"" "at"
+OK "at&d2&c1"
+OK "atdt2479381"
+"name:" "^Uusername"
+"word:" "\qpassword"
+"$" "\q^U/usr/sbin/pppd proxyarp"
+"~"
+
+You will need to change the details. Note that the "$" in the
+second-last line is expecting the shell prompt after a successful
+login - you may need to change it to "%" or something else.
+
+You then initiate the connection (from home) with the command:
+
+pppd call office
+
+------------------------------------------------------------------------
+
+Q: When I try to establish a connection, the modem successfully dials
+the remote system, but then hangs up a few seconds later. How do I
+find out what's going wrong?
+
+A: There are a number of possible problems here. The first thing to
+do is to ensure that pppd's messages are visible. Pppd uses the
+syslog facility to log messages which help to identify specific
+problems. Messages from pppd have facility "daemon" and levels
+ranging from "debug" to "error".
+
+Usually it is useful to see messages of level "notice" or higher on
+the console. To see these, find the line in /etc/syslog.conf which
+has /dev/console on the right-hand side, and add "daemon.notice" in
+the list on the left. The line will end up looking something like
+this:
+
+*.err;kern.debug;auth.notice;mail.crit;daemon.notice /dev/console
+
+Note that the whitespace is tabs, *not* spaces.
+
+If you are having problems, it may be useful to see messages of level
+"info" as well, in which case you would change "daemon.notice" to
+"daemon.info".
+
+In addition, it is useful to collect pppd's debugging output in a
+file - the debug option to pppd causes it to log the contents of all
+control packets sent and received in human-readable form. To do this,
+add a line like this to /etc/syslog.conf:
+
+daemon,local2.debug /etc/ppp/log
+
+and create an empty /etc/ppp/log file.
+
+When you change syslog.conf, you will need to send a HUP signal to
+syslogd to causes it to re-read syslog.conf. You can do this with a
+command like this (as root):
+
+ kill -HUP `cat /etc/syslogd.pid`
+
+(On some systems, you need to use /var/run/syslog.pid instead of
+/etc/syslogd.pid.)
+
+After setting up syslog like this, you can use the -v flag to chat and
+the `debug' option to pppd to get more information. Try initiating
+the connection again; when it fails, inspect /etc/ppp/log to see what
+happened and where the connection failed.
+
+
+------------------------------------------------------------------------
+
+Q: When I try to establish a connection, I get an error message saying
+"Serial link is not 8-bit clean". Why?
+
+A: The most common cause is that your connection script hasn't
+successfully dialled out to the remote system and invoked ppp service
+there. Instead, pppd is talking to something (a shell or login
+process on the remote machine, or maybe just the modem) which is only
+outputting 7-bit characters.
+
+This can also arise with a modem which uses an AT command set if the
+dial command is issued before pppd is invoked, rather than within a
+connect script started by pppd. If the serial port is set to 7
+bits/character plus parity when the last AT command is issued, the
+modem serial port will be set to the same setting.
+
+Note that pppd *always* sets the local serial port to 8 bits per
+character, with no parity and 1 stop bit. So you shouldn't need to
+issue an stty command before invoking pppd.
+
+
+------------------------------------------------------------------------
+
+Q: When I try to establish a connection, I get an error message saying
+"Serial line is looped back". Why?
+
+A: Probably your connection script hasn't successfully dialled out to
+the remote system and invoked ppp service there. Instead, pppd is
+talking to something which is just echoing back the characters it
+receives. The -v option to chat can help you find out what's going
+on. It can be useful to include "~" as the last expect string to
+chat, so chat won't return until it's seen the start of the first PPP
+frame from the remote system.
+
+Another possibility is that your phone connection has dropped for some
+obscure reason and the modem is echoing the characters it receives
+from your system.
+
+
+------------------------------------------------------------------------
+
+Q: I installed pppd successfully, but when I try to run it, I get a
+message saying something like "peer authentication required but no
+authentication files accessible".
+
+A: When pppd is used on a machine which already has a connection to
+the Internet (or to be more precise, one which has a default route in
+its routing table), it will require all peers to authenticate
+themselves. The reason for this is that if you don't require
+authentication, you have a security hole, because the peer can
+basically choose any IP address it wants, even the IP address of some
+trusted host (for example, a host mentioned in some .rhosts file).
+
+On machines which don't have a default route, pppd does not require
+the peer to authenticate itself. The reason is that such machines
+would mostly be using pppd to dial out to an ISP which will refuse to
+authenticate itself. In that case the peer can use any IP address as
+long as the system does not already have a route to that address.
+For example, if you have a local ethernet network, the peer can't use
+an address on that network. (In fact it could if it authenticated
+itself and it was permitted to use that address by the pap-secrets or
+chap-secrets file.)
+
+There are 3 ways around the problem:
+
+1. If possible, arrange for the peer to authenticate itself, and
+create the necessary secrets files (/etc/ppp/pap-secrets and/or
+/etc/ppp/chap-secrets).
+
+2. If the peer refuses to authenticate itself, and will always be
+using the same IP address, or one of a small set of IP addresses, you
+can create an entry in the /etc/ppp/pap-secrets file like this:
+
+ "" * "" his-ip.his-domain his-other-ip.other-domain
+
+(that is, using the empty string for the client name and password
+fields). Of couse, you replace the 4th and following fields in the
+example above with the IP address(es) that the peer may use. You can
+use either hostnames or numeric IP addresses.
+
+3. You can add the `noauth' option to the /etc/ppp/options file.
+Pppd will then not ask the peer to authenticate itself. If you do
+this, I *strongly* recommend that you remove the set-uid bit from the
+permissions on the pppd executable, with a command like this:
+
+ chmod u-s /usr/sbin/pppd
+
+Then, an intruder could only use pppd maliciously if they had already
+become root, in which case they couldn't do any more damage using pppd
+than they could anyway.
+
+
+------------------------------------------------------------------------
+
+Q: What do I need to put in the secrets files?
+
+A: Three things:
+ - secrets (i.e. passwords) to use for authenticating this host to
+ other hosts (i.e., for proving our identity to others);
+ - secrets which other hosts can use for authenticating themselves
+ to us (i.e., so that they can prove their identity to us); and
+ - information about which IP addresses other hosts may use, once
+ they have authenticated themselves.
+
+There are two authentication files: /etc/ppp/pap-secrets, which
+contains secrets for use with PAP (the Password Authentication
+Protocol), and /etc/ppp/chap-secrets, which contains secrets for use
+with CHAP (the Challenge Handshake Authentication Protocol). Both
+files have the same simple format, which is as follows:
+
+- The file contains a series of entries, each of which contains a
+secret for authenticating one machine to another.
+
+- Each entry is contained on a single logical line. A logical line
+may be continued across several lines by placing a backslash (\) at
+the end of each line except the last.
+
+- Each entry has 3 or more fields, separated by whitespace (spaces
+and/or tabs). These fields are, in order:
+ * The name of the machine that is authenticating itself
+ (the "client").
+ * The name of the machine that is authenticating the client
+ (the "server").
+ * The secret to be used for authenticating that client to that
+ server. If this field begins with the at-sign `@', the rest
+ of the field is taken as the name of a file containing the
+ actual secret.
+ * The 4th and any following fields list the IP address(es)
+ that the client may use.
+
+- The file may contain comments, which begin with a `#' and continue
+to the end of the line.
+
+- Double quotes `"' should be used around a field if it contains
+characters with special significance, such as space, tab, `#', etc.
+
+- The backslash `\' may be used before characters with special
+significance (space, tab, `#', `\', etc.) to remove that significance.
+
+Some important points to note:
+
+* A machine can be *both* a "client" and a "server" for the purposes
+of authentication - this happens when both peers require the other to
+authenticate itself. So A would authenticate itself to B, and B would
+also authenticate itself to A (possibly using a different
+authentication protocol).
+
+* If both the "client" and the "server" are running ppp-2.x, they need
+to have a similar entry in the appropriate secrets file; the first two
+fields are *not* swapped on the client, compared to the server. So
+the client might have an entry like this:
+
+ ay bee "our little secret" -
+
+and the corresponding entry on the server could look like this:
+
+ ay bee "our little secret" 123.45.67.89
+
+
+------------------------------------------------------------------------
+
+Q: Explain about PAP and CHAP?
+
+PAP stands for the Password Authentication Protocol. With this
+protocol, the "client" (the machine that needs to authenticate itself)
+sends its name and a password, in clear text, to the "server". The
+server returns a message indicating whether the name and password are
+valid.
+
+CHAP stands for the Challenge Handshake Authentication Protocol. It
+is designed to address some of the deficiencies and vulnerabilities of
+PAP. Like PAP, it is based on the client and server having a shared
+secret, but the secret is never passed in clear text over the link.
+Instead, the server sends a "challenge" - an arbitrary string of
+bytes, and the client must prove it knows the shared secret by
+generating a hash value from the challenge combined with the shared
+secret, and sending the hash value back to the server. The server
+also generates the hash value and compares it with the value received
+from the client.
+
+At a practical level, CHAP can be slightly easier to configure than
+PAP because the server sends its name with the challenge. Thus, when
+finding the appropriate secret in the secrets file, the client knows
+the server's name. In contrast, with PAP, the client has to find its
+password (i.e. the shared secret) before it has received anything from
+the server. Thus, it may be necessary to use the `remotename' option
+to pppd when using PAP authentication so that it can select the
+appropriate secret from /etc/ppp/pap-secrets.
+
+Microsoft also has a variant of CHAP which uses a different hashing
+arrangement from normal CHAP. There is a client-side implementation
+of Microsoft's CHAP in ppp-2.3; see README.MSCHAP80.
+
+
+------------------------------------------------------------------------
+
+Q: When the modem hangs up, without the remote system having
+terminated the connection properly, pppd does not notice the hangup,
+but just keeps running. How do I get pppd to notice the hangup and
+exit?
+
+A: Pppd detects modem hangup by looking for an end-of-file indication
+from the serial driver, which should be generated when the CD (carrier
+detect) signal on the serial port is deasserted. For this to work:
+
+- The modem has to be set to assert CD when the connection is made and
+deassert it when the phone line hangs up. Usually the AT&C1 modem
+command sets this mode.
+
+- The cable from the modem to the serial port must connect the CD
+signal (on pin 8).
+
+- Some serial drivers have a "software carrier detect" mode, which
+must be *disabled*. The method of doing this varies between systems.
+Under SunOS, use the ttysoftcar command. Under NetBSD, edit /etc/ttys
+to remove the "softcar" flag from the line for the serial port, and
+run ttyflags.
+
+
+------------------------------------------------------------------------
+
+Q: Why should I use PPP compression (BSD-Compress or Deflate) when my
+modem already does V.42 compression? Won't it slow the CPU down a
+lot?
+
+A: Using PPP compression is preferable, especially when using modems
+over phone lines, for the following reasons:
+
+- The V.42 compression in the modem isn't very strong - it's an LZW
+technique (same as BSD-Compress) with a 10, 11 or 12 bit code size.
+With BSD-Compress you can use a code size of up to 15 bits and get
+much better compression, or you can use Deflate and get even better
+compression ratios.
+
+- I have found that enabling V.42 compression in my 14.4k modem
+increases the round-trip time for a character to be sent, echoed and
+returned by around 40ms, from 160ms to 200ms (with error correction
+enabled). This is enough to make it feel less responsive on rlogin or
+telnet sessions. Using PPP compression adds less than 5ms (small
+enough that I couldn't measure it reliably). I admit my modem is a
+cheapie and other modems may well perform better.
+
+- While compression and decompression do require some CPU time, they
+reduce the amount of time spent in the serial driver to transmit a
+given amount of data. Many machines require an interrupt for each
+character sent or received, and the interrupt handler can take a
+significant amount of CPU time. So the increase in CPU load isn't as
+great as you might think. My measurements indicate that a system with
+a 33MHz 486 CPU should be able to do Deflate compression for serial
+link speeds of up to 100kb/s or more. It depends somewhat on the type
+of data, of course; for example, when compressing a string of nulls
+with Deflate, it's hard to get a high output data rate from the
+compressor, simply because it compresses strings of nulls so well that
+it has to eat a very large amount of input data to get each byte of
+output.
+
+
+------------------------------------------------------------------------
+
+Q: I get messages saying "Unsupported protocol (...) received". What do
+these mean?
+
+A: If you only get one or two when pppd starts negotiating with the
+peer, they mean that the peer wanted to negotiate some PPP protocol
+that pppd doesn't understand. This doesn't represent a problem, it
+simply means that there is some functionality that the peer supports
+that pppd doesn't, so that functionality can't be used.
+
+If you get them sporadically while the link is operating, or if the
+protocol numbers (in parentheses) don't correspond to any valid PPP
+protocol that the peer might be using, then the problem is probably
+that characters are getting corrupted on the receive side, or that
+extra characters are being inserted into the receive stream somehow.
+If this is happening, most packets that get corrupted should get
+discarded by the FCS (Frame Check Sequence, a 16-bit CRC) check, but a
+small number may get through.
+
+One possibility may be that you are receiving broadcast messages on
+the remote system which are being sent over your serial link. Another
+possibility is that your modem is set for XON/XOFF (software) flow
+control and is inserting ^Q and ^S characters into the receive data
+stream.
+
+
+------------------------------------------------------------------------
+
+Q: I get messages saying "Protocol-Reject for unsupported protocol ...".
+What do these mean?
+
+A: This is the other side of the previous question. If characters are
+getting corrupted on the way to the peer, or if your system is
+inserting extra bogus characters into the transmit data stream, the
+peer may send protocol-reject messages to you, resulting in the above
+message (since your pppd doesn't recognize the protocol number
+either.)
+
+
+------------------------------------------------------------------------
+
+Q: I get a message saying something like "ioctl(TIOCSETD): Operation
+not permitted". How do I fix this?
+
+A: This is because pppd is not running as root. If you have not
+installed pppd setuid-root, you will have to be root to run it. If
+you have installed pppd setuid-root and you still get this message, it
+is probably because your shell is using some other copy of pppd than
+the installed one - for example, if you are in the pppd directory
+where you've just built pppd and your $PATH has . before /usr/sbin (or
+wherever pppd gets installed).
+
+
+------------------------------------------------------------------------
+
+Q: Has your package been ported to HP/UX or IRIX or AIX?
+
+A: No. I don't have access to systems running HP/UX or AIX. No-one
+has volunteered to port it to HP/UX. I had someone who did a port for
+AIX 4.x, but who is no longer able to maintain it. And apparently AIX
+3.x is quite different, so it would need a separate port.
+
+IRIX includes a good PPP implementation in the standard distribution,
+as far as I know.
+
+
+------------------------------------------------------------------------
+
+Q: Under SunOS 4, when I try to modload the ppp modules, I get the
+message "can't open /dev/vd: No such device".
+
+A: First check in /dev that there is an entry like this:
+
+crw-r--r-- 1 root 57, 0 Oct 2 1991 vd
+
+If not, make one (mknod /dev/vd c 57 0). If the problem still exists,
+probably your kernel has been configured without the vd driver
+included. The vd driver is needed for loadable module support.
+
+First, identify the config file that was used. When you boot your
+machine, or if you run /etc/dmesg, you'll see a line that looks
+something like this:
+
+SunOS Release 4.1.3_U1 (CAP_XBOX) #7: Thu Mar 21 15:31:56 EST 1996
+ ^^^^^^^^
+ this is the config file name
+
+The config file will be in the /sys/`arch -k`/conf directory (arch -k
+should return sun4m for a SparcStation 10, sun3x for a Sun 3/80,
+etc.). Look in there for a line saying "options VDDRV". If that line
+isn't present (or is commented out), add it (or uncomment it).
+
+You then need to rebuild the kernel as described in the SunOS
+manuals. Basically you need to run config and make like this:
+
+ /usr/etc/config CAP_XBOX
+ cd ../CAP_XBOX
+ make
+
+(replacing the string CAP_XBOX by the name of the config file for your
+kernel, of course).
+
+Then copy the new kernel to /:
+
+ mv /vmunix /vmunix.working
+ cp vmunix /
+
+and reboot. Modload should then work.
+
+
+------------------------------------------------------------------------
+
+Q: I'm running Linux (or NetBSD or FreeBSD), and my system comes with
+PPP already. Should I consider installing this package? Why?
+
+A: The PPP that is already installed in your system is (or is derived
+from) some version of this PPP package. You can find out what version
+of this package is already installed with the command "pppd --help".
+If this is older than the latest version, you may wish to install the
+latest version so that you can take advantage of the new features or
+bug fixes.
+
+
+------------------------------------------------------------------------
+
+Q: I'm running pppd in demand mode, and I find that pppd often dials
+out unnecessarily when I try to make a connection within my local
+machine or with a machine on my local LAN. What can I do about this?
+
+A: Very often the cause of this is that a program is trying to contact
+a nameserver to resolve a hostname, and the nameserver (specified in
+/etc/resolv.conf, usually) is on the far side of the ppp link. You
+can try executing a command such as `ping myhost' (where myhost is the
+name of the local machine, or some other machine on a local LAN), to
+see whether that starts the ppp link. If it does, check the setup of
+your /etc/hosts file to make sure you have the local machine and any
+hosts on your local LAN listed, and /etc/resolv.conf and/or
+/etc/nsswitch.conf files to make sure you resolve hostnames from
+/etc/hosts if possible before trying to contact a nameserver.
+
+
+------------------------------------------------------------------------
+
+Q: Since I installed ppp-2.3.6, dialin users to my server have been
+getting this message when they run pppd:
+
+peer authentication required but no suitable secret(s) found for
+authenticating any peer to us (ispserver)
+
+A: In 2.3.6, the default is to let an unauthenticated peer only use IP
+addresses to which the machine doesn't already have a route. So on a
+machine with a default route, everyone has to authenticate. If you
+really don't want that, you can put `noauth' in the /etc/ppp/options
+file. Note that there is then no check on who is using which IP
+address. IMHO, this is undesirably insecure, but I guess it may be
+tolerable as long as you don't use any .rhosts files or anything like
+that. I recommend that you require dialin users to authenticate, even
+if just with PAP using their login password (using the `login' option
+to pppd). If you do use `noauth', you should at least have a pppusers
+group and set the permissions on pppd to allow only user and group to
+execute it.
+
+------------------------------------------------------------------------
+
+Q: When running pppd as a dial-in server, I often get the message
+"LCP: timeout sending Config-Requests" from pppd. It seems to be
+random, but dial-out always works fine. What is wrong?
+
+A: Most modern modems auto-detects the speed of the serial line
+between the modem and the computer. This auto-detection occurs when
+the computer sends characters to the modem, when the modem is in
+command mode. It does not occur when the modem is in data mode.
+Thus, if you send commands to the modem at 2400 bps, and then change
+the serial port speed to 115200 bps, the modem will not detect this
+change until something is transmitted from the computer to the modem.
+When running pppd in dial-in mode (i.e. without a connect script),
+pppd sets the speed of the serial port, but does not transmit
+anything. If the modem was already running at the specified speed,
+everything is fine, but if not, you will just receive garbage from the
+modem. To cure this, use an init script such as the following:
+
+ pppd ttyS0 115200 modem crtscts init "chat '' AT OK"
+
+To reset the modem and enable auto-answer, use:
+
+ pppd ttyS0 115200 modem crtscts init "chat '' ATZ OK ATS0=1 OK"
diff --git a/mdk-stage1/ppp/PLUGINS b/mdk-stage1/ppp/PLUGINS
new file mode 100644
index 000000000..5f17e1d0a
--- /dev/null
+++ b/mdk-stage1/ppp/PLUGINS
@@ -0,0 +1,131 @@
+Starting with version 2.3.10, pppd includes support for `plugins' -
+pieces of code which can be loaded into pppd at runtime and which can
+affect its behaviour in various ways. The idea of plugins is to
+provide a way for people to customize the behaviour of pppd without
+having to either apply local patches to each version or get their
+patches accepted into the standard distribution. My aim is that
+plugins will be able to be used with successive versions of pppd
+without needing to recompile the plugins.
+
+A plugin is a standard shared library object, typically with a name
+ending in .so. They are loaded using the standard dlopen() library
+call, so plugins are only supported on systems which support shared
+libraries and the dlopen call. At present pppd is compiled with
+plugin support only under Linux and Solaris.
+
+Plugins are loaded into pppd using the `plugin' option, which takes
+one argument, the name of a shared object file. The plugin option is
+a privileged option. I suggest that you give the full path name of
+the shared object file; if you don't, it may be possible for
+unscrupulous users to substitute another shared object file for the
+one you mean to load, e.g. by setting the LD_LIBRARY_PATH variable.
+
+Plugins are usually written in C and compiled and linked to a shared
+object file in the appropriate manner for your platform. Using gcc
+under Linux, a plugin called `xyz' could be compiled and linked with
+the following commands:
+
+ gcc -c -O xyz.c
+ gcc -shared -o xyz.so xyz.o
+
+There are some example plugins in the pppd/plugins directory in the
+ppp distribution. Currently there is one example, minconn.c, which
+implements a `minconnect' option, which specifies a minimum connect
+time before the idle timeout applies.
+
+Plugins can access global variables within pppd, so it is useful for
+them to #include "pppd.h" from the pppd source directory.
+
+Every plugin must contain a global procedure called `plugin_init'.
+This procedure will get called (with no arguments) immediately after
+the plugin is loaded.
+
+Plugins can affect the behaviour of pppd in at least three ways:
+
+1. They can add extra options which pppd will then recognize. This is
+ done by calling the add_options() procedure with a pointer to an
+ array of option_t structures. The last entry in the array must
+ have its name field set to NULL.
+
+2. Pppd contains `hook' variables which are procedure pointers. If a
+ given hook is not NULL, pppd will call the procedure it points to
+ at the appropriate point in its processing. The plugin can set any
+ of these hooks to point to its own procedures. See below for a
+ description of the hooks which are currently implemented.
+
+3. Plugin code can call any global procedures and access any global
+ variables in pppd.
+
+Here is a list of the currently implemented hooks in pppd.
+
+
+int (*idle_time_hook)(struct ppp_idle *idlep);
+
+The idle_time_hook is called when the link first comes up (i.e. when
+the first network protocol comes up) and at intervals thereafter. On
+the first call, the idlep parameter is NULL, and the return value is
+the number of seconds before pppd should check the link activity, or 0
+if there is to be no idle timeout.
+
+On subsequent calls, idlep points to a structure giving the number of
+seconds since the last packets were sent and received. If the return
+value is > 0, pppd will wait that many seconds before checking again.
+If it is <= 0, that indicates that the link should be terminated due
+to lack of activity.
+
+
+int (*holdoff_hook)(void);
+
+The holdoff_hook is called when an attempt to bring up the link fails,
+or the link is terminated, and the persist or demand option was used.
+It returns the number of seconds that pppd should wait before trying
+to reestablish the link (0 means immediately).
+
+
+int (*pap_check_hook)(void);
+int (*pap_passwd_hook)(char *user, char *passwd);
+int (*pap_auth_hook)(char *user, int userlen,
+ char *passwd, int passlen,
+ char **msgp, int *msglenp,
+ struct wordlist **paddrs,
+ struct wordlist **popts);
+
+These hooks are designed to allow a plugin to replace the normal PAP
+password processing in pppd with something different (e.g. contacting
+an external server).
+
+The pap_check_hook is called to check whether there is any possibility
+that the peer could authenticate itself to us. If it returns 1, pppd
+will ask the peer to authenticate itself. If it returns 0, pppd will
+not ask the peer to authenticate itself (but if authentication is
+required, pppd may exit, or terminate the link before network protocol
+negotiation). If it returns -1, pppd will look in the pap-secrets
+file as it would normally.
+
+The pap_passwd_hook is called to determine what username and password
+pppd should use in authenticating itself to the peer with PAP. The
+user string will already be initialized, by the `user' option, the
+`name' option, or from the hostname, but can be changed if necessary.
+MAXNAMELEN bytes of space are available at *user, and MAXSECRETLEN
+bytes of space at *passwd. If this hook returns 0, pppd will use the
+values at *user and *passwd; if it returns -1, pppd will look in the
+pap-secrets file, or use the value from the +ua or password option, as
+it would normally.
+
+The pap_auth_hook is called to determine whether the username and
+password supplied by the peer are valid. user and passwd point to
+null-terminated strings containing the username and password supplied
+by the peer, with non-printable characters converted to a printable
+form. The pap_auth_hook function should set msg to a string to be
+returned to the peer and return 1 if the username/password was valid
+and 0 if not. If the hook returns -1, pppd will look in the
+pap-secrets file as usual.
+
+If the username/password was valid, the hook can set *paddrs to point
+to a wordlist containing the IP address(es) which the peer is
+permitted to use, formatted as in the pap-secrets file. It can also
+set *popts to a wordlist containing any extra options for this user
+which pppd should apply at this point.
+
+
+## $Id: PLUGINS 195720 2001-06-11 11:44:34Z gc $ ##
diff --git a/mdk-stage1/ppp/README b/mdk-stage1/ppp/README
new file mode 100644
index 000000000..0967fc92a
--- /dev/null
+++ b/mdk-stage1/ppp/README
@@ -0,0 +1,168 @@
+This is the README file for ppp-2.4, a package which implements the
+Point-to-Point Protocol (PPP) to provide Internet connections over
+serial lines.
+
+
+Introduction.
+*************
+
+The Point-to-Point Protocol (PPP) provides a standard way to establish
+a network connection over a serial link. At present, this package
+supports IP and the protocols layered above IP, such as TCP and UDP.
+The Linux and Solaris ports of this package have optional support for
+IPV6; the Linux port of this package also has support for IPX.
+
+This software consists of two parts:
+
+- Kernel code, which establishes a network interface and passes
+packets between the serial port, the kernel networking code and the
+PPP daemon (pppd). This code is implemented using STREAMS modules on
+SunOS 4.x and Solaris, and as a line discipline under Linux and FreeBSD.
+
+- The PPP daemon (pppd), which negotiates with the peer to establish
+the link and sets up the ppp network interface. Pppd includes support
+for authentication, so you can control which other systems may make a
+PPP connection and what IP addresses they may use.
+
+The primary platforms supported by this package are Linux and Solaris.
+Code for SunOS 4.x is included here but is largely untested. I have
+code for NeXTStep, FreeBSD, SVR4, Tru64 (Digital Unix), AIX and Ultrix
+but no active maintainers for these platforms. Code for all of these
+except AIX is included in the ppp-2.3.11 release.
+
+
+Installation.
+*************
+
+The file SETUP contains general information about setting up your
+system for using PPP. There is also a README file for each supported
+system, which contains more specific details for installing PPP on
+that system. The supported systems, and the corresponding README
+files, are:
+
+ Linux README.linux
+ Solaris 2 README.sol2
+ SunOS 4.x README.sunos4
+
+In each case you start by running the ./configure script. This works
+out which operating system you are using and creates symbolic links to
+the appropriate makefiles. You then run `make' to compile the
+user-level code, and (as root) `make install' to install the
+user-level programs pppd, chat and pppstats.
+
+N.B. Since 2.3.0, leaving the permitted IP addresses column of the
+pap-secrets or chap-secrets file empty means that no addresses are
+permitted. You need to put a "*" in that column to allow the peer to
+use any IP address. (This only applies where the peer is
+authenticating itself to you, of course.)
+
+
+What's new in ppp-2.4.1.
+************************
+
+* Pppd can now print out the set of options that are in effect. The
+ new `dump' option causes pppd to print out the option values after
+ option parsing is complete. The `dryrun' option causes pppd to
+ print the options and then exit.
+
+* The option parsing code has been fixed so that options in the
+ per-tty options file are parsed correctly, and don't override values
+ from the command line in most cases.
+
+* The plugin option now looks in /usr/lib/pppd/<pppd-version> (for
+ example, /usr/lib/pppd/2.4.1b1) for shared objects for plugins if
+ there is no slash in the plugin name.
+
+* When loading a plugin, pppd will now check the version of pppd for
+ which the plugin was compiled, and refuse to load it if it is
+ different to pppd's version string. To enable this, the plugin
+ source needs to #include "pppd.h" and have a line saying:
+ char pppd_version[] = VERSION;
+
+* There is a bug in zlib, discovered by James Carlson, which can cause
+ kernel memory corruption if Deflate is used with the lowest setting,
+ 8. As a workaround pppd will now insist on using at least 9.
+
+* Pppd should compile on Solaris and SunOS again.
+
+* Pppd should now set the MTU correctly on demand-dialled interfaces.
+
+
+What was new in ppp-2.4.0.
+**************************
+
+* Multilink: this package now allows you to combine multiple serial
+ links into one logical link or `bundle', for increased bandwidth and
+ reduced latency. This is currently only supported under the
+ Linux-2.3.99pre5 or later kernels.
+
+* All the pppd processes running on a system now write information
+ into a common database. I used the `tdb' code from samba for this.
+
+* New hooks have been added.
+
+For a list of the changes made during the 2.3 series releases of this
+package, see the Changes-2.3 file.
+
+
+Compression methods.
+********************
+
+This package supports two packet compression methods: Deflate and
+BSD-Compress. Other compression methods which are in common use
+include Predictor, LZS, and MPPC. These methods are not supported for
+two reasons - they are patent-encumbered, and they cause some packets
+to expand slightly, which pppd doesn't currently allow for.
+BSD-Compress is also patent-encumbered (its inclusion in this package
+can be considered a historical anomaly :-) but it doesn't ever expand
+packets. Neither does Deflate, which uses the same algorithm as gzip.
+
+
+Patents.
+********
+
+The BSD-Compress algorithm used for packet compression is the same as
+that used in the Unix "compress" command. It is apparently covered by
+U.S. patents 4,814,746 (owned by IBM) and 4,558,302 (owned by Unisys),
+and corresponding patents in various other countries (but not
+Australia). If this is of concern, you can build the package without
+including BSD-Compress. To do this, edit net/ppp-comp.h to change the
+definition of DO_BSD_COMPRESS to 0. The bsd-comp.c files are then no
+longer needed, so the references to bsd-comp.o may optionally be
+removed from the Makefiles.
+
+
+Contacts.
+*********
+
+The comp.protocols.ppp newsgroup is a useful place to get help if you
+have trouble getting your ppp connections to work. Please do not send
+me questions of the form "please help me get connected to my ISP" -
+I'm sorry, but I simply do not have the time to answer all the
+questions like this that I get.
+
+If you find bugs in this package, please report them to the maintainer
+for the port for the operating system you are using:
+
+Linux Paul Mackerras <paulus@linuxcare.com>
+Solaris 2 James Carlson <james.d.carlson@east.sun.com>
+SunOS 4.x Adi Masputra <adi.masputra@sun.com>
+
+
+Copyrights:
+***********
+
+All of the code can be freely used and redistributed. The individual
+source files each have their own copyright and permission notice; some
+have a BSD-style notice and some are under the GPL.
+
+
+Distribution:
+*************
+
+The primary site for releases of this software is:
+
+ ftp://linuxcare.com.au/pub/ppp/
+
+
+($Id: README 195720 2001-06-11 11:44:34Z gc $)
diff --git a/mdk-stage1/ppp/README.MSCHAP80 b/mdk-stage1/ppp/README.MSCHAP80
new file mode 100644
index 000000000..d3ed291b7
--- /dev/null
+++ b/mdk-stage1/ppp/README.MSCHAP80
@@ -0,0 +1,284 @@
+PPP Client Support for Microsoft's CHAP-80
+==========================================
+
+Eric Rosenquist rosenqui@strataware.com
+(updated by Paul Mackerras)
+(updated by Al Longyear)
+(updated by Farrell Woods)
+
+INTRODUCTION
+
+Microsoft has introduced an extension to the Challenge/Handshake
+Authentication Protocol (CHAP) which avoids storing cleartext
+passwords on a server. (Unfortunately, this is not as secure as it
+sounds, because the encrypted password stored on a server can be used
+by a bogus client to gain access to the server just as easily as if
+the password were stored in cleartext.) The details of the Microsoft
+extensions can be found in the document:
+
+ <ftp://ftp.microsoft.com/developr/rfc/chapexts.txt>
+
+In short, MS-CHAP is identified as <auth chap 80> since the hex value
+of 80 is used to designate Microsoft's scheme. Standard PPP CHAP uses
+a value of 5. If you enable PPP debugging with the "debug" option and
+see something like the following in your logs, the remote server is
+requesting MS-CHAP:
+
+ rcvd [LCP ConfReq id=0x2 <asyncmap 0x0> <auth chap 80> <magic 0x46a3>]
+ ^^^^^^^^^^^^
+
+The standard pppd implementation will indicate its lack of support for
+MS-CHAP by NAKing it:
+
+ sent [LCP ConfNak id=0x2 <auth chap 05>]
+
+Windows NT Server systems are often configured to "Accept only
+Microsoft Authentication" (this is intended to enhance security). Up
+until now, that meant that you couldn't use this version of PPPD to
+connect to such a system. I've managed to get a client-only
+implementation of MS-CHAP working; it will authenticate itself to
+another system using MS-CHAP, but if you're using PPPD as a dial-in
+server, you won't be able to use MS-CHAP to authenticate the clients.
+This would not be a lot of extra work given that the framework is in
+place, but I didn't need it myself so I didn't implement it.
+
+
+BUILDING THE PPPD
+
+MS-CHAP uses a combination of MD4 hashing and DES encryption for
+authentication. You may need to get Eric Young's libdes library in
+order to use my MS-CHAP extensions. A lot of UNIX systems already
+have DES encryption available via the crypt(3), encrypt(3) and
+setkey(3) interfaces. Some may (such as that on Digital UNIX)
+provide only the encryption mechanism and will not perform
+decryption. This is okay. We only need to encrypt to perform
+MS-CHAP authentication.
+
+If you have encrypt/setkey available, then hopefully you need only
+define these two things in your Makefile: -DUSE_CRYPT and -DCHAPMS.
+Skip the paragraphs below about obtaining and building libdes. Do
+the "make clean" and "make" as described below. Linux users
+should not need to modify their Makefiles. Instead,
+just do "make CHAPMS=1 USE_CRYPT=1".
+
+If you don't have encrypt and setkey, you will need Eric Young's
+libdes library. You can find it in:
+
+ftp://ftp.funet.fi/pub/crypt/mirrors/ftp.psy.uq.oz.au/DES/libdes-3.06.tar.gz
+
+Australian residents can get libdes from Eric Young's site:
+
+ftp://ftp.psy.uq.oz.au/pub/Crypto/DES/libdes-3.06.tar.gz
+
+It is also available on many other sites (ask Archie).
+
+I used libdes-3.06, but hopefully anything newer than that will work
+also. Get the library, build and test it on your system, and install
+it somewhere (typically /usr/local/lib and /usr/local/include).
+
+
+
+You should now be ready to (re)compile the PPPD. Go to the pppd
+subdirectory and make sure the Makefile contains "-DCHAPMS" in the
+CFLAGS or COMPILE_FLAGS macro, and that the LIBS macro (or LDADD for
+BSD systems) contains "-ldes". Depending on your system and where the
+DES library was installed, you may also need to alter the include and
+library paths used by your compiler.
+
+Do a "make clean" and then a "make" to rebuild pppd. Assuming all
+goes well, install the new pppd and move on to the CONFIGURATION
+section.
+
+
+CONFIGURATION
+
+If you've never used PPPD with CHAP before, read the man page (type
+"man pppd") and read the description in there. Basically, you need to
+edit the "chap-secrets" file typically named /etc/ppp/chap-secrets.
+This should contain the following two lines for each system with which
+you use CHAP (with no leading blanks):
+
+ RemoteHost Account Secret
+ Account RemoteHost Secret
+
+Note that you need both lines and that item 1 and 2 are swapped in the
+second line. I'm not sure why you need it twice, but it works and I didn't
+have time to look into it further. The "RemoteHost" is a somewhat
+arbitrary name for the remote Windows NT system you're dialing. It doesn't
+have to match the NT system's name, but it *does* have to match what you
+use with the "remotename" parameter. The "Account" is the Windows NT
+account name you have been told to use when dialing, and the "Secret" is
+the password for that account. For example, if your service provider calls
+their machine "DialupNT" and tells you your account and password are
+"customer47" and "foobar", add the following to your chap-secrets file:
+
+ DialupNT customer47 foobar
+ customer47 DialupNT foobar
+
+The only other thing you need to do for MS-CHAP (compared to normal CHAP)
+is to always use the "remotename" option, either on the command line or in
+your "options" file (see the pppd man page for details). In the case of
+the above example, you would need to use the following command line:
+
+ pppd name customer47 remotename DialupNT <other options>
+
+or add:
+
+ name customer47
+ remotename DialupNT
+
+to your PPPD "options" file.
+
+The "remotename" option is required for MS-CHAP since Microsoft PPP servers
+don't send their system name in the CHAP challenge packet.
+
+
+E=691 (AUTHENTICATION_FAILURE) ERRORS WHEN YOU HAVE THE VALID SECRET (PASSWORD)
+
+If your RAS server is not the domain controller and is not a 'stand-alone'
+server then it must make a query to the domain controller for your domain.
+
+You need to specify the domain name with the user name when you attempt to
+use this type of a configuration. The domain name is specified with the
+local name in the chap-secrets file and with the option for the 'name'
+parameter.
+
+For example, the previous example would become:
+
+ DialupNT domain\\customer47 foobar
+ domain\\customer47 DialupNT foobar
+
+and
+
+ pppd name 'domain\\customer47' remotename DialupNT <other options>
+
+or add:
+
+ name domain\\customer47
+ remotename DialupNT
+
+when the Windows NT domain name is simply called 'domain'.
+
+
+TROUBLESHOOTING
+
+Assuming that everything else has been configured correctly for PPP and
+CHAP, the MS-CHAP-specific problems you're likely to encounter are mostly
+related to your Windows NT account and its settings. A Microsoft server
+returns error codes in its CHAP response. The following are extracted from
+Microsoft's "chapexts.txt" file referenced above:
+
+ 646 ERROR_RESTRICTED_LOGON_HOURS
+ 647 ERROR_ACCT_DISABLED
+ 648 ERROR_PASSWD_EXPIRED
+ 649 ERROR_NO_DIALIN_PERMISSION
+ 691 ERROR_AUTHENTICATION_FAILURE
+ 709 ERROR_CHANGING_PASSWORD
+
+You'll see these in your pppd log as a line similar to:
+
+ Remote message: E=649 R=0
+
+The "E=" is the error number from the table above, and the "R=" flag
+indicates whether the error is transient and the client should retry. If
+you consistently get error 691, then either you're using the wrong account
+name/password, or the DES library or MD4 hashing (in md4.c) aren't working
+properly. Verify your account name and password (use a Windows NT or
+Windows 95 system to dial-in if you have one available). If that checks
+out, test the DES library with the "destest" program included with the DES
+library. If DES checks out, the md4.c routines are probably failing
+(system byte ordering may be a problem) or my code is screwing up. I've
+only got access to a Linux system, so you're on your own for anything else.
+
+Another thing that might cause problems is that some RAS servers won't
+respond at all to LCP config requests without seeing the word "CLIENT"
+from the other end. If you see pppd sending out LCP config requests
+without getting any reply, try putting something in your chat script
+to send the word CLIENT after the modem has connected.
+
+If everything compiles cleanly, but fails at authentication time, then
+it might be a case of the MD4 or DES code screwing up. The following
+small program can be used to test the MS-CHAP code to see if it
+produces a known response:
+
+-----------------
+#include <stdio.h>
+
+#include "pppd.h"
+#include "chap.h"
+#include "chap_ms.h"
+
+int main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ u_char challenge[8];
+ int challengeInt[sizeof(challenge)];
+ chap_state cstate;
+ int i;
+
+ if (argc != 3) {
+ fprintf(stderr, "Usage: %s <16-hexchar challenge> <password>\n",
+ argv[0]); exit(1);
+ }
+
+ sscanf(argv[1], "%2x%2x%2x%2x%2x%2x%2x%2x",
+ challengeInt + 0, challengeInt + 1, challengeInt + 2,
+ challengeInt + 3, challengeInt + 4, challengeInt + 5,
+ challengeInt + 6, challengeInt + 7);
+
+ for (i = 0; i < sizeof(challenge); i++)
+ challenge[i] = (u_char)challengeInt[i];
+
+ ChapMS(&cstate, challenge, sizeof(challenge), argv[2], strlen(argv[2]));
+ printf("Response length is %d, response is:", cstate.resp_length);
+
+ for (i = 0; i < cstate.resp_length; i++) {
+ if (i % 8 == 0)
+ putchar('\n');
+ printf("%02X ", (unsigned int)cstate.response[i]);
+ }
+
+ putchar('\n');
+
+ exit(0);
+}
+-------------
+
+This needs to link against chap_ms.o, md4.o, and the DES library. When
+you run it with the command line:
+
+ $ testchap 00000000000000000000000000000000 hello
+
+it should output the following:
+
+ Response length is 49, response is:
+ 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00
+ F4 D9 9D AF 82 64 DC 3C
+ 53 F9 BC 92 14 B5 5D 9E
+ 78 C4 21 48 9D B7 A8 B4
+ 01
+
+if not, then either the DES library is not working, the MD4 code isn't
+working, or there are some problems with the port of the code in
+chap_ms.c.
+
+
+STILL TO DO
+
+A site using only MS-CHAP to authenticate has no need to store cleartext
+passwords in the "chap-secrets" file. A utility that spits out the ASCII
+hex MD4 hash of a given password would be nice, and would allow that hash
+to be used in chap-secrets in place of the password. The code to do this
+could quite easily be lifted from chap_ms.c (you have to convert the
+password to Unicode before hashing it). The chap_ms.c file would also have
+to be changed to recognize a password hash (16 binary bytes == 32 ASCII hex
+characters) and skip the hashing stage.
+
+A server implementation would allow MS-CHAP to be used with Windows NT and
+Windows 95 clients for enhanced security. Some new command-line options
+would be required, as would code to generate the Challenge packet and
+verify the response. Most of the helper functions are in place, so this
+shouldn't be too hard for someone to add.
diff --git a/mdk-stage1/ppp/README.cbcp b/mdk-stage1/ppp/README.cbcp
new file mode 100644
index 000000000..6f7b7685e
--- /dev/null
+++ b/mdk-stage1/ppp/README.cbcp
@@ -0,0 +1,97 @@
+ Microsoft Call Back Configuration Protocol.
+ by Pedro Roque Marques
+ (updated by Paul Mackerras)
+
+The CBCP is a method by which the Microsoft Windows NT Server may
+implement additional security. It is possible to configure the server
+in such a manner so as to require that the client systems which
+connect with it are required that following a valid authentication to
+leave a method by which the number may be returned call.
+
+It is a requirement of servers so configured that the protocol be
+exchanged.
+
+So, this set of patches may be applied to the pppd process to enable
+the cbcp client *only* portion of the specification. It is primarily
+meant to permit connection with Windows NT Servers.
+
+The ietf-working specification may be obtained from ftp.microsoft.com
+in the developr/rfc directory.
+
+The ietf task group has decided to recommend that the LCP sequence be
+extended to permit the callback operation. For this reason, these
+patches are not 'part' of pppd but are an adjunct to the code.
+
+To enable CBCP support, all that is required is to change the
+appropriate Makefile in the pppd subdirectory to add "-DCBCP_SUPPORT"
+to the CFLAGS definition and add cbcp.o to the list of object files,
+and then recompile pppd. The patch below does this for Makefile.bsd
+and Makefile.linux.
+
+
+--------------------------------cut here-------------------------------
+diff -r -c ppp-2.3.orig/pppd/Makefile.bsd ppp-2.3/pppd/Makefile.bsd
+*** ppp-2.3.orig/pppd/Makefile.bsd Tue Oct 8 13:33:33 1996
+--- ppp-2.3/pppd/Makefile.bsd Fri Apr 11 23:59:15 1997
+***************
+*** 4,14 ****
+ # -D_BITYPES is for FreeBSD, which doesn't define anything to
+ # tell us that u_int32_t gets defined if <sys/types.h> is included.
+ # Remove for older *BSD systems for which this isn't true.
+! CFLAGS+= -g -I.. -DHAVE_PATHS_H -D_BITYPES
+
+ PROG= pppd
+ SRCS= main.c magic.c fsm.c lcp.c ipcp.c upap.c chap.c md5.c ccp.c \
+! demand.c auth.c options.c sys-bsd.c
+ MAN= pppd.cat8
+ MAN8= pppd.8
+ BINMODE=4555
+--- 4,14 ----
+ # -D_BITYPES is for FreeBSD, which doesn't define anything to
+ # tell us that u_int32_t gets defined if <sys/types.h> is included.
+ # Remove for older *BSD systems for which this isn't true.
+! CFLAGS+= -I.. -DHAVE_PATHS_H -D_BITYPES -DCBCP_SUPPORT
+
+ PROG= pppd
+ SRCS= main.c magic.c fsm.c lcp.c ipcp.c upap.c chap.c md5.c ccp.c \
+! demand.c auth.c options.c sys-bsd.c cbcp.c
+ MAN= pppd.cat8
+ MAN8= pppd.8
+ BINMODE=4555
+diff -r -c ppp-2.3.orig/pppd/Makefile.linux ppp-2.3/pppd/Makefile.linux
+*** ppp-2.3.orig/pppd/Makefile.linux Tue Oct 8 15:42:41 1996
+--- ppp-2.3/pppd/Makefile.linux Sat Apr 12 00:02:28 1997
+***************
+*** 14,20 ****
+ ipxcp.h cbcp.h
+ MANPAGES = pppd.8
+ PPPDOBJS = main.o magic.o fsm.o lcp.o ipcp.o upap.o chap.o md5.o ccp.o \
+! auth.o options.o demand.o sys-linux.o ipxcp.o
+
+ all: pppd
+
+--- 14,20 ----
+ ipxcp.h cbcp.h
+ MANPAGES = pppd.8
+ PPPDOBJS = main.o magic.o fsm.o lcp.o ipcp.o upap.o chap.o md5.o ccp.o \
+! auth.o options.o demand.o sys-linux.o ipxcp.o cbcp.o
+
+ all: pppd
+
+***************
+*** 36,42 ****
+ #INCLUDE_DIRS= -I/usr/include -I..
+ INCLUDE_DIRS=
+
+! COMPILE_FLAGS= -D_linux_=1 -DHAVE_PATHS_H -DIPX_CHANGE
+
+ CFLAGS= $(COPTS) $(COMPILE_FLAGS) $(INCLUDE_DIRS)
+
+--- 36,42 ----
+ #INCLUDE_DIRS= -I/usr/include -I..
+ INCLUDE_DIRS=
+
+! COMPILE_FLAGS= -D_linux_=1 -DHAVE_PATHS_H -DIPX_CHANGE -DCBCP_SUPPORT
+
+ CFLAGS= $(COPTS) $(COMPILE_FLAGS) $(INCLUDE_DIRS)
+
diff --git a/mdk-stage1/ppp/README.linux b/mdk-stage1/ppp/README.linux
new file mode 100644
index 000000000..62ed9ca7f
--- /dev/null
+++ b/mdk-stage1/ppp/README.linux
@@ -0,0 +1,297 @@
+ PPP for Linux
+ -------------
+
+ Paul Mackerras
+ 8 March 2001
+
+ for ppp-2.4.1
+
+1. Introduction
+---------------
+
+The Linux PPP implementation includes both kernel and user-level
+parts. This package contains the user-level part, which consists of
+the PPP daemon (pppd) and associated utilities. In the past this
+package has contained updated kernel drivers. This is no longer
+necessary, as the current 2.2 and 2.4 kernel sources contain
+up-to-date drivers.
+
+The Linux PPP implementation is capable of being used both for
+initiating PPP connections (as a `client') or for handling incoming
+PPP connections (as a `server'). Note that this is an operational
+distinction, based on how the connection is created, rather than a
+distinction that is made in the PPP protocols themselves.
+
+Mostly this package is used for PPP connections over modems connected
+via asynchronous serial ports, so this guide concentrates on this
+situation.
+
+The PPP protocol consists of two parts. One is a scheme for framing
+and encoding packets, the other is a series of protocols called LCP,
+IPCP, PAP and CHAP, for negotiating link options and for
+authentication. This package similarly consists of two parts: a
+kernel module which handles PPP's low-level framing protocol, and a
+user-level program called pppd which implements PPP's negotiation
+protocols.
+
+The kernel module assembles/disassembles PPP frames, handles error
+detection, and forwards packets between the serial port and either the
+kernel network code or the user-level program pppd. IP packets go
+directly to the kernel network code. So once pppd has negotiated the
+link, it in practice lies completely dormant until you want to take
+the link down, when it negotiates a graceful disconnect.
+
+
+2. Installation
+---------------
+
+2.1 Kernel driver
+
+Assuming you are running a recent 2.2 or 2.4 (or later) series kernel,
+the kernel source code will contain an up-to-date kernel PPP driver.
+If the PPP driver was included in your kernel configuration when your
+kernel was built, then you only need to install the user-level
+programs. Otherwise you will need to get the source tree for your
+kernel version, configure it with PPP included, and recompile. Most
+Linux distribution vendors ship kernels with PPP included in the
+configuration.
+
+The PPP driver can be either compiled into the kernel or compiled as a
+kernel module. If it is compiled into the kernel, the PPP driver is
+included in the kernel image which is loaded at boot time. If it is
+compiled as a module, the PPP driver is present in one or more files
+under /lib/modules and is loaded into the kernel when needed.
+
+The 2.2 series kernels contain an older version of the kernel PPP
+driver, one which doesn't support multilink. If you want multilink,
+you need to run the latest 2.4 series kernel. The kernel PPP driver
+was completely rewritten for the 2.4 series kernels to support
+multilink and to allow it to operate over diverse kinds of
+communication medium (the 2.2 driver only operates over serial ports
+and devices which look like serial ports, such as pseudo-ttys).
+
+Under the 2.2 kernels, if PPP is compiled as a module, the PPP driver
+modules should be present in the /lib/modules/`uname -r`/net directory
+(where `uname -r` represents the kernel version number). The PPP
+driver module itself is called ppp.o, and there will usually be
+compression modules there, ppp_deflate.o and bsd_comp.o, as well as
+slhc.o, which handles TCP/IP header compression. If the PPP driver is
+compiled into the kernel, the compression code will still be compiled
+as modules, for kernels before 2.2.17pre12. For 2.2.17pre12 and later,
+if the PPP driver is compiled in, the compression code will also.
+
+Under the 2.4 kernels, there are two PPP modules, ppp_generic.o and
+ppp_async.o, plus the compression modules (ppp_deflate.o, bsd_comp.o
+and slhc.o). If the PPP generic driver is compiled into the kernel,
+the other four can then be present either as modules or compiled into
+the kernel. There is a sixth module, ppp_synctty.o, which is used for
+synchronous tty devices such as high-speed WAN adaptors.
+
+
+2.2 User-level programs
+
+If you obtained this package in .rpm or .deb format, you simply follow
+the usual procedure for installing the package.
+
+If you are using the .tar.gz form of this package, then cd into the
+ppp-2.4.1b1 directory you obtained by unpacking the archive and issue
+the following commands:
+
+$ ./configure
+$ make
+# make install
+
+The `make install' has to be done as root. This makes and installs
+four programs and their man pages: pppd, chat, pppstats and pppdump.
+If the /etc/ppp configuration directory doesn't exist, the `make
+install' step will create it and install some default configuration
+files.
+
+
+2.3 System setup for 2.4 kernels
+
+Under the 2.4 series kernels, pppd needs to be able to open /dev/ppp,
+character device (108,0). If you are using devfs (the device
+filesystem), the /dev/ppp node will automagically appear when the
+ppp_generic module is loaded, or at startup if ppp_generic is compiled
+in.
+
+If you have ppp_generic as a module, and you are using devfsd (the
+devfs daemon), you will need to add a line like this to your
+/etc/devfsd.conf:
+
+LOOKUP ppp MODLOAD
+
+Otherwise you will need to create a /dev/ppp device node with the
+commands:
+
+# mknod /dev/ppp c 108 0
+# chmod 600 /dev/ppp
+
+If you use module autoloading and have PPP as a module, you will need
+to add the following to your /etc/modules.conf or /etc/conf.modules:
+
+alias /dev/ppp ppp_generic
+alias char-major-108 ppp_generic
+alias tty-ldisc-3 ppp_async
+alias tty-ldisc-14 ppp_synctty
+alias ppp-compress-21 bsd_comp
+alias ppp-compress-24 ppp_deflate
+alias ppp-compress-26 ppp_deflate
+
+
+2.4 System setup under 2.2 series kernels
+
+Under the 2.2 series kernels, you should add the following to your
+/etc/modules.conf or /etc/conf.modules:
+
+alias tty-ldisc-3 ppp
+alias ppp-compress-21 bsd_comp
+alias ppp-compress-24 ppp_deflate
+alias ppp-compress-26 ppp_deflate
+
+
+3. Getting help with problems
+-----------------------------
+
+If you have problems with your PPP setup, or you just want to ask some
+questions, or better yet if you can help others with their PPP
+questions, then you should join the linux-ppp mailing list. Send an
+email to majordomo@vger.kernel.org with a line in the body saying
+
+subscribe linux-ppp
+
+To leave the mailing list, send an email to majordomo@vger.kernel.org
+with a line in the body saying
+
+unsubscribe linux-ppp
+
+To send a message to the list, email it to linux-ppp@vger.kernel.org.
+You don't have to be subscribed to send messages to the list.
+
+You can also email me (paulus@linuxcare.com.au) but I am overloaded
+with email and I can't respond to most messages I get in a timely
+fashion.
+
+There are also several relevant news groups, such as comp.protocols.ppp,
+comp.os.linux.networking, or comp.os.linux.setup.
+
+
+4. Configuring your dial-out PPP connections
+--------------------------------------------
+
+Some Linux distribution makers include tools in their distributions
+for setting up PPP connections. For example, for Red Hat Linux and
+derivatives, you should probably use linuxconf or netcfg to set up
+your PPP connections.
+
+The two main windowing environments for Linux, KDE and Gnome, both
+come with GUI utilities for configuring and controlling PPP dial-out
+connections. They are convenient and relatively easy to configure.
+
+A third alternative is to use a PPP front-end package such as wvdial
+or ezppp. These also will handle most of the details of talking to
+the modem and setting up the PPP connection for you.
+
+Assuming that you don't want to use any of these tools, you want to
+set up the configuration manually yourself, then read on. This
+document gives a brief description and example. More details can be
+found by reading the pppd and chat man pages and the PPP-HOWTO.
+
+We assume that you have a modem that uses the Hayes-compatible AT
+command set connected to an async serial port (e.g. /dev/ttyS0) and
+that you are dialling out to an ISP.
+
+The trickiest and most variable part of setting up a dial-out PPP
+connection is the part which involves getting the modem to dial and
+then invoking PPP service at the far end. Generally, once both ends
+are talking PPP the rest is relatively straightforward.
+
+Now in fact pppd doesn't know anything about how to get modems to dial
+or what you have to say to the system at the far end to get it to talk
+PPP. That's handled by an external program such as chat, specified
+with the connect option to pppd. Chat takes a series of strings to
+expect from the modem interleaved with a series of strings to send to
+the modem. See the chat man page for more information. Here is a
+simple example for connecting to an ISP, assuming that the ISP's
+system starts talking PPP as soon as it answers the phone:
+
+pppd connect 'chat -v "" AT OK ATDT5551212 ~' \
+ /dev/ttyS0 57600 crtscts debug defaultroute
+
+Going through pppd's options in order:
+ connect 'chat ...' This gives a command to run to contact the
+ PPP server. Here the supplied 'chat' program is used to dial a
+ remote computer. The whole command is enclosed in single quotes
+ because pppd expects a one-word argument for the 'connect' option.
+ The options to 'chat' itself are:
+
+ -v verbose mode; log what we do to syslog
+ "" don't wait for any prompt, but instead...
+ AT send the string "AT"
+ OK expect the response "OK", then
+ ATDT5551212 dial the modem, then
+ ~ wait for a ~ character, indicating the start
+ of a PPP frame from the server
+
+ /dev/ttyS0 specifies which serial port the modem is connected to
+ 57600 specifies the baud rate to use
+ crtscts use hardware flow control using the RTS & CTS signals
+ debug log the PPP negotiation with syslog
+ defaultroute add default network route via the PPP link
+
+Pppd will write error messages and debugging logs to the syslogd
+daemon using the facility name "daemon". These messages may already
+be logged to the console or to a file like /var/log/messages; consult
+your /etc/syslog.conf file to see. If you want to make all pppd
+messages go to a file such as /var/log/ppp-debug, add the line
+
+daemon.* /var/log/ppp-debug
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ This is one or more tabs. Do not use spaces.
+
+to syslog.conf; make sure to put one or more TAB characters (not
+spaces!) between the two fields. Then you need to create an empty
+/var/log/ppp-debug file with a command such as
+
+ touch /var/log/ppp-debug
+
+and then restart syslogd, usually by sending it a SIGHUP signal with a
+command like this:
+
+ killall -HUP syslogd
+
+
+4.1 Is the link up?
+
+The main way to tell if your PPP link is up and operational is the
+ifconfig ("interface configuration") command. Type
+
+ /sbin/ifconfig
+
+at a shell prompt. It should print a list of interfaces including one
+like this example:
+
+ppp0 Link encap Point-to-Point Protocol
+ inet addr 192.76.32.3 P-t-P 129.67.1.165 Mask 255.255.255.0
+ UP POINTOPOINT RUNNING MTU 1500 Metric 1
+ RX packets 33 errors 0 dropped 0 overrun 0
+ TX packets 42 errors 0 dropped 0 overrun 0
+
+Assuming that ifconfig shows the ppp network interface, you can test
+the link using the ping command like this:
+
+ /sbin/ping -c 3 129.67.1.165
+
+where the address you give is the address shown as the P-t-P address
+in the ifconfig output. If the link is operating correctly, you
+should see output like this:
+
+ PING 129.67.1.165 (129.67.1.165): 56 data bytes
+ 64 bytes from 129.67.1.165: icmp_seq=0 ttl=255 time=268 ms
+ 64 bytes from 129.67.1.165: icmp_seq=1 ttl=255 time=247 ms
+ 64 bytes from 129.67.1.165: icmp_seq=2 ttl=255 time=266 ms
+ --- 129.67.1.165 ping statistics ---
+ 3 packets transmitted, 3 packets received, 0% packet loss
+ round-trip min/avg/max = 247/260/268 ms
+
diff --git a/mdk-stage1/ppp/README.sol2 b/mdk-stage1/ppp/README.sol2
new file mode 100644
index 000000000..4c862208f
--- /dev/null
+++ b/mdk-stage1/ppp/README.sol2
@@ -0,0 +1,220 @@
+This file describes the installation process for ppp-2.3 on systems
+running Solaris 2. The Solaris 2 and SVR4 ports share a lot of code
+but are not identical. The STREAMS kernel modules and driver for
+Solaris 2 are in the svr4 directory (and use some code from the
+modules directory).
+
+NOTE: Although the kernel driver and modules have been designed to
+operate correctly on SMP systems, they have not been extensively
+tested on SMP machines. Some users of SMP Solaris x86 systems have
+reported system problems apparently linked to the use of previous
+versions of this software. I believe these problems have been fixed.
+
+
+Installation.
+*************
+
+1. Run the configure script and make the user-level programs and the
+kernel modules.
+
+ ./configure
+ make
+
+If you wish to use gcc (or another compiler) instead of Sun's cc, edit
+the svr4/Makedefs file and uncomment the definition of CC. You can
+also change the options passed to the C compiler by editing the COPTS
+definition.
+
+2. Install the programs and kernel modules: as root, do
+
+ make install
+
+This installs pppd, chat and pppstats in /usr/local/bin and the kernel
+modules in /kernel/drv and /kernel/strmod, and creates the /etc/ppp
+directory and populates it with default configuration files. You can
+change the installation directories by editing svr4/Makedefs.
+
+If your system normally has only one network interface, the default
+Solaris 2 system startup scripts will disable IP forwarding in the IP
+kernel module. This will prevent the remote machine from using the
+local machine as a gateway to access other hosts. The solution is to
+create an /etc/ppp/ip-up script containing something like this:
+
+ #!/bin/sh
+ /usr/sbin/ndd -set /dev/ip ip_forwarding 1
+
+See the man page for ip(7p) for details.
+
+Dynamic STREAMS Re-Plumbing Support.
+************************************
+
+Solaris 8 includes dynamic re-plumbing support. With this, modules
+below ip can be inserted, or removed, without having the ip stream be
+unplumbed, and re-plumbed again. All states in ip for an interface
+will therefore now be preserved. Users can install (or upgrade)
+modules like firewall, bandwidth manager, cache manager, tunneling,
+etc., without shutting the machine down.
+
+To support this, ppp driver now uses /dev/udp instead of /dev/ip for
+the ip stream. The interface stream (where ip module pushed on top of
+ppp) is then I_PLINK'ed below the ip stream. /dev/udp is used because
+STREAMS will not let a driver be PLINK'ed under itself, and /dev/ip is
+typically the driver at the bottom of the tunneling interfaces
+stream. The mux ids of the ip streams are then added using
+SIOCSxIFMUXID ioctl.
+
+Users will be able to see the modules on the interface stream by, for
+example:
+
+ pikapon% ifconfig ppp modlist
+ 0 ip
+ 1 ppp
+
+Or arbitrarily if bandwidth manager and firewall modules are installed:
+
+ pikapon% ifconfig hme0 modlist
+ 0 arp
+ 1 ip
+ 2 ipqos
+ 3 firewall
+ 4 hme
+
+Snoop Support.
+**************
+
+This version includes support for /usr/sbin/snoop. Tests has been done
+on both Solaris 7 and 8. Only IPv4 and IPv6 packets will be sent up to
+stream(s) marked as promiscuous, e.g, snoop et al.
+
+Users will be able to see the packets on the ppp interface by, for example:
+
+ snoop -d ppp0
+
+See the man page for snoop(1M) for details.
+
+IPv6 Support.
+*************
+
+This is for Solaris 8 and later.
+
+This version has been tested under Solaris 8 running IPv6. As of now,
+interoperability testing has only been done between Solaris machines
+in terms of the IPV6 NCP. An additional command line option for the
+pppd daemon has been added: ipv6cp-use-persistent.
+
+By default, compilation for IPv6 support is not enabled. Uncomment
+the necessary lines in pppd/Makefile.sol2 to enable it. Once done, the
+quickest way to get IPv6 running is to add the following somewhere in
+the command line option:
+
+ +ipv6 ipv6cp-use-persistent
+
+The persistent id for the link-local address was added to conform to
+RFC 2472; such that if there's an EUI-48 available, use that to make
+up the EUI-64. As of now, the Solaris implementation extracts the
+EUI-48 id from the Ethernet's MAC address (the ethernet interface
+needs to be up). Future works might support other ways of obtaining a
+unique yet persistent id, such as EEPROM serial numbers, etc.
+
+There need not be any up/down scripts for ipv6, e.g. /etc/ppp/ipv6-up
+or /etc/ppp/ipv6-down, to trigger IPv6 neighbor discovery for auto
+configuration and routing. The in.ndpd daemon will perform all of the
+necessary jobs in the background. /etc/inet/ndpd.conf can be further
+customized to enable the machine as an IPv6 router. See the man page
+for in.ndpd(1M) and ndpd.conf(4) for details.
+
+Below is a sample output of "ifconfig -a" with persistent link-local
+address. Note the UNNUMBERED flag is set because hme0 and ppp0 both
+have identical link-local IPv6 addresses:
+
+lo0: flags=1000849<UP,LOOPBACK,RUNNING,MULTICAST,IPv4> mtu 8232 index 1
+ inet 127.0.0.1 netmask ff000000
+hme0: flags=1000843<UP,BROADCAST,RUNNING,MULTICAST,IPv4> mtu 1500 index 2
+ inet 129.146.86.248 netmask ffffff00 broadcast 129.146.86.255
+ ether 8:0:20:8d:38:c1
+lo0: flags=2000849<UP,LOOPBACK,RUNNING,MULTICAST,IPv6> mtu 8252 index 1
+ inet6 ::1/128
+hme0: flags=2000841<UP,RUNNING,MULTICAST,IPv6> mtu 1500 index 2
+ ether 8:0:20:8d:38:c1
+ inet6 fe80::a00:20ff:fe8d:38c1/10
+hme0:1: flags=2080841<UP,RUNNING,MULTICAST,ADDRCONF,IPv6> mtu 1500 index 2
+ inet6 fec0::56:a00:20ff:fe8d:38c1/64
+hme0:2: flags=2080841<UP,RUNNING,MULTICAST,ADDRCONF,IPv6> mtu 1500 index 2
+ inet6 2000::56:a00:20ff:fe8d:38c1/64
+hme0:3: flags=2080841<UP,RUNNING,MULTICAST,ADDRCONF,IPv6> mtu 1500 index 2
+ inet6 2::56:a00:20ff:fe8d:38c1/64
+ppp0: flags=10008d1<UP,POINTOPOINT,RUNNING,NOARP,MULTICAST,IPv4> mtu 1500 index 12
+ inet 172.16.1.1 --> 172.16.1.2 netmask ffffff00
+ppp0: flags=2202851<UP,POINTOPOINT,RUNNING,MULTICAST,UNNUMBERED,NONUD,IPv6> mtu 1500 index 12
+ inet6 fe80::a00:20ff:fe8d:38c1/10 --> fe80::a00:20ff:fe7a:24fb
+
+Note also that a plumbed ipv6 interface stream will exist throughout
+the entire PPP session in the case where the peer rejects IPV6CP,
+which further causes the interface state to stay down. Unplumbing will
+happen when the daemon exits. This is done by design and is not a bug.
+
+64-bit Support.
+***************
+
+This version has been tested under Solaris 7 (and Solaris 8 ) in both
+32- and 64-bits environments (Ultra class machines). Installing the
+package by executing "make install" will result in additional files
+residing in /kernel/drv/sparcv9 and /kernel/strmod/sparcv9
+subdirectories.
+
+64-bit modules and driver have been compiled and tested using Sun's cc.
+
+Synchronous Serial Support.
+***************************
+
+This version has working but limited support for the on-board
+synchronous HDLC interfaces. It has been tested with the /dev/se_hdlc
+and /dev/zsh drivers. Synchronous mode was tested with a Cisco
+router.
+
+There ppp daemon does not directly support controlling the serial
+interface. It relies on the /usr/sbin/syncinit command to initialize
+HDLC mode and clocking.
+
+Some bugs remain: large sized frames are not sent/received properly,
+and may be related to the IP mtu. This may be due to bugs in pppd
+itself, bugs in Solaris or the serial drivers. The /dev/zsh driver
+seems more larger and can send/receive larger frames than the
+/dev/se_hdlc driver. There is a confirmed bug with NRZ/NRZI mode in
+the /dev/se_hdlc driver, and Solaris patch 104596-11 is needed to
+correct it. (However this patch seems to introduce other serial
+problems. If you don't apply the patch, the workaround is to change
+the nrzi mode to yes or no, whichever works)
+
+How to start pppd with synchronous support:
+
+#!/bin/sh
+
+local=1.1.1.1 # your ip address here
+baud=38400 # needed, but ignored by serial driver
+
+# Change to the correct serial driver/port
+#dev=/dev/zsh0
+dev=/dev/se_hdlc0
+
+# Change the driver, nrzi mode, speed and clocking to match your setup
+# This configuration is for external clocking from the DCE
+connect="syncinit se_hdlc0 nrzi=no speed=64000 txc=rxc rxc=rxc"
+
+/usr/sbin/pppd $dev sync $baud novj noauth $local: connect "$connect"
+
+
+Sample Cisco router config excerpt:
+
+!
+! Cisco router setup as DCE with RS-232 DCE cable
+!
+!
+interface Serial0
+ ip address 1.1.1.2 255.255.255.0
+ encapsulation ppp
+ clockrate 64000
+ no nrzi-encoding
+ no shutdown
+!
+
diff --git a/mdk-stage1/ppp/README.sunos4 b/mdk-stage1/ppp/README.sunos4
new file mode 100644
index 000000000..b48aec377
--- /dev/null
+++ b/mdk-stage1/ppp/README.sunos4
@@ -0,0 +1,62 @@
+This file describes the installation process for ppp-2.3 on systems
+running SunOS 4.1.x (or the equivalent).
+
+The STREAMS modules in the sunos4 directory provide kernel support for
+PPP on SunOS 4.1.x systems. They have been tested under SunOS 4.1.3
+on a SparcStation 1+. They should work under earlier SunOS 4.1.x
+systems, but no guarantees are given.
+
+These modules are designed to be loaded into the running kernel using
+the `modload' command.
+
+
+Installation.
+*************
+
+1. Run the configure script and make the user-level programs and the
+kernel modules.
+
+ ./configure
+ make
+
+If you wish to compile using gcc instead of cc, edit the
+sunos4/Makedefs file and uncomment the line saying "CC = gcc". You
+can also change the C compiler options by editing the COPTS
+definition.
+
+2. Install the pppd, pppstats and chat programs and the loadable
+module object files (you need to be root to do this):
+
+ make install
+
+By default, the programs and the loadable module object files go into
+/usr/local/etc. Doing `make install' also copies a script called
+ppp.INSTALL into /dev, and makes ppp.LOAD, ppp.UNLOAD, ppp.MKDEV and
+ppp.RMDEV links to it. You can change the installation directories by
+editing sunos4/Makedefs.
+
+3. Load the ppp modules (you need to be root for this too):
+
+ /dev/ppp.LOAD
+
+You will want to do this in your /etc/rc.local file once you have
+everything installed. I suggest you put something like the following
+in /etc/rc.local (or /etc/loadable, if you have one):
+
+ if [ -f /dev/ppp.AUTOLOAD ]; then
+ /dev/ppp.LOAD
+ fi
+
+and then create a /dev/ppp.AUTOLOAD file with the command
+
+ touch /dev/ppp.AUTOLOAD
+
+It is not advisable to unload the "if_ppp" module, because it creates
+network interface units, and SunOS does not provide any way to destroy
+network interfaces once created. If you do unload it, the system will
+probably crash at some later stage.
+
+If you have previously had ppp-2.2 installed, you may have statements
+in your /etc/rc.local to load the ppp module. You will need to remove
+those. Having done this, you will need to reboot to remove the old
+ppp module and load the new modules.
diff --git a/mdk-stage1/ppp/SETUP b/mdk-stage1/ppp/SETUP
new file mode 100644
index 000000000..fb28a2138
--- /dev/null
+++ b/mdk-stage1/ppp/SETUP
@@ -0,0 +1,111 @@
+ Configuring a PPP link.
+
+After you have compiled and installed this package, there are some
+configuration files which will generally need to be set up. The
+pppd(8) man page is the best reference for the full details; this file
+outlines the configuration process for the most common case, where
+this package is being used to enable a machine to dial an ISP and
+connect to the internet. The FAQ and README.linux files also provide
+useful information about setting up PPP.
+
+Dialling an ISP.
+****************
+
+Usually, an ISP will assign an IP address to your machine, and will
+refuse to authenticate itself to you. Some ISPs require a username
+and password to be entered before PPP service commences, while others
+use PPP authentication (using either the PAP or CHAP protocols).
+
+The recommended way to set up to dial an ISP is for the system
+administrator to create a file under /etc/ppp/peers, named for the ISP
+that you will be dialling. For example, suppose the file is called
+/etc/ppp/peers/isp. This file would contain something like this:
+
+cua0 # modem is connected to /dev/cua0
+38400 # run the serial port at 38400 baud
+crtscts # use hardware flow control
+noauth # don't require the ISP to authenticate itself
+defaultroute # use the ISP as our default route
+connect '/usr/sbin/chat -v -f /etc/ppp/chat-isp'
+
+If there are any other pppd options that should apply when calling
+this ISP, they can also be placed in this file.
+
+The /etc/ppp/chat-isp file named in the last line contains the script
+for chat(8) to use to dial the ISP and go through any username/
+password authentication required before PPP service starts. Here is
+an example (for dialling an Annex terminal server):
+
+ABORT "NO CARRIER"
+ABORT "NO DIALTONE"
+ABORT "ERROR"
+ABORT "NO ANSWER"
+ABORT "BUSY"
+ABORT "Username/Password Incorrect"
+"" "at"
+OK "at&d2&c1"
+OK "atdt2479381"
+"name:" "^Uusername"
+"word:" "\qpassword"
+"annex" "ppp"
+"Switching to PPP-ppp-Switching to PPP"
+
+See the chat(8) man page for details of the script. If you are not
+sure how the initial dialog with your ISP will go, you could use
+a terminal emulator such as kermit or minicom to go through the
+process manually.
+
+If your ISP requires PAP or CHAP authentication, you will have to
+create a line in /etc/ppp/pap-secrets or /etc/ppp/chap-secrets like
+this:
+
+myhostname * "password"
+
+(Replace myhostname with the hostname of your machine.)
+
+At this point, you can initiate the link with the command:
+
+/usr/sbin/pppd call isp
+
+(N.B.: pppd might be installed in a different directory on some
+systems).
+
+This will return to the shell prompt immediately, as pppd will detach
+itself from its controlling terminal. (If you don't want it to do
+this, use the "nodetach" option.)
+
+Pppd will log messages describing the progress of the connection and
+any errors using the syslog facility (see the syslogd(8) and
+syslog.conf(5) man pages). Pppd issues messages using syslog facility
+daemon (or local2 if it has been compiled with debugging enabled);
+chat uses facility local2. It is often useful to see messages of
+priority notice or higher on the console. To see these, find the line
+in /etc/syslog.conf which has /dev/console on the right-hand side, and
+add `daemon.notice' on the left. This line should end up something
+like this:
+
+*.err;kern.debug;daemon,local2,auth.notice;mail.crit /dev/console
+
+If you want to see more messages from pppd, request messages of
+priority info or higher for facility daemon, like this:
+
+*.err;kern.debug;daemon.info;local2,auth.notice;mail.crit /dev/console
+
+It is also useful to add a line like this:
+
+daemon,local2.debug /etc/ppp/ppp-log
+
+If you do this, you will need to create an empty /etc/ppp/ppp-log
+file.
+
+After modifying syslog.conf, you will then need to send a HUP signal
+to syslogd (or reboot).
+
+When you wish terminate the PPP link, you should send a TERM or INTR
+signal to pppd. Pppd writes its process ID to a file called
+ppp<n>.pid in /var/run (or /etc/ppp on older systems such as SunOS or
+Ultrix). Here <n> is the PPP interface unit number, which will be 0
+unless you have more than one PPP link running simultaneously. Thus
+you can terminate the link with a command like
+
+ kill `cat /var/run/ppp0.pid`
diff --git a/mdk-stage1/ppp/chat/Makefile.linux b/mdk-stage1/ppp/chat/Makefile.linux
new file mode 100644
index 000000000..a7045522c
--- /dev/null
+++ b/mdk-stage1/ppp/chat/Makefile.linux
@@ -0,0 +1,27 @@
+# $Id: Makefile.linux 195720 2001-06-11 11:44:34Z gc $
+
+CDEF1= -DTERMIOS # Use the termios structure
+CDEF2= -DSIGTYPE=void # Standard definition
+CDEF3= -UNO_SLEEP # Use the usleep function
+CDEF4= -DFNDELAY=O_NDELAY # Old name value
+CDEFS= $(CDEF1) $(CDEF2) $(CDEF3) $(CDEF4)
+
+CFLAGS= $(RPM_OPT_FLAGS) $(CDEFS)
+
+INSTALL= install
+
+all: chat
+
+chat: chat.o
+ $(CC) -o chat chat.o
+
+chat.o: chat.c
+ $(CC) -c $(CFLAGS) -o chat.o chat.c
+
+install: chat
+ mkdir -p $(BINDIR)
+ $(INSTALL) -s -c chat $(BINDIR)
+ $(INSTALL) -c -m 644 chat.8 $(MANDIR)/man8
+
+clean:
+ rm -f chat.o chat *~
diff --git a/mdk-stage1/ppp/chat/Makefile.linux.makeopt b/mdk-stage1/ppp/chat/Makefile.linux.makeopt
new file mode 100644
index 000000000..32f4e71ac
--- /dev/null
+++ b/mdk-stage1/ppp/chat/Makefile.linux.makeopt
@@ -0,0 +1,27 @@
+# $Id: Makefile.linux.makeopt 195720 2001-06-11 11:44:34Z gc $
+
+CDEF1= -DTERMIOS # Use the termios structure
+CDEF2= -DSIGTYPE=void # Standard definition
+CDEF3= -UNO_SLEEP # Use the usleep function
+CDEF4= -DFNDELAY=O_NDELAY # Old name value
+CDEFS= $(CDEF1) $(CDEF2) $(CDEF3) $(CDEF4)
+
+CFLAGS= -O2 -g -pipe $(CDEFS)
+
+INSTALL= install
+
+all: chat
+
+chat: chat.o
+ $(CC) -o chat chat.o
+
+chat.o: chat.c
+ $(CC) -c $(CFLAGS) -o chat.o chat.c
+
+install: chat
+ mkdir -p $(BINDIR)
+ $(INSTALL) -s -c chat $(BINDIR)
+ $(INSTALL) -c -m 644 chat.8 $(MANDIR)/man8
+
+clean:
+ rm -f chat.o chat *~
diff --git a/mdk-stage1/ppp/chat/Makefile.sol2 b/mdk-stage1/ppp/chat/Makefile.sol2
new file mode 100644
index 000000000..f566cc68b
--- /dev/null
+++ b/mdk-stage1/ppp/chat/Makefile.sol2
@@ -0,0 +1,19 @@
+#
+# Makefile for chat on Solaris 2
+#
+
+include ../solaris/Makedefs
+
+CFLAGS = $(COPTS) -DNO_USLEEP -DSOL2
+
+all: chat
+
+chat: chat.o
+ $(CC) -o chat chat.o
+
+install: chat
+ $(INSTALL) -f $(BINDIR) chat
+ $(INSTALL) -m 444 -f $(MANDIR)/man8 chat.8
+
+clean:
+ rm -f *~ *.o chat
diff --git a/mdk-stage1/ppp/chat/Makefile.sunos4 b/mdk-stage1/ppp/chat/Makefile.sunos4
new file mode 100644
index 000000000..b3507360e
--- /dev/null
+++ b/mdk-stage1/ppp/chat/Makefile.sunos4
@@ -0,0 +1,19 @@
+#
+# Makefile for chat on suns
+#
+
+include ../sunos4/Makedefs
+
+CFLAGS = -DSUNOS $(COPTS)
+
+all: chat
+
+chat: chat.o
+ $(CC) -o chat chat.o
+
+install: chat
+ $(INSTALL) -c chat $(BINDIR)/chat
+ $(INSTALL) -c -m 444 chat.8 $(MANDIR)/man8/chat.8
+
+clean:
+ rm -f *~ *.o chat
diff --git a/mdk-stage1/ppp/chat/chat.8 b/mdk-stage1/ppp/chat/chat.8
new file mode 100644
index 000000000..dc3889cfc
--- /dev/null
+++ b/mdk-stage1/ppp/chat/chat.8
@@ -0,0 +1,515 @@
+.\" -*- nroff -*-
+.\" manual page [] for chat 1.8
+.\" $Id: chat.8 195720 2001-06-11 11:44:34Z gc $
+.\" SH section heading
+.\" SS subsection heading
+.\" LP paragraph
+.\" IP indented paragraph
+.\" TP hanging label
+.TH CHAT 8 "22 May 1999" "Chat Version 1.22"
+.SH NAME
+chat \- Automated conversational script with a modem
+.SH SYNOPSIS
+.B chat
+[
+.I options
+]
+.I script
+.SH DESCRIPTION
+.LP
+The \fIchat\fR program defines a conversational exchange between the
+computer and the modem. Its primary purpose is to establish the
+connection between the Point-to-Point Protocol Daemon (\fIpppd\fR) and
+the remote's \fIpppd\fR process.
+.SH OPTIONS
+.TP
+.B -f \fI<chat file>
+Read the chat script from the chat \fIfile\fR. The use of this option
+is mutually exclusive with the chat script parameters. The user must
+have read access to the file. Multiple lines are permitted in the
+file. Space or horizontal tab characters should be used to separate
+the strings.
+.TP
+.B -t \fI<timeout>
+Set the timeout for the expected string to be received. If the string
+is not received within the time limit then the reply string is not
+sent. An alternate reply may be sent or the script will fail if there
+is no alternate reply string. A failed script will cause the
+\fIchat\fR program to terminate with a non-zero error code.
+.TP
+.B -r \fI<report file>
+Set the file for output of the report strings. If you use the keyword
+\fIREPORT\fR, the resulting strings are written to this file. If this
+option is not used and you still use \fIREPORT\fR keywords, the
+\fIstderr\fR file is used for the report strings.
+.TP
+.B -e
+Start with the echo option turned on. Echoing may also be turned on
+or off at specific points in the chat script by using the \fIECHO\fR
+keyword. When echoing is enabled, all output from the modem is echoed
+to \fIstderr\fR.
+.TP
+.B -E
+Enables environment variable substituion within chat scripts using the
+standard \fI$xxx\fR syntax.
+.TP
+.B -v
+Request that the \fIchat\fR script be executed in a verbose mode. The
+\fIchat\fR program will then log the execution state of the chat
+script as well as all text received from the modem and the output
+strings sent to the modem. The default is to log through the SYSLOG;
+the logging method may be altered with the -S and -s flags.
+.TP
+.B -V
+Request that the \fIchat\fR script be executed in a stderr verbose
+mode. The \fIchat\fR program will then log all text received from the
+modem and the output strings sent to the modem to the stderr device. This
+device is usually the local console at the station running the chat or
+pppd program.
+.TP
+.B -s
+Use stderr. All log messages from '-v' and all error messages will be
+sent to stderr.
+.TP
+.B -S
+Do not use the SYSLOG. By default, error messages are sent to the
+SYSLOG. The use of -S will prevent both log messages from '-v' and
+error messages from being sent to the SYSLOG.
+.TP
+.B -T \fI<phone number>
+Pass in an arbitary string, usually a phone number, that will be
+substituted for the \\T substitution metacharacter in a send string.
+.TP
+.B -U \fI<phone number 2>
+Pass in a second string, usually a phone number, that will be
+substituted for the \\U substitution metacharacter in a send string.
+This is useful when dialing an ISDN terminal adapter that requires two
+numbers.
+.TP
+.B script
+If the script is not specified in a file with the \fI-f\fR option then
+the script is included as parameters to the \fIchat\fR program.
+.SH CHAT SCRIPT
+.LP
+The \fIchat\fR script defines the communications.
+.LP
+A script consists of one or more "expect-send" pairs of strings,
+separated by spaces, with an optional "subexpect-subsend" string pair,
+separated by a dash as in the following example:
+.IP
+ogin:-BREAK-ogin: ppp ssword: hello2u2
+.LP
+This line indicates that the \fIchat\fR program should expect the string
+"ogin:". If it fails to receive a login prompt within the time interval
+allotted, it is to send a break sequence to the remote and then expect the
+string "ogin:". If the first "ogin:" is received then the break sequence is
+not generated.
+.LP
+Once it received the login prompt the \fIchat\fR program will send the
+string ppp and then expect the prompt "ssword:". When it receives the
+prompt for the password, it will send the password hello2u2.
+.LP
+A carriage return is normally sent following the reply string. It is not
+expected in the "expect" string unless it is specifically requested by using
+the \\r character sequence.
+.LP
+The expect sequence should contain only what is needed to identify the
+string. Since it is normally stored on a disk file, it should not contain
+variable information. It is generally not acceptable to look for time
+strings, network identification strings, or other variable pieces of data as
+an expect string.
+.LP
+To help correct for characters which may be corrupted during the initial
+sequence, look for the string "ogin:" rather than "login:". It is possible
+that the leading "l" character may be received in error and you may never
+find the string even though it was sent by the system. For this reason,
+scripts look for "ogin:" rather than "login:" and "ssword:" rather than
+"password:".
+.LP
+A very simple script might look like this:
+.IP
+ogin: ppp ssword: hello2u2
+.LP
+In other words, expect ....ogin:, send ppp, expect ...ssword:, send hello2u2.
+.LP
+In actual practice, simple scripts are rare. At the vary least, you
+should include sub-expect sequences should the original string not be
+received. For example, consider the following script:
+.IP
+ogin:--ogin: ppp ssword: hello2u2
+.LP
+This would be a better script than the simple one used earlier. This would look
+for the same login: prompt, however, if one was not received, a single
+return sequence is sent and then it will look for login: again. Should line
+noise obscure the first login prompt then sending the empty line will
+usually generate a login prompt again.
+.SH COMMENTS
+Comments can be embedded in the chat script. A comment is a line which
+starts with the \fB#\fR (hash) character in column 1. Such comment
+lines are just ignored by the chat program. If a '#' character is to
+be expected as the first character of the expect sequence, you should
+quote the expect string.
+If you want to wait for a prompt that starts with a # (hash)
+character, you would have to write something like this:
+.IP
+# Now wait for the prompt and send logout string
+.br
+\'# ' logout
+.LP
+
+.SH SENDING DATA FROM A FILE
+If the string to send starts with an at sign (@), the rest of the
+string is taken to be the name of a file to read to get the string to
+send. If the last character of the data read is a newline, it is
+removed. The file can be a named pipe (or fifo) instead of a regular
+file. This provides a way for \fBchat\fR to communicate with another
+program, for example, a program to prompt the user and receive a
+password typed in.
+.LP
+
+.SH ABORT STRINGS
+Many modems will report the status of the call as a string. These
+strings may be \fBCONNECTED\fR or \fBNO CARRIER\fR or \fBBUSY\fR. It
+is often desirable to terminate the script should the modem fail to
+connect to the remote. The difficulty is that a script would not know
+exactly which modem string it may receive. On one attempt, it may
+receive \fBBUSY\fR while the next time it may receive \fBNO CARRIER\fR.
+.LP
+These "abort" strings may be specified in the script using the \fIABORT\fR
+sequence. It is written in the script as in the following example:
+.IP
+ABORT BUSY ABORT 'NO CARRIER' '' ATZ OK ATDT5551212 CONNECT
+.LP
+This sequence will expect nothing; and then send the string ATZ. The
+expected response to this is the string \fIOK\fR. When it receives \fIOK\fR,
+the string ATDT5551212 to dial the telephone. The expected string is
+\fICONNECT\fR. If the string \fICONNECT\fR is received the remainder of the
+script is executed. However, should the modem find a busy telephone, it will
+send the string \fIBUSY\fR. This will cause the string to match the abort
+character sequence. The script will then fail because it found a match to
+the abort string. If it received the string \fINO CARRIER\fR, it will abort
+for the same reason. Either string may be received. Either string will
+terminate the \fIchat\fR script.
+.SH CLR_ABORT STRINGS
+This sequence allows for clearing previously set \fBABORT\fR strings.
+\fBABORT\fR strings are kept in an array of a pre-determined size (at
+compilation time); \fBCLR_ABORT\fR will reclaim the space for cleared
+entries so that new strings can use that space.
+.SH SAY STRINGS
+The \fBSAY\fR directive allows the script to send strings to the user
+at the terminal via standard error. If \fBchat\fR is being run by
+pppd, and pppd is running as a daemon (detached from its controlling
+terminal), standard error will normally be redirected to the file
+/etc/ppp/connect-errors.
+.LP
+\fBSAY\fR strings must be enclosed in single or double quotes. If
+carriage return and line feed are needed in the string to be output,
+you must explicitely add them to your string.
+.LP
+The SAY strings could be used to give progress messages in sections of
+the script where you want to have 'ECHO OFF' but still let the user
+know what is happening. An example is:
+.IP
+ABORT BUSY
+.br
+ECHO OFF
+.br
+SAY "Dialling your ISP...\\n"
+.br
+\'' ATDT5551212
+.br
+TIMEOUT 120
+.br
+SAY "Waiting up to 2 minutes for connection ... "
+.br
+CONNECT ''
+.br
+SAY "Connected, now logging in ...\n"
+.br
+ogin: account
+.br
+ssword: pass
+.br
+$ \c
+SAY "Logged in OK ...\n"
+\fIetc ...\fR
+.LP
+This sequence will only present the SAY strings to the user and all
+the details of the script will remain hidden. For example, if the
+above script works, the user will see:
+.IP
+Dialling your ISP...
+.br
+Waiting up to 2 minutes for connection ... Connected, now logging in ...
+.br
+Logged in OK ...
+.LP
+
+.SH REPORT STRINGS
+A \fBreport\fR string is similar to the ABORT string. The difference
+is that the strings, and all characters to the next control character
+such as a carriage return, are written to the report file.
+.LP
+The report strings may be used to isolate the transmission rate of the
+modem's connect string and return the value to the chat user. The
+analysis of the report string logic occurs in conjunction with the
+other string processing such as looking for the expect string. The use
+of the same string for a report and abort sequence is probably not
+very useful, however, it is possible.
+.LP
+The report strings to no change the completion code of the program.
+.LP
+These "report" strings may be specified in the script using the \fIREPORT\fR
+sequence. It is written in the script as in the following example:
+.IP
+REPORT CONNECT ABORT BUSY '' ATDT5551212 CONNECT '' ogin: account
+.LP
+This sequence will expect nothing; and then send the string
+ATDT5551212 to dial the telephone. The expected string is
+\fICONNECT\fR. If the string \fICONNECT\fR is received the remainder
+of the script is executed. In addition the program will write to the
+expect-file the string "CONNECT" plus any characters which follow it
+such as the connection rate.
+.SH CLR_REPORT STRINGS
+This sequence allows for clearing previously set \fBREPORT\fR strings.
+\fBREPORT\fR strings are kept in an array of a pre-determined size (at
+compilation time); \fBCLR_REPORT\fR will reclaim the space for cleared
+entries so that new strings can use that space.
+.SH ECHO
+The echo options controls whether the output from the modem is echoed
+to \fIstderr\fR. This option may be set with the \fI-e\fR option, but
+it can also be controlled by the \fIECHO\fR keyword. The "expect-send"
+pair \fIECHO\fR \fION\fR enables echoing, and \fIECHO\fR \fIOFF\fR
+disables it. With this keyword you can select which parts of the
+conversation should be visible. For instance, with the following
+script:
+.IP
+ABORT 'BUSY'
+.br
+ABORT 'NO CARRIER'
+.br
+'' ATZ
+.br
+OK\\r\\n ATD1234567
+.br
+\\r\\n \\c
+.br
+ECHO ON
+.br
+CONNECT \\c
+.br
+ogin: account
+.LP
+all output resulting from modem configuration and dialing is not visible,
+but starting with the \fICONNECT\fR (or \fIBUSY\fR) message, everything
+will be echoed.
+.SH HANGUP
+The HANGUP options control whether a modem hangup should be considered
+as an error or not. This option is useful in scripts for dialling
+systems which will hang up and call your system back. The HANGUP
+options can be \fBON\fR or \fBOFF\fR.
+.br
+When HANGUP is set OFF and the modem hangs up (e.g., after the first
+stage of logging in to a callback system), \fBchat\fR will continue
+running the script (e.g., waiting for the incoming call and second
+stage login prompt). As soon as the incoming call is connected, you
+should use the \fBHANGUP ON\fR directive to reinstall normal hang up
+signal behavior. Here is an (simple) example script:
+.IP
+ABORT 'BUSY'
+.br
+'' ATZ
+.br
+OK\\r\\n ATD1234567
+.br
+\\r\\n \\c
+.br
+CONNECT \\c
+.br
+\'Callback login:' call_back_ID
+.br
+HANGUP OFF
+.br
+ABORT "Bad Login"
+.br
+\'Callback Password:' Call_back_password
+.br
+TIMEOUT 120
+.br
+CONNECT \\c
+.br
+HANGUP ON
+.br
+ABORT "NO CARRIER"
+.br
+ogin:--BREAK--ogin: real_account
+.br
+\fIetc ...\fR
+.LP
+.SH TIMEOUT
+The initial timeout value is 45 seconds. This may be changed using the \fB-t\fR
+parameter.
+.LP
+To change the timeout value for the next expect string, the following
+example may be used:
+.IP
+ATZ OK ATDT5551212 CONNECT TIMEOUT 10 ogin:--ogin: TIMEOUT 5 assword: hello2u2
+.LP
+This will change the timeout to 10 seconds when it expects the login:
+prompt. The timeout is then changed to 5 seconds when it looks for the
+password prompt.
+.LP
+The timeout, once changed, remains in effect until it is changed again.
+.SH SENDING EOT
+The special reply string of \fIEOT\fR indicates that the chat program
+should send an EOT character to the remote. This is normally the
+End-of-file character sequence. A return character is not sent
+following the EOT.
+.PR
+The EOT sequence may be embedded into the send string using the
+sequence \fI^D\fR.
+.SH GENERATING BREAK
+The special reply string of \fIBREAK\fR will cause a break condition
+to be sent. The break is a special signal on the transmitter. The
+normal processing on the receiver is to change the transmission rate.
+It may be used to cycle through the available transmission rates on
+the remote until you are able to receive a valid login prompt.
+.PR
+The break sequence may be embedded into the send string using the
+\fI\\K\fR sequence.
+.SH ESCAPE SEQUENCES
+The expect and reply strings may contain escape sequences. All of the
+sequences are legal in the reply string. Many are legal in the expect.
+Those which are not valid in the expect sequence are so indicated.
+.TP
+.B ''
+Expects or sends a null string. If you send a null string then it will still
+send the return character. This sequence may either be a pair of apostrophe
+or quote characters.
+.TP
+.B \\\\b
+represents a backspace character.
+.TP
+.B \\\\c
+Suppresses the newline at the end of the reply string. This is the only
+method to send a string without a trailing return character. It must
+be at the end of the send string. For example,
+the sequence hello\\c will simply send the characters h, e, l, l, o.
+.I (not valid in expect.)
+.TP
+.B \\\\d
+Delay for one second. The program uses sleep(1) which will delay to a
+maximum of one second.
+.I (not valid in expect.)
+.TP
+.B \\\\K
+Insert a BREAK
+.I (not valid in expect.)
+.TP
+.B \\\\n
+Send a newline or linefeed character.
+.TP
+.B \\\\N
+Send a null character. The same sequence may be represented by \\0.
+.I (not valid in expect.)
+.TP
+.B \\\\p
+Pause for a fraction of a second. The delay is 1/10th of a second.
+.I (not valid in expect.)
+.TP
+.B \\\\q
+Suppress writing the string to the SYSLOG file. The string ?????? is
+written to the log in its place.
+.I (not valid in expect.)
+.TP
+.B \\\\r
+Send or expect a carriage return.
+.TP
+.B \\\\s
+Represents a space character in the string. This may be used when it
+is not desirable to quote the strings which contains spaces. The
+sequence 'HI TIM' and HI\\sTIM are the same.
+.TP
+.B \\\\t
+Send or expect a tab character.
+.TP
+.B \\\\T
+Send the phone number string as specified with the \fI-T\fR option
+.I (not valid in expect.)
+.TP
+.B \\\\U
+Send the phone number 2 string as specified with the \fI-U\fR option
+.I (not valid in expect.)
+.TP
+.B \\\\\\\\
+Send or expect a backslash character.
+.TP
+.B \\\\ddd
+Collapse the octal digits (ddd) into a single ASCII character and send that
+character.
+.I (some characters are not valid in expect.)
+.TP
+.B \^^C
+Substitute the sequence with the control character represented by C.
+For example, the character DC1 (17) is shown as \^^Q.
+.I (some characters are not valid in expect.)
+.SH ENVIRONMENT VARIABLES
+Environment variables are available within chat scripts, if the \fI-E\fR
+option was specified in the command line. The metacharacter \fI$\fR is used
+to introduce the name of the environment variable to substitute. If the
+substition fails, because the requested environment variable is not set,
+\fInothing\fR is replaced for the variable.
+.SH TERMINATION CODES
+The \fIchat\fR program will terminate with the following completion
+codes.
+.TP
+.B 0
+The normal termination of the program. This indicates that the script
+was executed without error to the normal conclusion.
+.TP
+.B 1
+One or more of the parameters are invalid or an expect string was too
+large for the internal buffers. This indicates that the program as not
+properly executed.
+.TP
+.B 2
+An error occurred during the execution of the program. This may be due
+to a read or write operation failing for some reason or chat receiving
+a signal such as SIGINT.
+.TP
+.B 3
+A timeout event occurred when there was an \fIexpect\fR string without
+having a "-subsend" string. This may mean that you did not program the
+script correctly for the condition or that some unexpected event has
+occurred and the expected string could not be found.
+.TP
+.B 4
+The first string marked as an \fIABORT\fR condition occurred.
+.TP
+.B 5
+The second string marked as an \fIABORT\fR condition occurred.
+.TP
+.B 6
+The third string marked as an \fIABORT\fR condition occurred.
+.TP
+.B 7
+The fourth string marked as an \fIABORT\fR condition occurred.
+.TP
+.B ...
+The other termination codes are also strings marked as an \fIABORT\fR
+condition.
+.LP
+Using the termination code, it is possible to determine which event
+terminated the script. It is possible to decide if the string "BUSY"
+was received from the modem as opposed to "NO DIAL TONE". While the
+first event may be retried, the second will probably have little
+chance of succeeding during a retry.
+.SH SEE ALSO
+Additional information about \fIchat\fR scripts may be found with UUCP
+documentation. The \fIchat\fR script was taken from the ideas proposed
+by the scripts used by the \fIuucico\fR program.
+.LP
+uucico(1), uucp(1)
+.SH COPYRIGHT
+The \fIchat\fR program is in public domain. This is not the GNU public
+license. If it breaks then you get to keep both pieces.
diff --git a/mdk-stage1/ppp/chat/chat.c b/mdk-stage1/ppp/chat/chat.c
new file mode 100644
index 000000000..6c4a8487b
--- /dev/null
+++ b/mdk-stage1/ppp/chat/chat.c
@@ -0,0 +1,1756 @@
+/*
+ * Chat -- a program for automatic session establishment (i.e. dial
+ * the phone and log in).
+ *
+ * Standard termination codes:
+ * 0 - successful completion of the script
+ * 1 - invalid argument, expect string too large, etc.
+ * 2 - error on an I/O operation or fatal error condition.
+ * 3 - timeout waiting for a simple string.
+ * 4 - the first string declared as "ABORT"
+ * 5 - the second string declared as "ABORT"
+ * 6 - ... and so on for successive ABORT strings.
+ *
+ * This software is in the public domain.
+ *
+ * -----------------
+ * 22-May-99 added environment substitutuion, enabled with -E switch.
+ * Andreas Arens <andras@cityweb.de>.
+ *
+ * 12-May-99 added a feature to read data to be sent from a file,
+ * if the send string starts with @. Idea from gpk <gpk@onramp.net>.
+ *
+ * added -T and -U option and \T and \U substitution to pass a phone
+ * number into chat script. Two are needed for some ISDN TA applications.
+ * Keith Dart <kdart@cisco.com>
+ *
+ *
+ * Added SAY keyword to send output to stderr.
+ * This allows to turn ECHO OFF and to output specific, user selected,
+ * text to give progress messages. This best works when stderr
+ * exists (i.e.: pppd in nodetach mode).
+ *
+ * Added HANGUP directives to allow for us to be called
+ * back. When HANGUP is set to NO, chat will not hangup at HUP signal.
+ * We rely on timeouts in that case.
+ *
+ * Added CLR_ABORT to clear previously set ABORT string. This has been
+ * dictated by the HANGUP above as "NO CARRIER" (for example) must be
+ * an ABORT condition until we know the other host is going to close
+ * the connection for call back. As soon as we have completed the
+ * first stage of the call back sequence, "NO CARRIER" is a valid, non
+ * fatal string. As soon as we got called back (probably get "CONNECT"),
+ * we should re-arm the ABORT "NO CARRIER". Hence the CLR_ABORT command.
+ * Note that CLR_ABORT packs the abort_strings[] array so that we do not
+ * have unused entries not being reclaimed.
+ *
+ * In the same vein as above, added CLR_REPORT keyword.
+ *
+ * Allow for comments. Line starting with '#' are comments and are
+ * ignored. If a '#' is to be expected as the first character, the
+ * expect string must be quoted.
+ *
+ *
+ * Francis Demierre <Francis@SwissMail.Com>
+ * Thu May 15 17:15:40 MET DST 1997
+ *
+ *
+ * Added -r "report file" switch & REPORT keyword.
+ * Robert Geer <bgeer@xmission.com>
+ *
+ * Added -s "use stderr" and -S "don't use syslog" switches.
+ * June 18, 1997
+ * Karl O. Pinc <kop@meme.com>
+ *
+ *
+ * Added -e "echo" switch & ECHO keyword
+ * Dick Streefland <dicks@tasking.nl>
+ *
+ *
+ * Considerable updates and modifications by
+ * Al Longyear <longyear@pobox.com>
+ * Paul Mackerras <paulus@cs.anu.edu.au>
+ *
+ *
+ * The original author is:
+ *
+ * Karl Fox <karl@MorningStar.Com>
+ * Morning Star Technologies, Inc.
+ * 1760 Zollinger Road
+ * Columbus, OH 43221
+ * (614)451-1883
+ *
+ */
+
+#ifndef __STDC__
+#define const
+#endif
+
+#ifndef lint
+static const char rcsid[] = "$Id: chat.c 195720 2001-06-11 11:44:34Z gc $";
+#endif
+
+#include <stdio.h>
+#include <ctype.h>
+#include <time.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <syslog.h>
+
+#ifndef TERMIO
+#undef TERMIOS
+#define TERMIOS
+#endif
+
+#ifdef TERMIO
+#include <termio.h>
+#endif
+#ifdef TERMIOS
+#include <termios.h>
+#endif
+
+#define STR_LEN 1024
+
+#ifndef SIGTYPE
+#define SIGTYPE void
+#endif
+
+#undef __P
+#undef __V
+
+#ifdef __STDC__
+#include <stdarg.h>
+#define __V(x) x
+#define __P(x) x
+#else
+#include <varargs.h>
+#define __V(x) (va_alist) va_dcl
+#define __P(x) ()
+#define const
+#endif
+
+#ifndef O_NONBLOCK
+#define O_NONBLOCK O_NDELAY
+#endif
+
+#ifdef SUNOS
+extern int sys_nerr;
+extern char *sys_errlist[];
+#define memmove(to, from, n) bcopy(from, to, n)
+#define strerror(n) ((unsigned)(n) < sys_nerr? sys_errlist[(n)] :\
+ "unknown error")
+#endif
+
+/*************** Micro getopt() *********************************************/
+#define OPTION(c,v) (_O&2&&**v?*(*v)++:!c||_O&4?0:(!(_O&1)&& \
+ (--c,++v),_O=4,c&&**v=='-'&&v[0][1]?*++*v=='-'\
+ &&!v[0][1]?(--c,++v,0):(_O=2,*(*v)++):0))
+#define OPTARG(c,v) (_O&2?**v||(++v,--c)?(_O=1,--c,*v++): \
+ (_O=4,(char*)0):(char*)0)
+#define OPTONLYARG(c,v) (_O&2&&**v?(_O=1,--c,*v++):(char*)0)
+#define ARG(c,v) (c?(--c,*v++):(char*)0)
+
+static int _O = 0; /* Internal state */
+/*************** Micro getopt() *********************************************/
+
+char *program_name;
+
+#define MAX_ABORTS 50
+#define MAX_REPORTS 50
+#define DEFAULT_CHAT_TIMEOUT 45
+
+int echo = 0;
+int verbose = 0;
+int to_log = 1;
+int to_stderr = 0;
+int Verbose = 0;
+int quiet = 0;
+int report = 0;
+int use_env = 0;
+int exit_code = 0;
+FILE* report_fp = (FILE *) 0;
+char *report_file = (char *) 0;
+char *chat_file = (char *) 0;
+char *phone_num = (char *) 0;
+char *phone_num2 = (char *) 0;
+int timeout = DEFAULT_CHAT_TIMEOUT;
+
+int have_tty_parameters = 0;
+
+#ifdef TERMIO
+#define term_parms struct termio
+#define get_term_param(param) ioctl(0, TCGETA, param)
+#define set_term_param(param) ioctl(0, TCSETA, param)
+struct termio saved_tty_parameters;
+#endif
+
+#ifdef TERMIOS
+#define term_parms struct termios
+#define get_term_param(param) tcgetattr(0, param)
+#define set_term_param(param) tcsetattr(0, TCSANOW, param)
+struct termios saved_tty_parameters;
+#endif
+
+char *abort_string[MAX_ABORTS], *fail_reason = (char *)0,
+ fail_buffer[50];
+int n_aborts = 0, abort_next = 0, timeout_next = 0, echo_next = 0;
+int clear_abort_next = 0;
+
+char *report_string[MAX_REPORTS] ;
+char report_buffer[50] ;
+int n_reports = 0, report_next = 0, report_gathering = 0 ;
+int clear_report_next = 0;
+
+int say_next = 0, hup_next = 0;
+
+void *dup_mem __P((void *b, size_t c));
+void *copy_of __P((char *s));
+void usage __P((void));
+void logf __P((const char *fmt, ...));
+void fatal __P((int code, const char *fmt, ...));
+SIGTYPE sigalrm __P((int signo));
+SIGTYPE sigint __P((int signo));
+SIGTYPE sigterm __P((int signo));
+SIGTYPE sighup __P((int signo));
+void unalarm __P((void));
+void init __P((void));
+void set_tty_parameters __P((void));
+void echo_stderr __P((int));
+void break_sequence __P((void));
+void terminate __P((int status));
+void do_file __P((char *chat_file));
+int get_string __P((register char *string));
+int put_string __P((register char *s));
+int write_char __P((int c));
+int put_char __P((int c));
+int get_char __P((void));
+void chat_send __P((register char *s));
+char *character __P((int c));
+void chat_expect __P((register char *s));
+char *clean __P((register char *s, int sending));
+void break_sequence __P((void));
+void terminate __P((int status));
+void pack_array __P((char **array, int end));
+char *expect_strtok __P((char *, char *));
+int vfmtmsg __P((char *, int, const char *, va_list)); /* vsprintf++ */
+
+int main __P((int, char *[]));
+
+void *dup_mem(b, c)
+void *b;
+size_t c;
+{
+ void *ans = malloc (c);
+ if (!ans)
+ fatal(2, "memory error!");
+
+ memcpy (ans, b, c);
+ return ans;
+}
+
+void *copy_of (s)
+char *s;
+{
+ return dup_mem (s, strlen (s) + 1);
+}
+
+/*
+ * chat [ -v ] [ -E ] [ -T number ] [ -U number ] [ -t timeout ] [ -f chat-file ] \
+ * [ -r report-file ] \
+ * [...[[expect[-say[-expect...]] say expect[-say[-expect]] ...]]]
+ *
+ * Perform a UUCP-dialer-like chat script on stdin and stdout.
+ */
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ int option;
+ char *arg;
+
+ program_name = *argv;
+ tzset();
+
+ while ((option = OPTION(argc, argv)) != 0) {
+ switch (option) {
+ case 'e':
+ ++echo;
+ break;
+
+ case 'E':
+ ++use_env;
+ break;
+
+ case 'v':
+ ++verbose;
+ break;
+
+ case 'V':
+ ++Verbose;
+ break;
+
+ case 's':
+ ++to_stderr;
+ break;
+
+ case 'S':
+ to_log = 0;
+ break;
+
+ case 'f':
+ if ((arg = OPTARG(argc, argv)) != NULL)
+ chat_file = copy_of(arg);
+ else
+ usage();
+ break;
+
+ case 't':
+ if ((arg = OPTARG(argc, argv)) != NULL)
+ timeout = atoi(arg);
+ else
+ usage();
+ break;
+
+ case 'r':
+ arg = OPTARG (argc, argv);
+ if (arg) {
+ if (report_fp != NULL)
+ fclose (report_fp);
+ report_file = copy_of (arg);
+ report_fp = fopen (report_file, "a");
+ if (report_fp != NULL) {
+ if (verbose)
+ fprintf (report_fp, "Opening \"%s\"...\n",
+ report_file);
+ report = 1;
+ }
+ }
+ break;
+
+ case 'T':
+ if ((arg = OPTARG(argc, argv)) != NULL)
+ phone_num = copy_of(arg);
+ else
+ usage();
+ break;
+
+ case 'U':
+ if ((arg = OPTARG(argc, argv)) != NULL)
+ phone_num2 = copy_of(arg);
+ else
+ usage();
+ break;
+
+ default:
+ usage();
+ break;
+ }
+ }
+/*
+ * Default the report file to the stderr location
+ */
+ if (report_fp == NULL)
+ report_fp = stderr;
+
+ if (to_log) {
+#ifdef ultrix
+ openlog("chat", LOG_PID);
+#else
+ openlog("chat", LOG_PID | LOG_NDELAY, LOG_LOCAL2);
+
+ if (verbose)
+ setlogmask(LOG_UPTO(LOG_INFO));
+ else
+ setlogmask(LOG_UPTO(LOG_WARNING));
+#endif
+ }
+
+ init();
+
+ if (chat_file != NULL) {
+ arg = ARG(argc, argv);
+ if (arg != NULL)
+ usage();
+ else
+ do_file (chat_file);
+ } else {
+ while ((arg = ARG(argc, argv)) != NULL) {
+ chat_expect(arg);
+
+ if ((arg = ARG(argc, argv)) != NULL)
+ chat_send(arg);
+ }
+ }
+
+ terminate(0);
+ return 0;
+}
+
+/*
+ * Process a chat script when read from a file.
+ */
+
+void do_file (chat_file)
+char *chat_file;
+{
+ int linect, sendflg;
+ char *sp, *arg, quote;
+ char buf [STR_LEN];
+ FILE *cfp;
+
+ cfp = fopen (chat_file, "r");
+ if (cfp == NULL)
+ fatal(1, "%s -- open failed: %m", chat_file);
+
+ linect = 0;
+ sendflg = 0;
+
+ while (fgets(buf, STR_LEN, cfp) != NULL) {
+ sp = strchr (buf, '\n');
+ if (sp)
+ *sp = '\0';
+
+ linect++;
+ sp = buf;
+
+ /* lines starting with '#' are comments. If a real '#'
+ is to be expected, it should be quoted .... */
+ if ( *sp == '#' )
+ continue;
+
+ while (*sp != '\0') {
+ if (*sp == ' ' || *sp == '\t') {
+ ++sp;
+ continue;
+ }
+
+ if (*sp == '"' || *sp == '\'') {
+ quote = *sp++;
+ arg = sp;
+ while (*sp != quote) {
+ if (*sp == '\0')
+ fatal(1, "unterminated quote (line %d)", linect);
+
+ if (*sp++ == '\\') {
+ if (*sp != '\0')
+ ++sp;
+ }
+ }
+ }
+ else {
+ arg = sp;
+ while (*sp != '\0' && *sp != ' ' && *sp != '\t')
+ ++sp;
+ }
+
+ if (*sp != '\0')
+ *sp++ = '\0';
+
+ if (sendflg)
+ chat_send (arg);
+ else
+ chat_expect (arg);
+ sendflg = !sendflg;
+ }
+ }
+ fclose (cfp);
+}
+
+/*
+ * We got an error parsing the command line.
+ */
+void usage()
+{
+ fprintf(stderr, "\
+Usage: %s [-e] [-E] [-v] [-V] [-t timeout] [-r report-file]\n\
+ [-T phone-number] [-U phone-number2] {-f chat-file | chat-script}\n", program_name);
+ exit(1);
+}
+
+char line[1024];
+
+/*
+ * Send a message to syslog and/or stderr.
+ */
+void logf __V((const char *fmt, ...))
+{
+ va_list args;
+
+#ifdef __STDC__
+ va_start(args, fmt);
+#else
+ char *fmt;
+ va_start(args);
+ fmt = va_arg(args, char *);
+#endif
+
+ vfmtmsg(line, sizeof(line), fmt, args);
+ if (to_log)
+ syslog(LOG_INFO, "%s", line);
+ if (to_stderr)
+ fprintf(stderr, "%s\n", line);
+}
+
+/*
+ * Print an error message and terminate.
+ */
+
+void fatal __V((int code, const char *fmt, ...))
+{
+ va_list args;
+
+#ifdef __STDC__
+ va_start(args, fmt);
+#else
+ int code;
+ char *fmt;
+ va_start(args);
+ code = va_arg(args, int);
+ fmt = va_arg(args, char *);
+#endif
+
+ vfmtmsg(line, sizeof(line), fmt, args);
+ if (to_log)
+ syslog(LOG_ERR, "%s", line);
+ if (to_stderr)
+ fprintf(stderr, "%s\n", line);
+ terminate(code);
+}
+
+int alarmed = 0;
+
+SIGTYPE sigalrm(signo)
+int signo;
+{
+ int flags;
+
+ alarm(1);
+ alarmed = 1; /* Reset alarm to avoid race window */
+ signal(SIGALRM, sigalrm); /* that can cause hanging in read() */
+
+ if ((flags = fcntl(0, F_GETFL, 0)) == -1)
+ fatal(2, "Can't get file mode flags on stdin: %m");
+
+ if (fcntl(0, F_SETFL, flags | O_NONBLOCK) == -1)
+ fatal(2, "Can't set file mode flags on stdin: %m");
+
+ if (verbose)
+ logf("alarm");
+}
+
+void unalarm()
+{
+ int flags;
+
+ if ((flags = fcntl(0, F_GETFL, 0)) == -1)
+ fatal(2, "Can't get file mode flags on stdin: %m");
+
+ if (fcntl(0, F_SETFL, flags & ~O_NONBLOCK) == -1)
+ fatal(2, "Can't set file mode flags on stdin: %m");
+}
+
+SIGTYPE sigint(signo)
+int signo;
+{
+ fatal(2, "SIGINT");
+}
+
+SIGTYPE sigterm(signo)
+int signo;
+{
+ fatal(2, "SIGTERM");
+}
+
+SIGTYPE sighup(signo)
+int signo;
+{
+ fatal(2, "SIGHUP");
+}
+
+void init()
+{
+ signal(SIGINT, sigint);
+ signal(SIGTERM, sigterm);
+ signal(SIGHUP, sighup);
+
+ set_tty_parameters();
+ signal(SIGALRM, sigalrm);
+ alarm(0);
+ alarmed = 0;
+}
+
+void set_tty_parameters()
+{
+#if defined(get_term_param)
+ term_parms t;
+
+ if (get_term_param (&t) < 0)
+ fatal(2, "Can't get terminal parameters: %m");
+
+ saved_tty_parameters = t;
+ have_tty_parameters = 1;
+
+ t.c_iflag |= IGNBRK | ISTRIP | IGNPAR;
+ t.c_oflag = 0;
+ t.c_lflag = 0;
+ t.c_cc[VERASE] =
+ t.c_cc[VKILL] = 0;
+ t.c_cc[VMIN] = 1;
+ t.c_cc[VTIME] = 0;
+
+ if (set_term_param (&t) < 0)
+ fatal(2, "Can't set terminal parameters: %m");
+#endif
+}
+
+void break_sequence()
+{
+#ifdef TERMIOS
+ tcsendbreak (0, 0);
+#endif
+}
+
+void terminate(status)
+int status;
+{
+ static int terminating = 0;
+
+ if (terminating)
+ exit(status);
+ terminating = 1;
+ echo_stderr(-1);
+/*
+ * Allow the last of the report string to be gathered before we terminate.
+ */
+ if (report_gathering) {
+ int c, rep_len;
+
+ rep_len = strlen(report_buffer);
+ while (rep_len + 1 <= sizeof(report_buffer)) {
+ alarm(1);
+ c = get_char();
+ alarm(0);
+ if (c < 0 || iscntrl(c))
+ break;
+ report_buffer[rep_len] = c;
+ ++rep_len;
+ }
+ report_buffer[rep_len] = 0;
+ fprintf (report_fp, "chat: %s\n", report_buffer);
+ }
+ if (report_file != (char *) 0 && report_fp != (FILE *) NULL) {
+ if (verbose)
+ fprintf (report_fp, "Closing \"%s\".\n", report_file);
+ fclose (report_fp);
+ report_fp = (FILE *) NULL;
+ }
+
+#if defined(get_term_param)
+ if (have_tty_parameters) {
+ if (set_term_param (&saved_tty_parameters) < 0)
+ fatal(2, "Can't restore terminal parameters: %m");
+ }
+#endif
+
+ exit(status);
+}
+
+/*
+ * 'Clean up' this string.
+ */
+char *clean(s, sending)
+register char *s;
+int sending; /* set to 1 when sending (putting) this string. */
+{
+ char temp[STR_LEN], env_str[STR_LEN], cur_chr;
+ register char *s1, *phchar;
+ int add_return = sending;
+#define isoctal(chr) (((chr) >= '0') && ((chr) <= '7'))
+#define isalnumx(chr) ((((chr) >= '0') && ((chr) <= '9')) \
+ || (((chr) >= 'a') && ((chr) <= 'z')) \
+ || (((chr) >= 'A') && ((chr) <= 'Z')) \
+ || (chr) == '_')
+
+ s1 = temp;
+ while (*s) {
+ cur_chr = *s++;
+ if (cur_chr == '^') {
+ cur_chr = *s++;
+ if (cur_chr == '\0') {
+ *s1++ = '^';
+ break;
+ }
+ cur_chr &= 0x1F;
+ if (cur_chr != 0) {
+ *s1++ = cur_chr;
+ }
+ continue;
+ }
+
+ if (use_env && cur_chr == '$') { /* ARI */
+ phchar = env_str;
+ while (isalnumx(*s))
+ *phchar++ = *s++;
+ *phchar = '\0';
+ phchar = getenv(env_str);
+ if (phchar)
+ while (*phchar)
+ *s1++ = *phchar++;
+ continue;
+ }
+
+ if (cur_chr != '\\') {
+ *s1++ = cur_chr;
+ continue;
+ }
+
+ cur_chr = *s++;
+ if (cur_chr == '\0') {
+ if (sending) {
+ *s1++ = '\\';
+ *s1++ = '\\';
+ }
+ break;
+ }
+
+ switch (cur_chr) {
+ case 'b':
+ *s1++ = '\b';
+ break;
+
+ case 'c':
+ if (sending && *s == '\0')
+ add_return = 0;
+ else
+ *s1++ = cur_chr;
+ break;
+
+ case '\\':
+ case 'K':
+ case 'p':
+ case 'd':
+ if (sending)
+ *s1++ = '\\';
+ *s1++ = cur_chr;
+ break;
+
+ case 'T':
+ if (sending && phone_num) {
+ for (phchar = phone_num; *phchar != '\0'; phchar++)
+ *s1++ = *phchar;
+ }
+ else {
+ *s1++ = '\\';
+ *s1++ = 'T';
+ }
+ break;
+
+ case 'U':
+ if (sending && phone_num2) {
+ for (phchar = phone_num2; *phchar != '\0'; phchar++)
+ *s1++ = *phchar;
+ }
+ else {
+ *s1++ = '\\';
+ *s1++ = 'U';
+ }
+ break;
+
+ case 'q':
+ quiet = 1;
+ break;
+
+ case 'r':
+ *s1++ = '\r';
+ break;
+
+ case 'n':
+ *s1++ = '\n';
+ break;
+
+ case 's':
+ *s1++ = ' ';
+ break;
+
+ case 't':
+ *s1++ = '\t';
+ break;
+
+ case 'N':
+ if (sending) {
+ *s1++ = '\\';
+ *s1++ = '\0';
+ }
+ else
+ *s1++ = 'N';
+ break;
+
+ case '$': /* ARI */
+ if (use_env) {
+ *s1++ = cur_chr;
+ break;
+ }
+ /* FALL THROUGH */
+
+ default:
+ if (isoctal (cur_chr)) {
+ cur_chr &= 0x07;
+ if (isoctal (*s)) {
+ cur_chr <<= 3;
+ cur_chr |= *s++ - '0';
+ if (isoctal (*s)) {
+ cur_chr <<= 3;
+ cur_chr |= *s++ - '0';
+ }
+ }
+
+ if (cur_chr != 0 || sending) {
+ if (sending && (cur_chr == '\\' || cur_chr == 0))
+ *s1++ = '\\';
+ *s1++ = cur_chr;
+ }
+ break;
+ }
+
+ if (sending)
+ *s1++ = '\\';
+ *s1++ = cur_chr;
+ break;
+ }
+ }
+
+ if (add_return)
+ *s1++ = '\r';
+
+ *s1++ = '\0'; /* guarantee closure */
+ *s1++ = '\0'; /* terminate the string */
+ return dup_mem (temp, (size_t) (s1 - temp)); /* may have embedded nuls */
+}
+
+/*
+ * A modified version of 'strtok'. This version skips \ sequences.
+ */
+
+char *expect_strtok (s, term)
+ char *s, *term;
+{
+ static char *str = "";
+ int escape_flag = 0;
+ char *result;
+
+/*
+ * If a string was specified then do initial processing.
+ */
+ if (s)
+ str = s;
+
+/*
+ * If this is the escape flag then reset it and ignore the character.
+ */
+ if (*str)
+ result = str;
+ else
+ result = (char *) 0;
+
+ while (*str) {
+ if (escape_flag) {
+ escape_flag = 0;
+ ++str;
+ continue;
+ }
+
+ if (*str == '\\') {
+ ++str;
+ escape_flag = 1;
+ continue;
+ }
+
+/*
+ * If this is not in the termination string, continue.
+ */
+ if (strchr (term, *str) == (char *) 0) {
+ ++str;
+ continue;
+ }
+
+/*
+ * This is the terminator. Mark the end of the string and stop.
+ */
+ *str++ = '\0';
+ break;
+ }
+ return (result);
+}
+
+/*
+ * Process the expect string
+ */
+
+void chat_expect (s)
+char *s;
+{
+ char *expect;
+ char *reply;
+
+ if (strcmp(s, "HANGUP") == 0) {
+ ++hup_next;
+ return;
+ }
+
+ if (strcmp(s, "ABORT") == 0) {
+ ++abort_next;
+ return;
+ }
+
+ if (strcmp(s, "CLR_ABORT") == 0) {
+ ++clear_abort_next;
+ return;
+ }
+
+ if (strcmp(s, "REPORT") == 0) {
+ ++report_next;
+ return;
+ }
+
+ if (strcmp(s, "CLR_REPORT") == 0) {
+ ++clear_report_next;
+ return;
+ }
+
+ if (strcmp(s, "TIMEOUT") == 0) {
+ ++timeout_next;
+ return;
+ }
+
+ if (strcmp(s, "ECHO") == 0) {
+ ++echo_next;
+ return;
+ }
+
+ if (strcmp(s, "SAY") == 0) {
+ ++say_next;
+ return;
+ }
+
+/*
+ * Fetch the expect and reply string.
+ */
+ for (;;) {
+ expect = expect_strtok (s, "-");
+ s = (char *) 0;
+
+ if (expect == (char *) 0)
+ return;
+
+ reply = expect_strtok (s, "-");
+
+/*
+ * Handle the expect string. If successful then exit.
+ */
+ if (get_string (expect))
+ return;
+
+/*
+ * If there is a sub-reply string then send it. Otherwise any condition
+ * is terminal.
+ */
+ if (reply == (char *) 0 || exit_code != 3)
+ break;
+
+ chat_send (reply);
+ }
+
+/*
+ * The expectation did not occur. This is terminal.
+ */
+ if (fail_reason)
+ logf("Failed (%s)", fail_reason);
+ else
+ logf("Failed");
+ terminate(exit_code);
+}
+
+/*
+ * Translate the input character to the appropriate string for printing
+ * the data.
+ */
+
+char *character(c)
+int c;
+{
+ static char string[10];
+ char *meta;
+
+ meta = (c & 0x80) ? "M-" : "";
+ c &= 0x7F;
+
+ if (c < 32)
+ sprintf(string, "%s^%c", meta, (int)c + '@');
+ else if (c == 127)
+ sprintf(string, "%s^?", meta);
+ else
+ sprintf(string, "%s%c", meta, c);
+
+ return (string);
+}
+
+/*
+ * process the reply string
+ */
+void chat_send (s)
+register char *s;
+{
+ char file_data[STR_LEN];
+
+ if (say_next) {
+ say_next = 0;
+ s = clean(s, 1);
+ write(2, s, strlen(s));
+ free(s);
+ return;
+ }
+
+ if (hup_next) {
+ hup_next = 0;
+ if (strcmp(s, "OFF") == 0)
+ signal(SIGHUP, SIG_IGN);
+ else
+ signal(SIGHUP, sighup);
+ return;
+ }
+
+ if (echo_next) {
+ echo_next = 0;
+ echo = (strcmp(s, "ON") == 0);
+ return;
+ }
+
+ if (abort_next) {
+ char *s1;
+
+ abort_next = 0;
+
+ if (n_aborts >= MAX_ABORTS)
+ fatal(2, "Too many ABORT strings");
+
+ s1 = clean(s, 0);
+
+ if (strlen(s1) > strlen(s)
+ || strlen(s1) + 1 > sizeof(fail_buffer))
+ fatal(1, "Illegal or too-long ABORT string ('%v')", s);
+
+ abort_string[n_aborts++] = s1;
+
+ if (verbose)
+ logf("abort on (%v)", s);
+ return;
+ }
+
+ if (clear_abort_next) {
+ char *s1;
+ int i;
+ int old_max;
+ int pack = 0;
+
+ clear_abort_next = 0;
+
+ s1 = clean(s, 0);
+
+ if (strlen(s1) > strlen(s)
+ || strlen(s1) + 1 > sizeof(fail_buffer))
+ fatal(1, "Illegal or too-long CLR_ABORT string ('%v')", s);
+
+ old_max = n_aborts;
+ for (i=0; i < n_aborts; i++) {
+ if ( strcmp(s1,abort_string[i]) == 0 ) {
+ free(abort_string[i]);
+ abort_string[i] = NULL;
+ pack++;
+ n_aborts--;
+ if (verbose)
+ logf("clear abort on (%v)", s);
+ }
+ }
+ free(s1);
+ if (pack)
+ pack_array(abort_string,old_max);
+ return;
+ }
+
+ if (report_next) {
+ char *s1;
+
+ report_next = 0;
+ if (n_reports >= MAX_REPORTS)
+ fatal(2, "Too many REPORT strings");
+
+ s1 = clean(s, 0);
+
+ if (strlen(s1) > strlen(s) || strlen(s1) > sizeof fail_buffer - 1)
+ fatal(1, "Illegal or too-long REPORT string ('%v')", s);
+
+ report_string[n_reports++] = s1;
+
+ if (verbose)
+ logf("report (%v)", s);
+ return;
+ }
+
+ if (clear_report_next) {
+ char *s1;
+ int i;
+ int old_max;
+ int pack = 0;
+
+ clear_report_next = 0;
+
+ s1 = clean(s, 0);
+
+ if (strlen(s1) > strlen(s) || strlen(s1) > sizeof fail_buffer - 1)
+ fatal(1, "Illegal or too-long REPORT string ('%v')", s);
+
+ old_max = n_reports;
+ for (i=0; i < n_reports; i++) {
+ if ( strcmp(s1,report_string[i]) == 0 ) {
+ free(report_string[i]);
+ report_string[i] = NULL;
+ pack++;
+ n_reports--;
+ if (verbose)
+ logf("clear report (%v)", s);
+ }
+ }
+ free(s1);
+ if (pack)
+ pack_array(report_string,old_max);
+
+ return;
+ }
+
+ if (timeout_next) {
+ timeout_next = 0;
+ timeout = atoi(s);
+
+ if (timeout <= 0)
+ timeout = DEFAULT_CHAT_TIMEOUT;
+
+ if (verbose)
+ logf("timeout set to %d seconds", timeout);
+
+ return;
+ }
+
+ /*
+ * The syntax @filename means read the string to send from the
+ * file `filename'.
+ */
+ if (s[0] == '@') {
+ /* skip the @ and any following white-space */
+ char *fn = s;
+ while (*++fn == ' ' || *fn == '\t')
+ ;
+
+ if (*fn != 0) {
+ FILE *f;
+ int n = 0;
+
+ /* open the file and read until STR_LEN-1 bytes or end-of-file */
+ f = fopen(fn, "r");
+ if (f == NULL)
+ fatal(1, "%s -- open failed: %m", fn);
+ while (n < STR_LEN - 1) {
+ int nr = fread(&file_data[n], 1, STR_LEN - 1 - n, f);
+ if (nr < 0)
+ fatal(1, "%s -- read error", fn);
+ if (nr == 0)
+ break;
+ n += nr;
+ }
+ fclose(f);
+
+ /* use the string we got as the string to send,
+ but trim off the final newline if any. */
+ if (n > 0 && file_data[n-1] == '\n')
+ --n;
+ file_data[n] = 0;
+ s = file_data;
+ }
+ }
+
+ if (strcmp(s, "EOT") == 0)
+ s = "^D\\c";
+ else if (strcmp(s, "BREAK") == 0)
+ s = "\\K\\c";
+
+ if (!put_string(s))
+ fatal(1, "Failed");
+}
+
+int get_char()
+{
+ int status;
+ char c;
+
+ status = read(0, &c, 1);
+
+ switch (status) {
+ case 1:
+ return ((int)c & 0x7F);
+
+ default:
+ logf("warning: read() on stdin returned %d", status);
+
+ case -1:
+ if ((status = fcntl(0, F_GETFL, 0)) == -1)
+ fatal(2, "Can't get file mode flags on stdin: %m");
+
+ if (fcntl(0, F_SETFL, status & ~O_NONBLOCK) == -1)
+ fatal(2, "Can't set file mode flags on stdin: %m");
+
+ return (-1);
+ }
+}
+
+int put_char(c)
+int c;
+{
+ int status;
+ char ch = c;
+
+ usleep(10000); /* inter-character typing delay (?) */
+
+ status = write(1, &ch, 1);
+
+ switch (status) {
+ case 1:
+ return (0);
+
+ default:
+ logf("warning: write() on stdout returned %d", status);
+
+ case -1:
+ if ((status = fcntl(0, F_GETFL, 0)) == -1)
+ fatal(2, "Can't get file mode flags on stdin, %m");
+
+ if (fcntl(0, F_SETFL, status & ~O_NONBLOCK) == -1)
+ fatal(2, "Can't set file mode flags on stdin: %m");
+
+ return (-1);
+ }
+}
+
+int write_char (c)
+int c;
+{
+ if (alarmed || put_char(c) < 0) {
+ alarm(0);
+ alarmed = 0;
+
+ if (verbose) {
+ if (errno == EINTR || errno == EWOULDBLOCK)
+ logf(" -- write timed out");
+ else
+ logf(" -- write failed: %m");
+ }
+ return (0);
+ }
+ return (1);
+}
+
+int put_string (s)
+register char *s;
+{
+ quiet = 0;
+ s = clean(s, 1);
+
+ if (verbose) {
+ if (quiet)
+ logf("send (??????)");
+ else
+ logf("send (%v)", s);
+ }
+
+ alarm(timeout); alarmed = 0;
+
+ while (*s) {
+ register char c = *s++;
+
+ if (c != '\\') {
+ if (!write_char (c))
+ return 0;
+ continue;
+ }
+
+ c = *s++;
+ switch (c) {
+ case 'd':
+ sleep(1);
+ break;
+
+ case 'K':
+ break_sequence();
+ break;
+
+ case 'p':
+ usleep(10000); /* 1/100th of a second (arg is microseconds) */
+ break;
+
+ default:
+ if (!write_char (c))
+ return 0;
+ break;
+ }
+ }
+
+ alarm(0);
+ alarmed = 0;
+ return (1);
+}
+
+/*
+ * Echo a character to stderr.
+ * When called with -1, a '\n' character is generated when
+ * the cursor is not at the beginning of a line.
+ */
+void echo_stderr(n)
+int n;
+{
+ static int need_lf;
+ char *s;
+
+ switch (n) {
+ case '\r': /* ignore '\r' */
+ break;
+ case -1:
+ if (need_lf == 0)
+ break;
+ /* fall through */
+ case '\n':
+ write(2, "\n", 1);
+ need_lf = 0;
+ break;
+ default:
+ s = character(n);
+ write(2, s, strlen(s));
+ need_lf = 1;
+ break;
+ }
+}
+
+/*
+ * 'Wait for' this string to appear on this file descriptor.
+ */
+int get_string(string)
+register char *string;
+{
+ char temp[STR_LEN];
+ int c, printed = 0, len, minlen;
+ register char *s = temp, *end = s + STR_LEN;
+ char *logged = temp;
+
+ fail_reason = (char *)0;
+ string = clean(string, 0);
+ len = strlen(string);
+ minlen = (len > sizeof(fail_buffer)? len: sizeof(fail_buffer)) - 1;
+
+ if (verbose)
+ logf("expect (%v)", string);
+
+ if (len > STR_LEN) {
+ logf("expect string is too long");
+ exit_code = 1;
+ return 0;
+ }
+
+ if (len == 0) {
+ if (verbose)
+ logf("got it");
+ return (1);
+ }
+
+ alarm(timeout);
+ alarmed = 0;
+
+ while ( ! alarmed && (c = get_char()) >= 0) {
+ int n, abort_len, report_len;
+
+ if (echo)
+ echo_stderr(c);
+ if (verbose && c == '\n') {
+ if (s == logged)
+ logf(""); /* blank line */
+ else
+ logf("%0.*v", s - logged, logged);
+ logged = s + 1;
+ }
+
+ *s++ = c;
+
+ if (verbose && s >= logged + 80) {
+ logf("%0.*v", s - logged, logged);
+ logged = s;
+ }
+
+ if (Verbose) {
+ if (c == '\n')
+ fputc( '\n', stderr );
+ else if (c != '\r')
+ fprintf( stderr, "%s", character(c) );
+ }
+
+ if (!report_gathering) {
+ for (n = 0; n < n_reports; ++n) {
+ if ((report_string[n] != (char*) NULL) &&
+ s - temp >= (report_len = strlen(report_string[n])) &&
+ strncmp(s - report_len, report_string[n], report_len) == 0) {
+ time_t time_now = time ((time_t*) NULL);
+ struct tm* tm_now = localtime (&time_now);
+
+ strftime (report_buffer, 20, "%b %d %H:%M:%S ", tm_now);
+ strcat (report_buffer, report_string[n]);
+
+ report_string[n] = (char *) NULL;
+ report_gathering = 1;
+ break;
+ }
+ }
+ }
+ else {
+ if (!iscntrl (c)) {
+ int rep_len = strlen (report_buffer);
+ report_buffer[rep_len] = c;
+ report_buffer[rep_len + 1] = '\0';
+ }
+ else {
+ report_gathering = 0;
+ fprintf (report_fp, "chat: %s\n", report_buffer);
+ }
+ }
+
+ if (s - temp >= len &&
+ c == string[len - 1] &&
+ strncmp(s - len, string, len) == 0) {
+ if (verbose) {
+ if (s > logged)
+ logf("%0.*v", s - logged, logged);
+ logf(" -- got it\n");
+ }
+
+ alarm(0);
+ alarmed = 0;
+ return (1);
+ }
+
+ for (n = 0; n < n_aborts; ++n) {
+ if (s - temp >= (abort_len = strlen(abort_string[n])) &&
+ strncmp(s - abort_len, abort_string[n], abort_len) == 0) {
+ if (verbose) {
+ if (s > logged)
+ logf("%0.*v", s - logged, logged);
+ logf(" -- failed");
+ }
+
+ alarm(0);
+ alarmed = 0;
+ exit_code = n + 4;
+ strcpy(fail_reason = fail_buffer, abort_string[n]);
+ return (0);
+ }
+ }
+
+ if (s >= end) {
+ if (logged < s - minlen) {
+ if (verbose)
+ logf("%0.*v", s - logged, logged);
+ logged = s;
+ }
+ s -= minlen;
+ memmove(temp, s, minlen);
+ logged = temp + (logged - s);
+ s = temp + minlen;
+ }
+
+ if (alarmed && verbose)
+ logf("warning: alarm synchronization problem");
+ }
+
+ alarm(0);
+
+ if (verbose && printed) {
+ if (alarmed)
+ logf(" -- read timed out");
+ else
+ logf(" -- read failed: %m");
+ }
+
+ exit_code = 3;
+ alarmed = 0;
+ return (0);
+}
+
+/*
+ * Gross kludge to handle Solaris versions >= 2.6 having usleep.
+ */
+#ifdef SOL2
+#include <sys/param.h>
+#if MAXUID > 65536 /* then this is Solaris 2.6 or later */
+#undef NO_USLEEP
+#endif
+#endif /* SOL2 */
+
+#ifdef NO_USLEEP
+#include <sys/types.h>
+#include <sys/time.h>
+
+/*
+ usleep -- support routine for 4.2BSD system call emulations
+ last edit: 29-Oct-1984 D A Gwyn
+ */
+
+extern int select();
+
+int
+usleep( usec ) /* returns 0 if ok, else -1 */
+ long usec; /* delay in microseconds */
+{
+ static struct { /* `timeval' */
+ long tv_sec; /* seconds */
+ long tv_usec; /* microsecs */
+ } delay; /* _select() timeout */
+
+ delay.tv_sec = usec / 1000000L;
+ delay.tv_usec = usec % 1000000L;
+
+ return select(0, (long *)0, (long *)0, (long *)0, &delay);
+}
+#endif
+
+void
+pack_array (array, end)
+ char **array; /* The address of the array of string pointers */
+ int end; /* The index of the next free entry before CLR_ */
+{
+ int i, j;
+
+ for (i = 0; i < end; i++) {
+ if (array[i] == NULL) {
+ for (j = i+1; j < end; ++j)
+ if (array[j] != NULL)
+ array[i++] = array[j];
+ for (; i < end; ++i)
+ array[i] = NULL;
+ break;
+ }
+ }
+}
+
+/*
+ * vfmtmsg - format a message into a buffer. Like vsprintf except we
+ * also specify the length of the output buffer, and we handle the
+ * %m (error message) format.
+ * Doesn't do floating-point formats.
+ * Returns the number of chars put into buf.
+ */
+#define OUTCHAR(c) (buflen > 0? (--buflen, *buf++ = (c)): 0)
+
+int
+vfmtmsg(buf, buflen, fmt, args)
+ char *buf;
+ int buflen;
+ const char *fmt;
+ va_list args;
+{
+ int c, i, n;
+ int width, prec, fillch;
+ int base, len, neg, quoted;
+ unsigned long val = 0;
+ char *str, *buf0;
+ const char *f;
+ unsigned char *p;
+ char num[32];
+ static char hexchars[] = "0123456789abcdef";
+
+ buf0 = buf;
+ --buflen;
+ while (buflen > 0) {
+ for (f = fmt; *f != '%' && *f != 0; ++f)
+ ;
+ if (f > fmt) {
+ len = f - fmt;
+ if (len > buflen)
+ len = buflen;
+ memcpy(buf, fmt, len);
+ buf += len;
+ buflen -= len;
+ fmt = f;
+ }
+ if (*fmt == 0)
+ break;
+ c = *++fmt;
+ width = prec = 0;
+ fillch = ' ';
+ if (c == '0') {
+ fillch = '0';
+ c = *++fmt;
+ }
+ if (c == '*') {
+ width = va_arg(args, int);
+ c = *++fmt;
+ } else {
+ while (isdigit(c)) {
+ width = width * 10 + c - '0';
+ c = *++fmt;
+ }
+ }
+ if (c == '.') {
+ c = *++fmt;
+ if (c == '*') {
+ prec = va_arg(args, int);
+ c = *++fmt;
+ } else {
+ while (isdigit(c)) {
+ prec = prec * 10 + c - '0';
+ c = *++fmt;
+ }
+ }
+ }
+ str = 0;
+ base = 0;
+ neg = 0;
+ ++fmt;
+ switch (c) {
+ case 'd':
+ i = va_arg(args, int);
+ if (i < 0) {
+ neg = 1;
+ val = -i;
+ } else
+ val = i;
+ base = 10;
+ break;
+ case 'o':
+ val = va_arg(args, unsigned int);
+ base = 8;
+ break;
+ case 'x':
+ val = va_arg(args, unsigned int);
+ base = 16;
+ break;
+ case 'p':
+ val = (unsigned long) va_arg(args, void *);
+ base = 16;
+ neg = 2;
+ break;
+ case 's':
+ str = va_arg(args, char *);
+ break;
+ case 'c':
+ num[0] = va_arg(args, int);
+ num[1] = 0;
+ str = num;
+ break;
+ case 'm':
+ str = strerror(errno);
+ break;
+ case 'v': /* "visible" string */
+ case 'q': /* quoted string */
+ quoted = c == 'q';
+ p = va_arg(args, unsigned char *);
+ if (fillch == '0' && prec > 0) {
+ n = prec;
+ } else {
+ n = strlen((char *)p);
+ if (prec > 0 && prec < n)
+ n = prec;
+ }
+ while (n > 0 && buflen > 0) {
+ c = *p++;
+ --n;
+ if (!quoted && c >= 0x80) {
+ OUTCHAR('M');
+ OUTCHAR('-');
+ c -= 0x80;
+ }
+ if (quoted && (c == '"' || c == '\\'))
+ OUTCHAR('\\');
+ if (c < 0x20 || (0x7f <= c && c < 0xa0)) {
+ if (quoted) {
+ OUTCHAR('\\');
+ switch (c) {
+ case '\t': OUTCHAR('t'); break;
+ case '\n': OUTCHAR('n'); break;
+ case '\b': OUTCHAR('b'); break;
+ case '\f': OUTCHAR('f'); break;
+ default:
+ OUTCHAR('x');
+ OUTCHAR(hexchars[c >> 4]);
+ OUTCHAR(hexchars[c & 0xf]);
+ }
+ } else {
+ if (c == '\t')
+ OUTCHAR(c);
+ else {
+ OUTCHAR('^');
+ OUTCHAR(c ^ 0x40);
+ }
+ }
+ } else
+ OUTCHAR(c);
+ }
+ continue;
+ default:
+ *buf++ = '%';
+ if (c != '%')
+ --fmt; /* so %z outputs %z etc. */
+ --buflen;
+ continue;
+ }
+ if (base != 0) {
+ str = num + sizeof(num);
+ *--str = 0;
+ while (str > num + neg) {
+ *--str = hexchars[val % base];
+ val = val / base;
+ if (--prec <= 0 && val == 0)
+ break;
+ }
+ switch (neg) {
+ case 1:
+ *--str = '-';
+ break;
+ case 2:
+ *--str = 'x';
+ *--str = '0';
+ break;
+ }
+ len = num + sizeof(num) - 1 - str;
+ } else {
+ len = strlen(str);
+ if (prec > 0 && len > prec)
+ len = prec;
+ }
+ if (width > 0) {
+ if (width > buflen)
+ width = buflen;
+ if ((n = width - len) > 0) {
+ buflen -= n;
+ for (; n > 0; --n)
+ *buf++ = fillch;
+ }
+ }
+ if (len > buflen)
+ len = buflen;
+ memcpy(buf, str, len);
+ buf += len;
+ buflen -= len;
+ }
+ *buf = 0;
+ return buf - buf0;
+}
diff --git a/mdk-stage1/ppp/common/zlib.c b/mdk-stage1/ppp/common/zlib.c
new file mode 100644
index 000000000..f4d2cc266
--- /dev/null
+++ b/mdk-stage1/ppp/common/zlib.c
@@ -0,0 +1,5376 @@
+/*
+ * This file is derived from various .h and .c files from the zlib-1.0.4
+ * distribution by Jean-loup Gailly and Mark Adler, with some additions
+ * by Paul Mackerras to aid in implementing Deflate compression and
+ * decompression for PPP packets. See zlib.h for conditions of
+ * distribution and use.
+ *
+ * Changes that have been made include:
+ * - added Z_PACKET_FLUSH (see zlib.h for details)
+ * - added inflateIncomp and deflateOutputPending
+ * - allow strm->next_out to be NULL, meaning discard the output
+ *
+ * $Id: zlib.c 195720 2001-06-11 11:44:34Z gc $
+ */
+
+/*
+ * ==FILEVERSION 971210==
+ *
+ * This marker is used by the Linux installation script to determine
+ * whether an up-to-date version of this file is already installed.
+ */
+
+#define NO_DUMMY_DECL
+#define NO_ZCFUNCS
+#define MY_ZCALLOC
+
+#if defined(__FreeBSD__) && (defined(KERNEL) || defined(_KERNEL))
+#define inflate inflate_ppp /* FreeBSD already has an inflate :-( */
+#endif
+
+
+/* +++ zutil.h */
+/* zutil.h -- internal interface and configuration of the compression library
+ * Copyright (C) 1995-1996 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+/* From: zutil.h,v 1.16 1996/07/24 13:41:13 me Exp $ */
+
+#ifndef _Z_UTIL_H
+#define _Z_UTIL_H
+
+#include "zlib.h"
+
+#if defined(KERNEL) || defined(_KERNEL)
+/* Assume this is a *BSD or SVR4 kernel */
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/systm.h>
+#undef u
+# define HAVE_MEMCPY
+# define memcpy(d, s, n) bcopy((s), (d), (n))
+# define memset(d, v, n) bzero((d), (n))
+# define memcmp bcmp
+
+#else
+#if defined(__KERNEL__)
+/* Assume this is a Linux kernel */
+#include <linux/string.h>
+#define HAVE_MEMCPY
+
+#else /* not kernel */
+
+#if defined(MSDOS)||defined(VMS)||defined(CRAY)||defined(WIN32)||defined(RISCOS)
+# include <stddef.h>
+# include <errno.h>
+#else
+ extern int errno;
+#endif
+#ifdef STDC
+# include <string.h>
+# include <stdlib.h>
+#endif
+#endif /* __KERNEL__ */
+#endif /* _KERNEL || KERNEL */
+
+#ifndef local
+# define local static
+#endif
+/* compile with -Dlocal if your debugger can't find static symbols */
+
+typedef unsigned char uch;
+typedef uch FAR uchf;
+typedef unsigned short ush;
+typedef ush FAR ushf;
+typedef unsigned long ulg;
+
+extern const char *z_errmsg[10]; /* indexed by 2-zlib_error */
+/* (size given to avoid silly warnings with Visual C++) */
+
+#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)]
+
+#define ERR_RETURN(strm,err) \
+ return (strm->msg = (char*)ERR_MSG(err), (err))
+/* To be used only when the state is known to be valid */
+
+ /* common constants */
+
+#ifndef DEF_WBITS
+# define DEF_WBITS MAX_WBITS
+#endif
+/* default windowBits for decompression. MAX_WBITS is for compression only */
+
+#if MAX_MEM_LEVEL >= 8
+# define DEF_MEM_LEVEL 8
+#else
+# define DEF_MEM_LEVEL MAX_MEM_LEVEL
+#endif
+/* default memLevel */
+
+#define STORED_BLOCK 0
+#define STATIC_TREES 1
+#define DYN_TREES 2
+/* The three kinds of block type */
+
+#define MIN_MATCH 3
+#define MAX_MATCH 258
+/* The minimum and maximum match lengths */
+
+#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */
+
+ /* target dependencies */
+
+#ifdef MSDOS
+# define OS_CODE 0x00
+# ifdef __TURBOC__
+# include <alloc.h>
+# else /* MSC or DJGPP */
+# include <malloc.h>
+# endif
+#endif
+
+#ifdef OS2
+# define OS_CODE 0x06
+#endif
+
+#ifdef WIN32 /* Window 95 & Windows NT */
+# define OS_CODE 0x0b
+#endif
+
+#if defined(VAXC) || defined(VMS)
+# define OS_CODE 0x02
+# define FOPEN(name, mode) \
+ fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512")
+#endif
+
+#ifdef AMIGA
+# define OS_CODE 0x01
+#endif
+
+#if defined(ATARI) || defined(atarist)
+# define OS_CODE 0x05
+#endif
+
+#ifdef MACOS
+# define OS_CODE 0x07
+#endif
+
+#ifdef __50SERIES /* Prime/PRIMOS */
+# define OS_CODE 0x0F
+#endif
+
+#ifdef TOPS20
+# define OS_CODE 0x0a
+#endif
+
+#if defined(_BEOS_) || defined(RISCOS)
+# define fdopen(fd,mode) NULL /* No fdopen() */
+#endif
+
+ /* Common defaults */
+
+#ifndef OS_CODE
+# define OS_CODE 0x03 /* assume Unix */
+#endif
+
+#ifndef FOPEN
+# define FOPEN(name, mode) fopen((name), (mode))
+#endif
+
+ /* functions */
+
+#ifdef HAVE_STRERROR
+ extern char *strerror OF((int));
+# define zstrerror(errnum) strerror(errnum)
+#else
+# define zstrerror(errnum) ""
+#endif
+
+#if defined(pyr)
+# define NO_MEMCPY
+#endif
+#if (defined(M_I86SM) || defined(M_I86MM)) && !defined(_MSC_VER)
+ /* Use our own functions for small and medium model with MSC <= 5.0.
+ * You may have to use the same strategy for Borland C (untested).
+ */
+# define NO_MEMCPY
+#endif
+#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY)
+# define HAVE_MEMCPY
+#endif
+#ifdef HAVE_MEMCPY
+# ifdef SMALL_MEDIUM /* MSDOS small or medium model */
+# define zmemcpy _fmemcpy
+# define zmemcmp _fmemcmp
+# define zmemzero(dest, len) _fmemset(dest, 0, len)
+# else
+# define zmemcpy memcpy
+# define zmemcmp memcmp
+# define zmemzero(dest, len) memset(dest, 0, len)
+# endif
+#else
+ extern void zmemcpy OF((Bytef* dest, Bytef* source, uInt len));
+ extern int zmemcmp OF((Bytef* s1, Bytef* s2, uInt len));
+ extern void zmemzero OF((Bytef* dest, uInt len));
+#endif
+
+/* Diagnostic functions */
+#ifdef DEBUG_ZLIB
+# include <stdio.h>
+# ifndef verbose
+# define verbose 0
+# endif
+ extern void z_error OF((char *m));
+# define Assert(cond,msg) {if(!(cond)) z_error(msg);}
+# define Trace(x) fprintf x
+# define Tracev(x) {if (verbose) fprintf x ;}
+# define Tracevv(x) {if (verbose>1) fprintf x ;}
+# define Tracec(c,x) {if (verbose && (c)) fprintf x ;}
+# define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;}
+#else
+# define Assert(cond,msg)
+# define Trace(x)
+# define Tracev(x)
+# define Tracevv(x)
+# define Tracec(c,x)
+# define Tracecv(c,x)
+#endif
+
+
+typedef uLong (*check_func) OF((uLong check, const Bytef *buf, uInt len));
+
+voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size));
+void zcfree OF((voidpf opaque, voidpf ptr));
+
+#define ZALLOC(strm, items, size) \
+ (*((strm)->zalloc))((strm)->opaque, (items), (size))
+#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr))
+#define TRY_FREE(s, p) {if (p) ZFREE(s, p);}
+
+#endif /* _Z_UTIL_H */
+/* --- zutil.h */
+
+/* +++ deflate.h */
+/* deflate.h -- internal compression state
+ * Copyright (C) 1995-1996 Jean-loup Gailly
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+/* From: deflate.h,v 1.10 1996/07/02 12:41:00 me Exp $ */
+
+#ifndef _DEFLATE_H
+#define _DEFLATE_H
+
+/* #include "zutil.h" */
+
+/* ===========================================================================
+ * Internal compression state.
+ */
+
+#define LENGTH_CODES 29
+/* number of length codes, not counting the special END_BLOCK code */
+
+#define LITERALS 256
+/* number of literal bytes 0..255 */
+
+#define L_CODES (LITERALS+1+LENGTH_CODES)
+/* number of Literal or Length codes, including the END_BLOCK code */
+
+#define D_CODES 30
+/* number of distance codes */
+
+#define BL_CODES 19
+/* number of codes used to transfer the bit lengths */
+
+#define HEAP_SIZE (2*L_CODES+1)
+/* maximum heap size */
+
+#define MAX_BITS 15
+/* All codes must not exceed MAX_BITS bits */
+
+#define INIT_STATE 42
+#define BUSY_STATE 113
+#define FINISH_STATE 666
+/* Stream status */
+
+
+/* Data structure describing a single value and its code string. */
+typedef struct ct_data_s {
+ union {
+ ush freq; /* frequency count */
+ ush code; /* bit string */
+ } fc;
+ union {
+ ush dad; /* father node in Huffman tree */
+ ush len; /* length of bit string */
+ } dl;
+} FAR ct_data;
+
+#define Freq fc.freq
+#define Code fc.code
+#define Dad dl.dad
+#define Len dl.len
+
+typedef struct static_tree_desc_s static_tree_desc;
+
+typedef struct tree_desc_s {
+ ct_data *dyn_tree; /* the dynamic tree */
+ int max_code; /* largest code with non zero frequency */
+ static_tree_desc *stat_desc; /* the corresponding static tree */
+} FAR tree_desc;
+
+typedef ush Pos;
+typedef Pos FAR Posf;
+typedef unsigned IPos;
+
+/* A Pos is an index in the character window. We use short instead of int to
+ * save space in the various tables. IPos is used only for parameter passing.
+ */
+
+typedef struct deflate_state {
+ z_streamp strm; /* pointer back to this zlib stream */
+ int status; /* as the name implies */
+ Bytef *pending_buf; /* output still pending */
+ ulg pending_buf_size; /* size of pending_buf */
+ Bytef *pending_out; /* next pending byte to output to the stream */
+ int pending; /* nb of bytes in the pending buffer */
+ int noheader; /* suppress zlib header and adler32 */
+ Byte data_type; /* UNKNOWN, BINARY or ASCII */
+ Byte method; /* STORED (for zip only) or DEFLATED */
+ int last_flush; /* value of flush param for previous deflate call */
+
+ /* used by deflate.c: */
+
+ uInt w_size; /* LZ77 window size (32K by default) */
+ uInt w_bits; /* log2(w_size) (8..16) */
+ uInt w_mask; /* w_size - 1 */
+
+ Bytef *window;
+ /* Sliding window. Input bytes are read into the second half of the window,
+ * and move to the first half later to keep a dictionary of at least wSize
+ * bytes. With this organization, matches are limited to a distance of
+ * wSize-MAX_MATCH bytes, but this ensures that IO is always
+ * performed with a length multiple of the block size. Also, it limits
+ * the window size to 64K, which is quite useful on MSDOS.
+ * To do: use the user input buffer as sliding window.
+ */
+
+ ulg window_size;
+ /* Actual size of window: 2*wSize, except when the user input buffer
+ * is directly used as sliding window.
+ */
+
+ Posf *prev;
+ /* Link to older string with same hash index. To limit the size of this
+ * array to 64K, this link is maintained only for the last 32K strings.
+ * An index in this array is thus a window index modulo 32K.
+ */
+
+ Posf *head; /* Heads of the hash chains or NIL. */
+
+ uInt ins_h; /* hash index of string to be inserted */
+ uInt hash_size; /* number of elements in hash table */
+ uInt hash_bits; /* log2(hash_size) */
+ uInt hash_mask; /* hash_size-1 */
+
+ uInt hash_shift;
+ /* Number of bits by which ins_h must be shifted at each input
+ * step. It must be such that after MIN_MATCH steps, the oldest
+ * byte no longer takes part in the hash key, that is:
+ * hash_shift * MIN_MATCH >= hash_bits
+ */
+
+ long block_start;
+ /* Window position at the beginning of the current output block. Gets
+ * negative when the window is moved backwards.
+ */
+
+ uInt match_length; /* length of best match */
+ IPos prev_match; /* previous match */
+ int match_available; /* set if previous match exists */
+ uInt strstart; /* start of string to insert */
+ uInt match_start; /* start of matching string */
+ uInt lookahead; /* number of valid bytes ahead in window */
+
+ uInt prev_length;
+ /* Length of the best match at previous step. Matches not greater than this
+ * are discarded. This is used in the lazy match evaluation.
+ */
+
+ uInt max_chain_length;
+ /* To speed up deflation, hash chains are never searched beyond this
+ * length. A higher limit improves compression ratio but degrades the
+ * speed.
+ */
+
+ uInt max_lazy_match;
+ /* Attempt to find a better match only when the current match is strictly
+ * smaller than this value. This mechanism is used only for compression
+ * levels >= 4.
+ */
+# define max_insert_length max_lazy_match
+ /* Insert new strings in the hash table only if the match length is not
+ * greater than this length. This saves time but degrades compression.
+ * max_insert_length is used only for compression levels <= 3.
+ */
+
+ int level; /* compression level (1..9) */
+ int strategy; /* favor or force Huffman coding*/
+
+ uInt good_match;
+ /* Use a faster search when the previous match is longer than this */
+
+ int nice_match; /* Stop searching when current match exceeds this */
+
+ /* used by trees.c: */
+ /* Didn't use ct_data typedef below to supress compiler warning */
+ struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */
+ struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */
+ struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */
+
+ struct tree_desc_s l_desc; /* desc. for literal tree */
+ struct tree_desc_s d_desc; /* desc. for distance tree */
+ struct tree_desc_s bl_desc; /* desc. for bit length tree */
+
+ ush bl_count[MAX_BITS+1];
+ /* number of codes at each bit length for an optimal tree */
+
+ int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */
+ int heap_len; /* number of elements in the heap */
+ int heap_max; /* element of largest frequency */
+ /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.
+ * The same heap array is used to build all trees.
+ */
+
+ uch depth[2*L_CODES+1];
+ /* Depth of each subtree used as tie breaker for trees of equal frequency
+ */
+
+ uchf *l_buf; /* buffer for literals or lengths */
+
+ uInt lit_bufsize;
+ /* Size of match buffer for literals/lengths. There are 4 reasons for
+ * limiting lit_bufsize to 64K:
+ * - frequencies can be kept in 16 bit counters
+ * - if compression is not successful for the first block, all input
+ * data is still in the window so we can still emit a stored block even
+ * when input comes from standard input. (This can also be done for
+ * all blocks if lit_bufsize is not greater than 32K.)
+ * - if compression is not successful for a file smaller than 64K, we can
+ * even emit a stored file instead of a stored block (saving 5 bytes).
+ * This is applicable only for zip (not gzip or zlib).
+ * - creating new Huffman trees less frequently may not provide fast
+ * adaptation to changes in the input data statistics. (Take for
+ * example a binary file with poorly compressible code followed by
+ * a highly compressible string table.) Smaller buffer sizes give
+ * fast adaptation but have of course the overhead of transmitting
+ * trees more frequently.
+ * - I can't count above 4
+ */
+
+ uInt last_lit; /* running index in l_buf */
+
+ ushf *d_buf;
+ /* Buffer for distances. To simplify the code, d_buf and l_buf have
+ * the same number of elements. To use different lengths, an extra flag
+ * array would be necessary.
+ */
+
+ ulg opt_len; /* bit length of current block with optimal trees */
+ ulg static_len; /* bit length of current block with static trees */
+ ulg compressed_len; /* total bit length of compressed file */
+ uInt matches; /* number of string matches in current block */
+ int last_eob_len; /* bit length of EOB code for last block */
+
+#ifdef DEBUG_ZLIB
+ ulg bits_sent; /* bit length of the compressed data */
+#endif
+
+ ush bi_buf;
+ /* Output buffer. bits are inserted starting at the bottom (least
+ * significant bits).
+ */
+ int bi_valid;
+ /* Number of valid bits in bi_buf. All bits above the last valid bit
+ * are always zero.
+ */
+
+} FAR deflate_state;
+
+/* Output a byte on the stream.
+ * IN assertion: there is enough room in pending_buf.
+ */
+#define put_byte(s, c) {s->pending_buf[s->pending++] = (c);}
+
+
+#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
+/* Minimum amount of lookahead, except at the end of the input file.
+ * See deflate.c for comments about the MIN_MATCH+1.
+ */
+
+#define MAX_DIST(s) ((s)->w_size-MIN_LOOKAHEAD)
+/* In order to simplify the code, particularly on 16 bit machines, match
+ * distances are limited to MAX_DIST instead of WSIZE.
+ */
+
+ /* in trees.c */
+void _tr_init OF((deflate_state *s));
+int _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc));
+ulg _tr_flush_block OF((deflate_state *s, charf *buf, ulg stored_len,
+ int eof));
+void _tr_align OF((deflate_state *s));
+void _tr_stored_block OF((deflate_state *s, charf *buf, ulg stored_len,
+ int eof));
+void _tr_stored_type_only OF((deflate_state *));
+
+#endif
+/* --- deflate.h */
+
+/* +++ deflate.c */
+/* deflate.c -- compress data using the deflation algorithm
+ * Copyright (C) 1995-1996 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/*
+ * ALGORITHM
+ *
+ * The "deflation" process depends on being able to identify portions
+ * of the input text which are identical to earlier input (within a
+ * sliding window trailing behind the input currently being processed).
+ *
+ * The most straightforward technique turns out to be the fastest for
+ * most input files: try all possible matches and select the longest.
+ * The key feature of this algorithm is that insertions into the string
+ * dictionary are very simple and thus fast, and deletions are avoided
+ * completely. Insertions are performed at each input character, whereas
+ * string matches are performed only when the previous match ends. So it
+ * is preferable to spend more time in matches to allow very fast string
+ * insertions and avoid deletions. The matching algorithm for small
+ * strings is inspired from that of Rabin & Karp. A brute force approach
+ * is used to find longer strings when a small match has been found.
+ * A similar algorithm is used in comic (by Jan-Mark Wams) and freeze
+ * (by Leonid Broukhis).
+ * A previous version of this file used a more sophisticated algorithm
+ * (by Fiala and Greene) which is guaranteed to run in linear amortized
+ * time, but has a larger average cost, uses more memory and is patented.
+ * However the F&G algorithm may be faster for some highly redundant
+ * files if the parameter max_chain_length (described below) is too large.
+ *
+ * ACKNOWLEDGEMENTS
+ *
+ * The idea of lazy evaluation of matches is due to Jan-Mark Wams, and
+ * I found it in 'freeze' written by Leonid Broukhis.
+ * Thanks to many people for bug reports and testing.
+ *
+ * REFERENCES
+ *
+ * Deutsch, L.P.,"DEFLATE Compressed Data Format Specification".
+ * Available in ftp://ds.internic.net/rfc/rfc1951.txt
+ *
+ * A description of the Rabin and Karp algorithm is given in the book
+ * "Algorithms" by R. Sedgewick, Addison-Wesley, p252.
+ *
+ * Fiala,E.R., and Greene,D.H.
+ * Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595
+ *
+ */
+
+/* From: deflate.c,v 1.15 1996/07/24 13:40:58 me Exp $ */
+
+/* #include "deflate.h" */
+
+char deflate_copyright[] = " deflate 1.0.4 Copyright 1995-1996 Jean-loup Gailly ";
+/*
+ If you use the zlib library in a product, an acknowledgment is welcome
+ in the documentation of your product. If for some reason you cannot
+ include such an acknowledgment, I would appreciate that you keep this
+ copyright string in the executable of your product.
+ */
+
+/* ===========================================================================
+ * Function prototypes.
+ */
+typedef enum {
+ need_more, /* block not completed, need more input or more output */
+ block_done, /* block flush performed */
+ finish_started, /* finish started, need only more output at next deflate */
+ finish_done /* finish done, accept no more input or output */
+} block_state;
+
+typedef block_state (*compress_func) OF((deflate_state *s, int flush));
+/* Compression function. Returns the block state after the call. */
+
+local void fill_window OF((deflate_state *s));
+local block_state deflate_stored OF((deflate_state *s, int flush));
+local block_state deflate_fast OF((deflate_state *s, int flush));
+local block_state deflate_slow OF((deflate_state *s, int flush));
+local void lm_init OF((deflate_state *s));
+local void putShortMSB OF((deflate_state *s, uInt b));
+local void flush_pending OF((z_streamp strm));
+local int read_buf OF((z_streamp strm, charf *buf, unsigned size));
+#ifdef ASMV
+ void match_init OF((void)); /* asm code initialization */
+ uInt longest_match OF((deflate_state *s, IPos cur_match));
+#else
+local uInt longest_match OF((deflate_state *s, IPos cur_match));
+#endif
+
+#ifdef DEBUG_ZLIB
+local void check_match OF((deflate_state *s, IPos start, IPos match,
+ int length));
+#endif
+
+/* ===========================================================================
+ * Local data
+ */
+
+#define NIL 0
+/* Tail of hash chains */
+
+#ifndef TOO_FAR
+# define TOO_FAR 4096
+#endif
+/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */
+
+#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
+/* Minimum amount of lookahead, except at the end of the input file.
+ * See deflate.c for comments about the MIN_MATCH+1.
+ */
+
+/* Values for max_lazy_match, good_match and max_chain_length, depending on
+ * the desired pack level (0..9). The values given below have been tuned to
+ * exclude worst case performance for pathological files. Better values may be
+ * found for specific files.
+ */
+typedef struct config_s {
+ ush good_length; /* reduce lazy search above this match length */
+ ush max_lazy; /* do not perform lazy search above this match length */
+ ush nice_length; /* quit search above this match length */
+ ush max_chain;
+ compress_func func;
+} config;
+
+local config configuration_table[10] = {
+/* good lazy nice chain */
+/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */
+/* 1 */ {4, 4, 8, 4, deflate_fast}, /* maximum speed, no lazy matches */
+/* 2 */ {4, 5, 16, 8, deflate_fast},
+/* 3 */ {4, 6, 32, 32, deflate_fast},
+
+/* 4 */ {4, 4, 16, 16, deflate_slow}, /* lazy matches */
+/* 5 */ {8, 16, 32, 32, deflate_slow},
+/* 6 */ {8, 16, 128, 128, deflate_slow},
+/* 7 */ {8, 32, 128, 256, deflate_slow},
+/* 8 */ {32, 128, 258, 1024, deflate_slow},
+/* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* maximum compression */
+
+/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4
+ * For deflate_fast() (levels <= 3) good is ignored and lazy has a different
+ * meaning.
+ */
+
+#define EQUAL 0
+/* result of memcmp for equal strings */
+
+#ifndef NO_DUMMY_DECL
+struct static_tree_desc_s {int dummy;}; /* for buggy compilers */
+#endif
+
+/* ===========================================================================
+ * Update a hash value with the given input byte
+ * IN assertion: all calls to to UPDATE_HASH are made with consecutive
+ * input characters, so that a running hash key can be computed from the
+ * previous key instead of complete recalculation each time.
+ */
+#define UPDATE_HASH(s,h,c) (h = (((h)<<s->hash_shift) ^ (c)) & s->hash_mask)
+
+
+/* ===========================================================================
+ * Insert string str in the dictionary and set match_head to the previous head
+ * of the hash chain (the most recent string with same hash key). Return
+ * the previous length of the hash chain.
+ * IN assertion: all calls to to INSERT_STRING are made with consecutive
+ * input characters and the first MIN_MATCH bytes of str are valid
+ * (except for the last MIN_MATCH-1 bytes of the input file).
+ */
+#define INSERT_STRING(s, str, match_head) \
+ (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \
+ s->prev[(str) & s->w_mask] = match_head = s->head[s->ins_h], \
+ s->head[s->ins_h] = (Pos)(str))
+
+/* ===========================================================================
+ * Initialize the hash table (avoiding 64K overflow for 16 bit systems).
+ * prev[] will be initialized on the fly.
+ */
+#define CLEAR_HASH(s) \
+ s->head[s->hash_size-1] = NIL; \
+ zmemzero((charf *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head));
+
+/* ========================================================================= */
+int deflateInit_(strm, level, version, stream_size)
+ z_streamp strm;
+ int level;
+ const char *version;
+ int stream_size;
+{
+ return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL,
+ Z_DEFAULT_STRATEGY, version, stream_size);
+ /* To do: ignore strm->next_in if we use it as window */
+}
+
+/* ========================================================================= */
+int deflateInit2_(strm, level, method, windowBits, memLevel, strategy,
+ version, stream_size)
+ z_streamp strm;
+ int level;
+ int method;
+ int windowBits;
+ int memLevel;
+ int strategy;
+ const char *version;
+ int stream_size;
+{
+ deflate_state *s;
+ int noheader = 0;
+ static char* my_version = ZLIB_VERSION;
+
+ ushf *overlay;
+ /* We overlay pending_buf and d_buf+l_buf. This works since the average
+ * output size for (length,distance) codes is <= 24 bits.
+ */
+
+ if (version == Z_NULL || version[0] != my_version[0] ||
+ stream_size != sizeof(z_stream)) {
+ return Z_VERSION_ERROR;
+ }
+ if (strm == Z_NULL) return Z_STREAM_ERROR;
+
+ strm->msg = Z_NULL;
+#ifndef NO_ZCFUNCS
+ if (strm->zalloc == Z_NULL) {
+ strm->zalloc = zcalloc;
+ strm->opaque = (voidpf)0;
+ }
+ if (strm->zfree == Z_NULL) strm->zfree = zcfree;
+#endif
+
+ if (level == Z_DEFAULT_COMPRESSION) level = 6;
+
+ if (windowBits < 0) { /* undocumented feature: suppress zlib header */
+ noheader = 1;
+ windowBits = -windowBits;
+ }
+ if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED ||
+ windowBits < 8 || windowBits > 15 || level < 0 || level > 9 ||
+ strategy < 0 || strategy > Z_HUFFMAN_ONLY) {
+ return Z_STREAM_ERROR;
+ }
+ s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state));
+ if (s == Z_NULL) return Z_MEM_ERROR;
+ strm->state = (struct internal_state FAR *)s;
+ s->strm = strm;
+
+ s->noheader = noheader;
+ s->w_bits = windowBits;
+ s->w_size = 1 << s->w_bits;
+ s->w_mask = s->w_size - 1;
+
+ s->hash_bits = memLevel + 7;
+ s->hash_size = 1 << s->hash_bits;
+ s->hash_mask = s->hash_size - 1;
+ s->hash_shift = ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH);
+
+ s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte));
+ s->prev = (Posf *) ZALLOC(strm, s->w_size, sizeof(Pos));
+ s->head = (Posf *) ZALLOC(strm, s->hash_size, sizeof(Pos));
+
+ s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */
+
+ overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2);
+ s->pending_buf = (uchf *) overlay;
+ s->pending_buf_size = (ulg)s->lit_bufsize * (sizeof(ush)+2L);
+
+ if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL ||
+ s->pending_buf == Z_NULL) {
+ strm->msg = (char*)ERR_MSG(Z_MEM_ERROR);
+ deflateEnd (strm);
+ return Z_MEM_ERROR;
+ }
+ s->d_buf = overlay + s->lit_bufsize/sizeof(ush);
+ s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize;
+
+ s->level = level;
+ s->strategy = strategy;
+ s->method = (Byte)method;
+
+ return deflateReset(strm);
+}
+
+/* ========================================================================= */
+int deflateSetDictionary (strm, dictionary, dictLength)
+ z_streamp strm;
+ const Bytef *dictionary;
+ uInt dictLength;
+{
+ deflate_state *s;
+ uInt length = dictLength;
+ uInt n;
+ IPos hash_head = 0;
+
+ if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL)
+ return Z_STREAM_ERROR;
+
+ s = (deflate_state *) strm->state;
+ if (s->status != INIT_STATE) return Z_STREAM_ERROR;
+
+ strm->adler = adler32(strm->adler, dictionary, dictLength);
+
+ if (length < MIN_MATCH) return Z_OK;
+ if (length > MAX_DIST(s)) {
+ length = MAX_DIST(s);
+#ifndef USE_DICT_HEAD
+ dictionary += dictLength - length; /* use the tail of the dictionary */
+#endif
+ }
+ zmemcpy((charf *)s->window, dictionary, length);
+ s->strstart = length;
+ s->block_start = (long)length;
+
+ /* Insert all strings in the hash table (except for the last two bytes).
+ * s->lookahead stays null, so s->ins_h will be recomputed at the next
+ * call of fill_window.
+ */
+ s->ins_h = s->window[0];
+ UPDATE_HASH(s, s->ins_h, s->window[1]);
+ for (n = 0; n <= length - MIN_MATCH; n++) {
+ INSERT_STRING(s, n, hash_head);
+ }
+ if (hash_head) hash_head = 0; /* to make compiler happy */
+ return Z_OK;
+}
+
+/* ========================================================================= */
+int deflateReset (strm)
+ z_streamp strm;
+{
+ deflate_state *s;
+
+ if (strm == Z_NULL || strm->state == Z_NULL ||
+ strm->zalloc == Z_NULL || strm->zfree == Z_NULL) return Z_STREAM_ERROR;
+
+ strm->total_in = strm->total_out = 0;
+ strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */
+ strm->data_type = Z_UNKNOWN;
+
+ s = (deflate_state *)strm->state;
+ s->pending = 0;
+ s->pending_out = s->pending_buf;
+
+ if (s->noheader < 0) {
+ s->noheader = 0; /* was set to -1 by deflate(..., Z_FINISH); */
+ }
+ s->status = s->noheader ? BUSY_STATE : INIT_STATE;
+ strm->adler = 1;
+ s->last_flush = Z_NO_FLUSH;
+
+ _tr_init(s);
+ lm_init(s);
+
+ return Z_OK;
+}
+
+/* ========================================================================= */
+int deflateParams(strm, level, strategy)
+ z_streamp strm;
+ int level;
+ int strategy;
+{
+ deflate_state *s;
+ compress_func func;
+ int err = Z_OK;
+
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ s = (deflate_state *) strm->state;
+
+ if (level == Z_DEFAULT_COMPRESSION) {
+ level = 6;
+ }
+ if (level < 0 || level > 9 || strategy < 0 || strategy > Z_HUFFMAN_ONLY) {
+ return Z_STREAM_ERROR;
+ }
+ func = configuration_table[s->level].func;
+
+ if (func != configuration_table[level].func && strm->total_in != 0) {
+ /* Flush the last buffer: */
+ err = deflate(strm, Z_PARTIAL_FLUSH);
+ }
+ if (s->level != level) {
+ s->level = level;
+ s->max_lazy_match = configuration_table[level].max_lazy;
+ s->good_match = configuration_table[level].good_length;
+ s->nice_match = configuration_table[level].nice_length;
+ s->max_chain_length = configuration_table[level].max_chain;
+ }
+ s->strategy = strategy;
+ return err;
+}
+
+/* =========================================================================
+ * Put a short in the pending buffer. The 16-bit value is put in MSB order.
+ * IN assertion: the stream state is correct and there is enough room in
+ * pending_buf.
+ */
+local void putShortMSB (s, b)
+ deflate_state *s;
+ uInt b;
+{
+ put_byte(s, (Byte)(b >> 8));
+ put_byte(s, (Byte)(b & 0xff));
+}
+
+/* =========================================================================
+ * Flush as much pending output as possible. All deflate() output goes
+ * through this function so some applications may wish to modify it
+ * to avoid allocating a large strm->next_out buffer and copying into it.
+ * (See also read_buf()).
+ */
+local void flush_pending(strm)
+ z_streamp strm;
+{
+ deflate_state *s = (deflate_state *) strm->state;
+ unsigned len = s->pending;
+
+ if (len > strm->avail_out) len = strm->avail_out;
+ if (len == 0) return;
+
+ if (strm->next_out != Z_NULL) {
+ zmemcpy(strm->next_out, s->pending_out, len);
+ strm->next_out += len;
+ }
+ s->pending_out += len;
+ strm->total_out += len;
+ strm->avail_out -= len;
+ s->pending -= len;
+ if (s->pending == 0) {
+ s->pending_out = s->pending_buf;
+ }
+}
+
+/* ========================================================================= */
+int deflate (strm, flush)
+ z_streamp strm;
+ int flush;
+{
+ int old_flush; /* value of flush param for previous deflate call */
+ deflate_state *s;
+
+ if (strm == Z_NULL || strm->state == Z_NULL ||
+ flush > Z_FINISH || flush < 0) {
+ return Z_STREAM_ERROR;
+ }
+ s = (deflate_state *) strm->state;
+
+ if ((strm->next_in == Z_NULL && strm->avail_in != 0) ||
+ (s->status == FINISH_STATE && flush != Z_FINISH)) {
+ ERR_RETURN(strm, Z_STREAM_ERROR);
+ }
+ if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR);
+
+ s->strm = strm; /* just in case */
+ old_flush = s->last_flush;
+ s->last_flush = flush;
+
+ /* Write the zlib header */
+ if (s->status == INIT_STATE) {
+
+ uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8;
+ uInt level_flags = (s->level-1) >> 1;
+
+ if (level_flags > 3) level_flags = 3;
+ header |= (level_flags << 6);
+ if (s->strstart != 0) header |= PRESET_DICT;
+ header += 31 - (header % 31);
+
+ s->status = BUSY_STATE;
+ putShortMSB(s, header);
+
+ /* Save the adler32 of the preset dictionary: */
+ if (s->strstart != 0) {
+ putShortMSB(s, (uInt)(strm->adler >> 16));
+ putShortMSB(s, (uInt)(strm->adler & 0xffff));
+ }
+ strm->adler = 1L;
+ }
+
+ /* Flush as much pending output as possible */
+ if (s->pending != 0) {
+ flush_pending(strm);
+ if (strm->avail_out == 0) {
+ /* Since avail_out is 0, deflate will be called again with
+ * more output space, but possibly with both pending and
+ * avail_in equal to zero. There won't be anything to do,
+ * but this is not an error situation so make sure we
+ * return OK instead of BUF_ERROR at next call of deflate:
+ */
+ s->last_flush = -1;
+ return Z_OK;
+ }
+
+ /* Make sure there is something to do and avoid duplicate consecutive
+ * flushes. For repeated and useless calls with Z_FINISH, we keep
+ * returning Z_STREAM_END instead of Z_BUFF_ERROR.
+ */
+ } else if (strm->avail_in == 0 && flush <= old_flush &&
+ flush != Z_FINISH) {
+ ERR_RETURN(strm, Z_BUF_ERROR);
+ }
+
+ /* User must not provide more input after the first FINISH: */
+ if (s->status == FINISH_STATE && strm->avail_in != 0) {
+ ERR_RETURN(strm, Z_BUF_ERROR);
+ }
+
+ /* Start a new block or continue the current one.
+ */
+ if (strm->avail_in != 0 || s->lookahead != 0 ||
+ (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) {
+ block_state bstate;
+
+ bstate = (*(configuration_table[s->level].func))(s, flush);
+
+ if (bstate == finish_started || bstate == finish_done) {
+ s->status = FINISH_STATE;
+ }
+ if (bstate == need_more || bstate == finish_started) {
+ if (strm->avail_out == 0) {
+ s->last_flush = -1; /* avoid BUF_ERROR next call, see above */
+ }
+ return Z_OK;
+ /* If flush != Z_NO_FLUSH && avail_out == 0, the next call
+ * of deflate should use the same flush parameter to make sure
+ * that the flush is complete. So we don't have to output an
+ * empty block here, this will be done at next call. This also
+ * ensures that for a very small output buffer, we emit at most
+ * one empty block.
+ */
+ }
+ if (bstate == block_done) {
+ if (flush == Z_PARTIAL_FLUSH) {
+ _tr_align(s);
+ } else if (flush == Z_PACKET_FLUSH) {
+ /* Output just the 3-bit `stored' block type value,
+ but not a zero length. */
+ _tr_stored_type_only(s);
+ } else { /* FULL_FLUSH or SYNC_FLUSH */
+ _tr_stored_block(s, (char*)0, 0L, 0);
+ /* For a full flush, this empty block will be recognized
+ * as a special marker by inflate_sync().
+ */
+ if (flush == Z_FULL_FLUSH) {
+ CLEAR_HASH(s); /* forget history */
+ }
+ }
+ flush_pending(strm);
+ if (strm->avail_out == 0) {
+ s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */
+ return Z_OK;
+ }
+ }
+ }
+ Assert(strm->avail_out > 0, "bug2");
+
+ if (flush != Z_FINISH) return Z_OK;
+ if (s->noheader) return Z_STREAM_END;
+
+ /* Write the zlib trailer (adler32) */
+ putShortMSB(s, (uInt)(strm->adler >> 16));
+ putShortMSB(s, (uInt)(strm->adler & 0xffff));
+ flush_pending(strm);
+ /* If avail_out is zero, the application will call deflate again
+ * to flush the rest.
+ */
+ s->noheader = -1; /* write the trailer only once! */
+ return s->pending != 0 ? Z_OK : Z_STREAM_END;
+}
+
+/* ========================================================================= */
+int deflateEnd (strm)
+ z_streamp strm;
+{
+ int status;
+ deflate_state *s;
+
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ s = (deflate_state *) strm->state;
+
+ status = s->status;
+ if (status != INIT_STATE && status != BUSY_STATE &&
+ status != FINISH_STATE) {
+ return Z_STREAM_ERROR;
+ }
+
+ /* Deallocate in reverse order of allocations: */
+ TRY_FREE(strm, s->pending_buf);
+ TRY_FREE(strm, s->head);
+ TRY_FREE(strm, s->prev);
+ TRY_FREE(strm, s->window);
+
+ ZFREE(strm, s);
+ strm->state = Z_NULL;
+
+ return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK;
+}
+
+/* =========================================================================
+ * Copy the source state to the destination state.
+ */
+int deflateCopy (dest, source)
+ z_streamp dest;
+ z_streamp source;
+{
+ deflate_state *ds;
+ deflate_state *ss;
+ ushf *overlay;
+
+ if (source == Z_NULL || dest == Z_NULL || source->state == Z_NULL)
+ return Z_STREAM_ERROR;
+ ss = (deflate_state *) source->state;
+
+ zmemcpy(dest, source, sizeof(*dest));
+
+ ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state));
+ if (ds == Z_NULL) return Z_MEM_ERROR;
+ dest->state = (struct internal_state FAR *) ds;
+ zmemcpy(ds, ss, sizeof(*ds));
+ ds->strm = dest;
+
+ ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte));
+ ds->prev = (Posf *) ZALLOC(dest, ds->w_size, sizeof(Pos));
+ ds->head = (Posf *) ZALLOC(dest, ds->hash_size, sizeof(Pos));
+ overlay = (ushf *) ZALLOC(dest, ds->lit_bufsize, sizeof(ush)+2);
+ ds->pending_buf = (uchf *) overlay;
+
+ if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL ||
+ ds->pending_buf == Z_NULL) {
+ deflateEnd (dest);
+ return Z_MEM_ERROR;
+ }
+ /* ??? following zmemcpy doesn't work for 16-bit MSDOS */
+ zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte));
+ zmemcpy(ds->prev, ss->prev, ds->w_size * sizeof(Pos));
+ zmemcpy(ds->head, ss->head, ds->hash_size * sizeof(Pos));
+ zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size);
+
+ ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf);
+ ds->d_buf = overlay + ds->lit_bufsize/sizeof(ush);
+ ds->l_buf = ds->pending_buf + (1+sizeof(ush))*ds->lit_bufsize;
+
+ ds->l_desc.dyn_tree = ds->dyn_ltree;
+ ds->d_desc.dyn_tree = ds->dyn_dtree;
+ ds->bl_desc.dyn_tree = ds->bl_tree;
+
+ return Z_OK;
+}
+
+/* ===========================================================================
+ * Return the number of bytes of output which are immediately available
+ * for output from the decompressor.
+ */
+int deflateOutputPending (strm)
+ z_streamp strm;
+{
+ if (strm == Z_NULL || strm->state == Z_NULL) return 0;
+
+ return ((deflate_state *)(strm->state))->pending;
+}
+
+/* ===========================================================================
+ * Read a new buffer from the current input stream, update the adler32
+ * and total number of bytes read. All deflate() input goes through
+ * this function so some applications may wish to modify it to avoid
+ * allocating a large strm->next_in buffer and copying from it.
+ * (See also flush_pending()).
+ */
+local int read_buf(strm, buf, size)
+ z_streamp strm;
+ charf *buf;
+ unsigned size;
+{
+ unsigned len = strm->avail_in;
+
+ if (len > size) len = size;
+ if (len == 0) return 0;
+
+ strm->avail_in -= len;
+
+ if (!((deflate_state *)(strm->state))->noheader) {
+ strm->adler = adler32(strm->adler, strm->next_in, len);
+ }
+ zmemcpy(buf, strm->next_in, len);
+ strm->next_in += len;
+ strm->total_in += len;
+
+ return (int)len;
+}
+
+/* ===========================================================================
+ * Initialize the "longest match" routines for a new zlib stream
+ */
+local void lm_init (s)
+ deflate_state *s;
+{
+ s->window_size = (ulg)2L*s->w_size;
+
+ CLEAR_HASH(s);
+
+ /* Set the default configuration parameters:
+ */
+ s->max_lazy_match = configuration_table[s->level].max_lazy;
+ s->good_match = configuration_table[s->level].good_length;
+ s->nice_match = configuration_table[s->level].nice_length;
+ s->max_chain_length = configuration_table[s->level].max_chain;
+
+ s->strstart = 0;
+ s->block_start = 0L;
+ s->lookahead = 0;
+ s->match_length = s->prev_length = MIN_MATCH-1;
+ s->match_available = 0;
+ s->ins_h = 0;
+#ifdef ASMV
+ match_init(); /* initialize the asm code */
+#endif
+}
+
+/* ===========================================================================
+ * Set match_start to the longest match starting at the given string and
+ * return its length. Matches shorter or equal to prev_length are discarded,
+ * in which case the result is equal to prev_length and match_start is
+ * garbage.
+ * IN assertions: cur_match is the head of the hash chain for the current
+ * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1
+ * OUT assertion: the match length is not greater than s->lookahead.
+ */
+#ifndef ASMV
+/* For 80x86 and 680x0, an optimized version will be provided in match.asm or
+ * match.S. The code will be functionally equivalent.
+ */
+local uInt longest_match(s, cur_match)
+ deflate_state *s;
+ IPos cur_match; /* current match */
+{
+ unsigned chain_length = s->max_chain_length;/* max hash chain length */
+ register Bytef *scan = s->window + s->strstart; /* current string */
+ register Bytef *match; /* matched string */
+ register int len; /* length of current match */
+ int best_len = s->prev_length; /* best match length so far */
+ int nice_match = s->nice_match; /* stop if match long enough */
+ IPos limit = s->strstart > (IPos)MAX_DIST(s) ?
+ s->strstart - (IPos)MAX_DIST(s) : NIL;
+ /* Stop when cur_match becomes <= limit. To simplify the code,
+ * we prevent matches with the string of window index 0.
+ */
+ Posf *prev = s->prev;
+ uInt wmask = s->w_mask;
+
+#ifdef UNALIGNED_OK
+ /* Compare two bytes at a time. Note: this is not always beneficial.
+ * Try with and without -DUNALIGNED_OK to check.
+ */
+ register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1;
+ register ush scan_start = *(ushf*)scan;
+ register ush scan_end = *(ushf*)(scan+best_len-1);
+#else
+ register Bytef *strend = s->window + s->strstart + MAX_MATCH;
+ register Byte scan_end1 = scan[best_len-1];
+ register Byte scan_end = scan[best_len];
+#endif
+
+ /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
+ * It is easy to get rid of this optimization if necessary.
+ */
+ Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever");
+
+ /* Do not waste too much time if we already have a good match: */
+ if (s->prev_length >= s->good_match) {
+ chain_length >>= 2;
+ }
+ /* Do not look for matches beyond the end of the input. This is necessary
+ * to make deflate deterministic.
+ */
+ if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead;
+
+ Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead");
+
+ do {
+ Assert(cur_match < s->strstart, "no future");
+ match = s->window + cur_match;
+
+ /* Skip to next match if the match length cannot increase
+ * or if the match length is less than 2:
+ */
+#if (defined(UNALIGNED_OK) && MAX_MATCH == 258)
+ /* This code assumes sizeof(unsigned short) == 2. Do not use
+ * UNALIGNED_OK if your compiler uses a different size.
+ */
+ if (*(ushf*)(match+best_len-1) != scan_end ||
+ *(ushf*)match != scan_start) continue;
+
+ /* It is not necessary to compare scan[2] and match[2] since they are
+ * always equal when the other bytes match, given that the hash keys
+ * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at
+ * strstart+3, +5, ... up to strstart+257. We check for insufficient
+ * lookahead only every 4th comparison; the 128th check will be made
+ * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is
+ * necessary to put more guard bytes at the end of the window, or
+ * to check more often for insufficient lookahead.
+ */
+ Assert(scan[2] == match[2], "scan[2]?");
+ scan++, match++;
+ do {
+ } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+ *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+ *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+ *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+ scan < strend);
+ /* The funny "do {}" generates better code on most compilers */
+
+ /* Here, scan <= window+strstart+257 */
+ Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
+ if (*scan == *match) scan++;
+
+ len = (MAX_MATCH - 1) - (int)(strend-scan);
+ scan = strend - (MAX_MATCH-1);
+
+#else /* UNALIGNED_OK */
+
+ if (match[best_len] != scan_end ||
+ match[best_len-1] != scan_end1 ||
+ *match != *scan ||
+ *++match != scan[1]) continue;
+
+ /* The check at best_len-1 can be removed because it will be made
+ * again later. (This heuristic is not always a win.)
+ * It is not necessary to compare scan[2] and match[2] since they
+ * are always equal when the other bytes match, given that
+ * the hash keys are equal and that HASH_BITS >= 8.
+ */
+ scan += 2, match++;
+ Assert(*scan == *match, "match[2]?");
+
+ /* We check for insufficient lookahead only every 8th comparison;
+ * the 256th check will be made at strstart+258.
+ */
+ do {
+ } while (*++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ scan < strend);
+
+ Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
+
+ len = MAX_MATCH - (int)(strend - scan);
+ scan = strend - MAX_MATCH;
+
+#endif /* UNALIGNED_OK */
+
+ if (len > best_len) {
+ s->match_start = cur_match;
+ best_len = len;
+ if (len >= nice_match) break;
+#ifdef UNALIGNED_OK
+ scan_end = *(ushf*)(scan+best_len-1);
+#else
+ scan_end1 = scan[best_len-1];
+ scan_end = scan[best_len];
+#endif
+ }
+ } while ((cur_match = prev[cur_match & wmask]) > limit
+ && --chain_length != 0);
+
+ if ((uInt)best_len <= s->lookahead) return best_len;
+ return s->lookahead;
+}
+#endif /* ASMV */
+
+#ifdef DEBUG_ZLIB
+/* ===========================================================================
+ * Check that the match at match_start is indeed a match.
+ */
+local void check_match(s, start, match, length)
+ deflate_state *s;
+ IPos start, match;
+ int length;
+{
+ /* check that the match is indeed a match */
+ if (zmemcmp((charf *)s->window + match,
+ (charf *)s->window + start, length) != EQUAL) {
+ fprintf(stderr, " start %u, match %u, length %d\n",
+ start, match, length);
+ do {
+ fprintf(stderr, "%c%c", s->window[match++], s->window[start++]);
+ } while (--length != 0);
+ z_error("invalid match");
+ }
+ if (z_verbose > 1) {
+ fprintf(stderr,"\\[%d,%d]", start-match, length);
+ do { putc(s->window[start++], stderr); } while (--length != 0);
+ }
+}
+#else
+# define check_match(s, start, match, length)
+#endif
+
+/* ===========================================================================
+ * Fill the window when the lookahead becomes insufficient.
+ * Updates strstart and lookahead.
+ *
+ * IN assertion: lookahead < MIN_LOOKAHEAD
+ * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD
+ * At least one byte has been read, or avail_in == 0; reads are
+ * performed for at least two bytes (required for the zip translate_eol
+ * option -- not supported here).
+ */
+local void fill_window(s)
+ deflate_state *s;
+{
+ register unsigned n, m;
+ register Posf *p;
+ unsigned more; /* Amount of free space at the end of the window. */
+ uInt wsize = s->w_size;
+
+ do {
+ more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart);
+
+ /* Deal with !@#$% 64K limit: */
+ if (more == 0 && s->strstart == 0 && s->lookahead == 0) {
+ more = wsize;
+
+ } else if (more == (unsigned)(-1)) {
+ /* Very unlikely, but possible on 16 bit machine if strstart == 0
+ * and lookahead == 1 (input done one byte at time)
+ */
+ more--;
+
+ /* If the window is almost full and there is insufficient lookahead,
+ * move the upper half to the lower one to make room in the upper half.
+ */
+ } else if (s->strstart >= wsize+MAX_DIST(s)) {
+
+ zmemcpy((charf *)s->window, (charf *)s->window+wsize,
+ (unsigned)wsize);
+ s->match_start -= wsize;
+ s->strstart -= wsize; /* we now have strstart >= MAX_DIST */
+ s->block_start -= (long) wsize;
+
+ /* Slide the hash table (could be avoided with 32 bit values
+ at the expense of memory usage). We slide even when level == 0
+ to keep the hash table consistent if we switch back to level > 0
+ later. (Using level 0 permanently is not an optimal usage of
+ zlib, so we don't care about this pathological case.)
+ */
+ n = s->hash_size;
+ p = &s->head[n];
+ do {
+ m = *--p;
+ *p = (Pos)(m >= wsize ? m-wsize : NIL);
+ } while (--n);
+
+ n = wsize;
+ p = &s->prev[n];
+ do {
+ m = *--p;
+ *p = (Pos)(m >= wsize ? m-wsize : NIL);
+ /* If n is not on any hash chain, prev[n] is garbage but
+ * its value will never be used.
+ */
+ } while (--n);
+ more += wsize;
+ }
+ if (s->strm->avail_in == 0) return;
+
+ /* If there was no sliding:
+ * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 &&
+ * more == window_size - lookahead - strstart
+ * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1)
+ * => more >= window_size - 2*WSIZE + 2
+ * In the BIG_MEM or MMAP case (not yet supported),
+ * window_size == input_size + MIN_LOOKAHEAD &&
+ * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD.
+ * Otherwise, window_size == 2*WSIZE so more >= 2.
+ * If there was sliding, more >= WSIZE. So in all cases, more >= 2.
+ */
+ Assert(more >= 2, "more < 2");
+
+ n = read_buf(s->strm, (charf *)s->window + s->strstart + s->lookahead,
+ more);
+ s->lookahead += n;
+
+ /* Initialize the hash value now that we have some input: */
+ if (s->lookahead >= MIN_MATCH) {
+ s->ins_h = s->window[s->strstart];
+ UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]);
+#if MIN_MATCH != 3
+ Call UPDATE_HASH() MIN_MATCH-3 more times
+#endif
+ }
+ /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage,
+ * but this is not important since only literal bytes will be emitted.
+ */
+
+ } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0);
+}
+
+/* ===========================================================================
+ * Flush the current block, with given end-of-file flag.
+ * IN assertion: strstart is set to the end of the current match.
+ */
+#define FLUSH_BLOCK_ONLY(s, eof) { \
+ _tr_flush_block(s, (s->block_start >= 0L ? \
+ (charf *)&s->window[(unsigned)s->block_start] : \
+ (charf *)Z_NULL), \
+ (ulg)((long)s->strstart - s->block_start), \
+ (eof)); \
+ s->block_start = s->strstart; \
+ flush_pending(s->strm); \
+ Tracev((stderr,"[FLUSH]")); \
+}
+
+/* Same but force premature exit if necessary. */
+#define FLUSH_BLOCK(s, eof) { \
+ FLUSH_BLOCK_ONLY(s, eof); \
+ if (s->strm->avail_out == 0) return (eof) ? finish_started : need_more; \
+}
+
+/* ===========================================================================
+ * Copy without compression as much as possible from the input stream, return
+ * the current block state.
+ * This function does not insert new strings in the dictionary since
+ * uncompressible data is probably not useful. This function is used
+ * only for the level=0 compression option.
+ * NOTE: this function should be optimized to avoid extra copying from
+ * window to pending_buf.
+ */
+local block_state deflate_stored(s, flush)
+ deflate_state *s;
+ int flush;
+{
+ /* Stored blocks are limited to 0xffff bytes, pending_buf is limited
+ * to pending_buf_size, and each stored block has a 5 byte header:
+ */
+ ulg max_block_size = 0xffff;
+ ulg max_start;
+
+ if (max_block_size > s->pending_buf_size - 5) {
+ max_block_size = s->pending_buf_size - 5;
+ }
+
+ /* Copy as much as possible from input to output: */
+ for (;;) {
+ /* Fill the window as much as possible: */
+ if (s->lookahead <= 1) {
+
+ Assert(s->strstart < s->w_size+MAX_DIST(s) ||
+ s->block_start >= (long)s->w_size, "slide too late");
+
+ fill_window(s);
+ if (s->lookahead == 0 && flush == Z_NO_FLUSH) return need_more;
+
+ if (s->lookahead == 0) break; /* flush the current block */
+ }
+ Assert(s->block_start >= 0L, "block gone");
+
+ s->strstart += s->lookahead;
+ s->lookahead = 0;
+
+ /* Emit a stored block if pending_buf will be full: */
+ max_start = s->block_start + max_block_size;
+ if (s->strstart == 0 || (ulg)s->strstart >= max_start) {
+ /* strstart == 0 is possible when wraparound on 16-bit machine */
+ s->lookahead = (uInt)(s->strstart - max_start);
+ s->strstart = (uInt)max_start;
+ FLUSH_BLOCK(s, 0);
+ }
+ /* Flush if we may have to slide, otherwise block_start may become
+ * negative and the data will be gone:
+ */
+ if (s->strstart - (uInt)s->block_start >= MAX_DIST(s)) {
+ FLUSH_BLOCK(s, 0);
+ }
+ }
+ FLUSH_BLOCK(s, flush == Z_FINISH);
+ return flush == Z_FINISH ? finish_done : block_done;
+}
+
+/* ===========================================================================
+ * Compress as much as possible from the input stream, return the current
+ * block state.
+ * This function does not perform lazy evaluation of matches and inserts
+ * new strings in the dictionary only for unmatched strings or for short
+ * matches. It is used only for the fast compression options.
+ */
+local block_state deflate_fast(s, flush)
+ deflate_state *s;
+ int flush;
+{
+ IPos hash_head = NIL; /* head of the hash chain */
+ int bflush; /* set if current block must be flushed */
+
+ for (;;) {
+ /* Make sure that we always have enough lookahead, except
+ * at the end of the input file. We need MAX_MATCH bytes
+ * for the next match, plus MIN_MATCH bytes to insert the
+ * string following the next match.
+ */
+ if (s->lookahead < MIN_LOOKAHEAD) {
+ fill_window(s);
+ if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {
+ return need_more;
+ }
+ if (s->lookahead == 0) break; /* flush the current block */
+ }
+
+ /* Insert the string window[strstart .. strstart+2] in the
+ * dictionary, and set hash_head to the head of the hash chain:
+ */
+ if (s->lookahead >= MIN_MATCH) {
+ INSERT_STRING(s, s->strstart, hash_head);
+ }
+
+ /* Find the longest match, discarding those <= prev_length.
+ * At this point we have always match_length < MIN_MATCH
+ */
+ if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) {
+ /* To simplify the code, we prevent matches with the string
+ * of window index 0 (in particular we have to avoid a match
+ * of the string with itself at the start of the input file).
+ */
+ if (s->strategy != Z_HUFFMAN_ONLY) {
+ s->match_length = longest_match (s, hash_head);
+ }
+ /* longest_match() sets match_start */
+ }
+ if (s->match_length >= MIN_MATCH) {
+ check_match(s, s->strstart, s->match_start, s->match_length);
+
+ bflush = _tr_tally(s, s->strstart - s->match_start,
+ s->match_length - MIN_MATCH);
+
+ s->lookahead -= s->match_length;
+
+ /* Insert new strings in the hash table only if the match length
+ * is not too large. This saves time but degrades compression.
+ */
+ if (s->match_length <= s->max_insert_length &&
+ s->lookahead >= MIN_MATCH) {
+ s->match_length--; /* string at strstart already in hash table */
+ do {
+ s->strstart++;
+ INSERT_STRING(s, s->strstart, hash_head);
+ /* strstart never exceeds WSIZE-MAX_MATCH, so there are
+ * always MIN_MATCH bytes ahead.
+ */
+ } while (--s->match_length != 0);
+ s->strstart++;
+ } else {
+ s->strstart += s->match_length;
+ s->match_length = 0;
+ s->ins_h = s->window[s->strstart];
+ UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]);
+#if MIN_MATCH != 3
+ Call UPDATE_HASH() MIN_MATCH-3 more times
+#endif
+ /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not
+ * matter since it will be recomputed at next deflate call.
+ */
+ }
+ } else {
+ /* No match, output a literal byte */
+ Tracevv((stderr,"%c", s->window[s->strstart]));
+ bflush = _tr_tally (s, 0, s->window[s->strstart]);
+ s->lookahead--;
+ s->strstart++;
+ }
+ if (bflush) FLUSH_BLOCK(s, 0);
+ }
+ FLUSH_BLOCK(s, flush == Z_FINISH);
+ return flush == Z_FINISH ? finish_done : block_done;
+}
+
+/* ===========================================================================
+ * Same as above, but achieves better compression. We use a lazy
+ * evaluation for matches: a match is finally adopted only if there is
+ * no better match at the next window position.
+ */
+local block_state deflate_slow(s, flush)
+ deflate_state *s;
+ int flush;
+{
+ IPos hash_head = NIL; /* head of hash chain */
+ int bflush; /* set if current block must be flushed */
+
+ /* Process the input block. */
+ for (;;) {
+ /* Make sure that we always have enough lookahead, except
+ * at the end of the input file. We need MAX_MATCH bytes
+ * for the next match, plus MIN_MATCH bytes to insert the
+ * string following the next match.
+ */
+ if (s->lookahead < MIN_LOOKAHEAD) {
+ fill_window(s);
+ if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {
+ return need_more;
+ }
+ if (s->lookahead == 0) break; /* flush the current block */
+ }
+
+ /* Insert the string window[strstart .. strstart+2] in the
+ * dictionary, and set hash_head to the head of the hash chain:
+ */
+ if (s->lookahead >= MIN_MATCH) {
+ INSERT_STRING(s, s->strstart, hash_head);
+ }
+
+ /* Find the longest match, discarding those <= prev_length.
+ */
+ s->prev_length = s->match_length, s->prev_match = s->match_start;
+ s->match_length = MIN_MATCH-1;
+
+ if (hash_head != NIL && s->prev_length < s->max_lazy_match &&
+ s->strstart - hash_head <= MAX_DIST(s)) {
+ /* To simplify the code, we prevent matches with the string
+ * of window index 0 (in particular we have to avoid a match
+ * of the string with itself at the start of the input file).
+ */
+ if (s->strategy != Z_HUFFMAN_ONLY) {
+ s->match_length = longest_match (s, hash_head);
+ }
+ /* longest_match() sets match_start */
+
+ if (s->match_length <= 5 && (s->strategy == Z_FILTERED ||
+ (s->match_length == MIN_MATCH &&
+ s->strstart - s->match_start > TOO_FAR))) {
+
+ /* If prev_match is also MIN_MATCH, match_start is garbage
+ * but we will ignore the current match anyway.
+ */
+ s->match_length = MIN_MATCH-1;
+ }
+ }
+ /* If there was a match at the previous step and the current
+ * match is not better, output the previous match:
+ */
+ if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) {
+ uInt max_insert = s->strstart + s->lookahead - MIN_MATCH;
+ /* Do not insert strings in hash table beyond this. */
+
+ check_match(s, s->strstart-1, s->prev_match, s->prev_length);
+
+ bflush = _tr_tally(s, s->strstart -1 - s->prev_match,
+ s->prev_length - MIN_MATCH);
+
+ /* Insert in hash table all strings up to the end of the match.
+ * strstart-1 and strstart are already inserted. If there is not
+ * enough lookahead, the last two strings are not inserted in
+ * the hash table.
+ */
+ s->lookahead -= s->prev_length-1;
+ s->prev_length -= 2;
+ do {
+ if (++s->strstart <= max_insert) {
+ INSERT_STRING(s, s->strstart, hash_head);
+ }
+ } while (--s->prev_length != 0);
+ s->match_available = 0;
+ s->match_length = MIN_MATCH-1;
+ s->strstart++;
+
+ if (bflush) FLUSH_BLOCK(s, 0);
+
+ } else if (s->match_available) {
+ /* If there was no match at the previous position, output a
+ * single literal. If there was a match but the current match
+ * is longer, truncate the previous match to a single literal.
+ */
+ Tracevv((stderr,"%c", s->window[s->strstart-1]));
+ if (_tr_tally (s, 0, s->window[s->strstart-1])) {
+ FLUSH_BLOCK_ONLY(s, 0);
+ }
+ s->strstart++;
+ s->lookahead--;
+ if (s->strm->avail_out == 0) return need_more;
+ } else {
+ /* There is no previous match to compare with, wait for
+ * the next step to decide.
+ */
+ s->match_available = 1;
+ s->strstart++;
+ s->lookahead--;
+ }
+ }
+ Assert (flush != Z_NO_FLUSH, "no flush?");
+ if (s->match_available) {
+ Tracevv((stderr,"%c", s->window[s->strstart-1]));
+ _tr_tally (s, 0, s->window[s->strstart-1]);
+ s->match_available = 0;
+ }
+ FLUSH_BLOCK(s, flush == Z_FINISH);
+ return flush == Z_FINISH ? finish_done : block_done;
+}
+/* --- deflate.c */
+
+/* +++ trees.c */
+/* trees.c -- output deflated data using Huffman coding
+ * Copyright (C) 1995-1996 Jean-loup Gailly
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/*
+ * ALGORITHM
+ *
+ * The "deflation" process uses several Huffman trees. The more
+ * common source values are represented by shorter bit sequences.
+ *
+ * Each code tree is stored in a compressed form which is itself
+ * a Huffman encoding of the lengths of all the code strings (in
+ * ascending order by source values). The actual code strings are
+ * reconstructed from the lengths in the inflate process, as described
+ * in the deflate specification.
+ *
+ * REFERENCES
+ *
+ * Deutsch, L.P.,"'Deflate' Compressed Data Format Specification".
+ * Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc
+ *
+ * Storer, James A.
+ * Data Compression: Methods and Theory, pp. 49-50.
+ * Computer Science Press, 1988. ISBN 0-7167-8156-5.
+ *
+ * Sedgewick, R.
+ * Algorithms, p290.
+ * Addison-Wesley, 1983. ISBN 0-201-06672-6.
+ */
+
+/* From: trees.c,v 1.11 1996/07/24 13:41:06 me Exp $ */
+
+/* #include "deflate.h" */
+
+#ifdef DEBUG_ZLIB
+# include <ctype.h>
+#endif
+
+/* ===========================================================================
+ * Constants
+ */
+
+#define MAX_BL_BITS 7
+/* Bit length codes must not exceed MAX_BL_BITS bits */
+
+#define END_BLOCK 256
+/* end of block literal code */
+
+#define REP_3_6 16
+/* repeat previous bit length 3-6 times (2 bits of repeat count) */
+
+#define REPZ_3_10 17
+/* repeat a zero length 3-10 times (3 bits of repeat count) */
+
+#define REPZ_11_138 18
+/* repeat a zero length 11-138 times (7 bits of repeat count) */
+
+local int extra_lbits[LENGTH_CODES] /* extra bits for each length code */
+ = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0};
+
+local int extra_dbits[D_CODES] /* extra bits for each distance code */
+ = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13};
+
+local int extra_blbits[BL_CODES]/* extra bits for each bit length code */
+ = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7};
+
+local uch bl_order[BL_CODES]
+ = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15};
+/* The lengths of the bit length codes are sent in order of decreasing
+ * probability, to avoid transmitting the lengths for unused bit length codes.
+ */
+
+#define Buf_size (8 * 2*sizeof(char))
+/* Number of bits used within bi_buf. (bi_buf might be implemented on
+ * more than 16 bits on some systems.)
+ */
+
+/* ===========================================================================
+ * Local data. These are initialized only once.
+ */
+
+local ct_data static_ltree[L_CODES+2];
+/* The static literal tree. Since the bit lengths are imposed, there is no
+ * need for the L_CODES extra codes used during heap construction. However
+ * The codes 286 and 287 are needed to build a canonical tree (see _tr_init
+ * below).
+ */
+
+local ct_data static_dtree[D_CODES];
+/* The static distance tree. (Actually a trivial tree since all codes use
+ * 5 bits.)
+ */
+
+local uch dist_code[512];
+/* distance codes. The first 256 values correspond to the distances
+ * 3 .. 258, the last 256 values correspond to the top 8 bits of
+ * the 15 bit distances.
+ */
+
+local uch length_code[MAX_MATCH-MIN_MATCH+1];
+/* length code for each normalized match length (0 == MIN_MATCH) */
+
+local int base_length[LENGTH_CODES];
+/* First normalized length for each code (0 = MIN_MATCH) */
+
+local int base_dist[D_CODES];
+/* First normalized distance for each code (0 = distance of 1) */
+
+struct static_tree_desc_s {
+ ct_data *static_tree; /* static tree or NULL */
+ intf *extra_bits; /* extra bits for each code or NULL */
+ int extra_base; /* base index for extra_bits */
+ int elems; /* max number of elements in the tree */
+ int max_length; /* max bit length for the codes */
+};
+
+local static_tree_desc static_l_desc =
+{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS};
+
+local static_tree_desc static_d_desc =
+{static_dtree, extra_dbits, 0, D_CODES, MAX_BITS};
+
+local static_tree_desc static_bl_desc =
+{(ct_data *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS};
+
+/* ===========================================================================
+ * Local (static) routines in this file.
+ */
+
+local void tr_static_init OF((void));
+local void init_block OF((deflate_state *s));
+local void pqdownheap OF((deflate_state *s, ct_data *tree, int k));
+local void gen_bitlen OF((deflate_state *s, tree_desc *desc));
+local void gen_codes OF((ct_data *tree, int max_code, ushf *bl_count));
+local void build_tree OF((deflate_state *s, tree_desc *desc));
+local void scan_tree OF((deflate_state *s, ct_data *tree, int max_code));
+local void send_tree OF((deflate_state *s, ct_data *tree, int max_code));
+local int build_bl_tree OF((deflate_state *s));
+local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes,
+ int blcodes));
+local void compress_block OF((deflate_state *s, ct_data *ltree,
+ ct_data *dtree));
+local void set_data_type OF((deflate_state *s));
+local unsigned bi_reverse OF((unsigned value, int length));
+local void bi_windup OF((deflate_state *s));
+local void bi_flush OF((deflate_state *s));
+local void copy_block OF((deflate_state *s, charf *buf, unsigned len,
+ int header));
+
+#ifndef DEBUG_ZLIB
+# define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len)
+ /* Send a code of the given tree. c and tree must not have side effects */
+
+#else /* DEBUG_ZLIB */
+# define send_code(s, c, tree) \
+ { if (verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \
+ send_bits(s, tree[c].Code, tree[c].Len); }
+#endif
+
+#define d_code(dist) \
+ ((dist) < 256 ? dist_code[dist] : dist_code[256+((dist)>>7)])
+/* Mapping from a distance to a distance code. dist is the distance - 1 and
+ * must not have side effects. dist_code[256] and dist_code[257] are never
+ * used.
+ */
+
+/* ===========================================================================
+ * Output a short LSB first on the stream.
+ * IN assertion: there is enough room in pendingBuf.
+ */
+#define put_short(s, w) { \
+ put_byte(s, (uch)((w) & 0xff)); \
+ put_byte(s, (uch)((ush)(w) >> 8)); \
+}
+
+/* ===========================================================================
+ * Send a value on a given number of bits.
+ * IN assertion: length <= 16 and value fits in length bits.
+ */
+#ifdef DEBUG_ZLIB
+local void send_bits OF((deflate_state *s, int value, int length));
+
+local void send_bits(s, value, length)
+ deflate_state *s;
+ int value; /* value to send */
+ int length; /* number of bits */
+{
+ Tracevv((stderr," l %2d v %4x ", length, value));
+ Assert(length > 0 && length <= 15, "invalid length");
+ s->bits_sent += (ulg)length;
+
+ /* If not enough room in bi_buf, use (valid) bits from bi_buf and
+ * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid))
+ * unused bits in value.
+ */
+ if (s->bi_valid > (int)Buf_size - length) {
+ s->bi_buf |= (value << s->bi_valid);
+ put_short(s, s->bi_buf);
+ s->bi_buf = (ush)value >> (Buf_size - s->bi_valid);
+ s->bi_valid += length - Buf_size;
+ } else {
+ s->bi_buf |= value << s->bi_valid;
+ s->bi_valid += length;
+ }
+}
+#else /* !DEBUG_ZLIB */
+
+#define send_bits(s, value, length) \
+{ int len = length;\
+ if (s->bi_valid > (int)Buf_size - len) {\
+ int val = value;\
+ s->bi_buf |= (val << s->bi_valid);\
+ put_short(s, s->bi_buf);\
+ s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\
+ s->bi_valid += len - Buf_size;\
+ } else {\
+ s->bi_buf |= (value) << s->bi_valid;\
+ s->bi_valid += len;\
+ }\
+}
+#endif /* DEBUG_ZLIB */
+
+
+#define MAX(a,b) (a >= b ? a : b)
+/* the arguments must not have side effects */
+
+/* ===========================================================================
+ * Initialize the various 'constant' tables. In a multi-threaded environment,
+ * this function may be called by two threads concurrently, but this is
+ * harmless since both invocations do exactly the same thing.
+ */
+local void tr_static_init()
+{
+ static int static_init_done = 0;
+ int n; /* iterates over tree elements */
+ int bits; /* bit counter */
+ int length; /* length value */
+ int code; /* code value */
+ int dist; /* distance index */
+ ush bl_count[MAX_BITS+1];
+ /* number of codes at each bit length for an optimal tree */
+
+ if (static_init_done) return;
+
+ /* Initialize the mapping length (0..255) -> length code (0..28) */
+ length = 0;
+ for (code = 0; code < LENGTH_CODES-1; code++) {
+ base_length[code] = length;
+ for (n = 0; n < (1<<extra_lbits[code]); n++) {
+ length_code[length++] = (uch)code;
+ }
+ }
+ Assert (length == 256, "tr_static_init: length != 256");
+ /* Note that the length 255 (match length 258) can be represented
+ * in two different ways: code 284 + 5 bits or code 285, so we
+ * overwrite length_code[255] to use the best encoding:
+ */
+ length_code[length-1] = (uch)code;
+
+ /* Initialize the mapping dist (0..32K) -> dist code (0..29) */
+ dist = 0;
+ for (code = 0 ; code < 16; code++) {
+ base_dist[code] = dist;
+ for (n = 0; n < (1<<extra_dbits[code]); n++) {
+ dist_code[dist++] = (uch)code;
+ }
+ }
+ Assert (dist == 256, "tr_static_init: dist != 256");
+ dist >>= 7; /* from now on, all distances are divided by 128 */
+ for ( ; code < D_CODES; code++) {
+ base_dist[code] = dist << 7;
+ for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) {
+ dist_code[256 + dist++] = (uch)code;
+ }
+ }
+ Assert (dist == 256, "tr_static_init: 256+dist != 512");
+
+ /* Construct the codes of the static literal tree */
+ for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0;
+ n = 0;
+ while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++;
+ while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++;
+ while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++;
+ while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++;
+ /* Codes 286 and 287 do not exist, but we must include them in the
+ * tree construction to get a canonical Huffman tree (longest code
+ * all ones)
+ */
+ gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count);
+
+ /* The static distance tree is trivial: */
+ for (n = 0; n < D_CODES; n++) {
+ static_dtree[n].Len = 5;
+ static_dtree[n].Code = bi_reverse((unsigned)n, 5);
+ }
+ static_init_done = 1;
+}
+
+/* ===========================================================================
+ * Initialize the tree data structures for a new zlib stream.
+ */
+void _tr_init(s)
+ deflate_state *s;
+{
+ tr_static_init();
+
+ s->compressed_len = 0L;
+
+ s->l_desc.dyn_tree = s->dyn_ltree;
+ s->l_desc.stat_desc = &static_l_desc;
+
+ s->d_desc.dyn_tree = s->dyn_dtree;
+ s->d_desc.stat_desc = &static_d_desc;
+
+ s->bl_desc.dyn_tree = s->bl_tree;
+ s->bl_desc.stat_desc = &static_bl_desc;
+
+ s->bi_buf = 0;
+ s->bi_valid = 0;
+ s->last_eob_len = 8; /* enough lookahead for inflate */
+#ifdef DEBUG_ZLIB
+ s->bits_sent = 0L;
+#endif
+
+ /* Initialize the first block of the first file: */
+ init_block(s);
+}
+
+/* ===========================================================================
+ * Initialize a new block.
+ */
+local void init_block(s)
+ deflate_state *s;
+{
+ int n; /* iterates over tree elements */
+
+ /* Initialize the trees. */
+ for (n = 0; n < L_CODES; n++) s->dyn_ltree[n].Freq = 0;
+ for (n = 0; n < D_CODES; n++) s->dyn_dtree[n].Freq = 0;
+ for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0;
+
+ s->dyn_ltree[END_BLOCK].Freq = 1;
+ s->opt_len = s->static_len = 0L;
+ s->last_lit = s->matches = 0;
+}
+
+#define SMALLEST 1
+/* Index within the heap array of least frequent node in the Huffman tree */
+
+
+/* ===========================================================================
+ * Remove the smallest element from the heap and recreate the heap with
+ * one less element. Updates heap and heap_len.
+ */
+#define pqremove(s, tree, top) \
+{\
+ top = s->heap[SMALLEST]; \
+ s->heap[SMALLEST] = s->heap[s->heap_len--]; \
+ pqdownheap(s, tree, SMALLEST); \
+}
+
+/* ===========================================================================
+ * Compares to subtrees, using the tree depth as tie breaker when
+ * the subtrees have equal frequency. This minimizes the worst case length.
+ */
+#define smaller(tree, n, m, depth) \
+ (tree[n].Freq < tree[m].Freq || \
+ (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m]))
+
+/* ===========================================================================
+ * Restore the heap property by moving down the tree starting at node k,
+ * exchanging a node with the smallest of its two sons if necessary, stopping
+ * when the heap property is re-established (each father smaller than its
+ * two sons).
+ */
+local void pqdownheap(s, tree, k)
+ deflate_state *s;
+ ct_data *tree; /* the tree to restore */
+ int k; /* node to move down */
+{
+ int v = s->heap[k];
+ int j = k << 1; /* left son of k */
+ while (j <= s->heap_len) {
+ /* Set j to the smallest of the two sons: */
+ if (j < s->heap_len &&
+ smaller(tree, s->heap[j+1], s->heap[j], s->depth)) {
+ j++;
+ }
+ /* Exit if v is smaller than both sons */
+ if (smaller(tree, v, s->heap[j], s->depth)) break;
+
+ /* Exchange v with the smallest son */
+ s->heap[k] = s->heap[j]; k = j;
+
+ /* And continue down the tree, setting j to the left son of k */
+ j <<= 1;
+ }
+ s->heap[k] = v;
+}
+
+/* ===========================================================================
+ * Compute the optimal bit lengths for a tree and update the total bit length
+ * for the current block.
+ * IN assertion: the fields freq and dad are set, heap[heap_max] and
+ * above are the tree nodes sorted by increasing frequency.
+ * OUT assertions: the field len is set to the optimal bit length, the
+ * array bl_count contains the frequencies for each bit length.
+ * The length opt_len is updated; static_len is also updated if stree is
+ * not null.
+ */
+local void gen_bitlen(s, desc)
+ deflate_state *s;
+ tree_desc *desc; /* the tree descriptor */
+{
+ ct_data *tree = desc->dyn_tree;
+ int max_code = desc->max_code;
+ ct_data *stree = desc->stat_desc->static_tree;
+ intf *extra = desc->stat_desc->extra_bits;
+ int base = desc->stat_desc->extra_base;
+ int max_length = desc->stat_desc->max_length;
+ int h; /* heap index */
+ int n, m; /* iterate over the tree elements */
+ int bits; /* bit length */
+ int xbits; /* extra bits */
+ ush f; /* frequency */
+ int overflow = 0; /* number of elements with bit length too large */
+
+ for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0;
+
+ /* In a first pass, compute the optimal bit lengths (which may
+ * overflow in the case of the bit length tree).
+ */
+ tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */
+
+ for (h = s->heap_max+1; h < HEAP_SIZE; h++) {
+ n = s->heap[h];
+ bits = tree[tree[n].Dad].Len + 1;
+ if (bits > max_length) bits = max_length, overflow++;
+ tree[n].Len = (ush)bits;
+ /* We overwrite tree[n].Dad which is no longer needed */
+
+ if (n > max_code) continue; /* not a leaf node */
+
+ s->bl_count[bits]++;
+ xbits = 0;
+ if (n >= base) xbits = extra[n-base];
+ f = tree[n].Freq;
+ s->opt_len += (ulg)f * (bits + xbits);
+ if (stree) s->static_len += (ulg)f * (stree[n].Len + xbits);
+ }
+ if (overflow == 0) return;
+
+ Trace((stderr,"\nbit length overflow\n"));
+ /* This happens for example on obj2 and pic of the Calgary corpus */
+
+ /* Find the first bit length which could increase: */
+ do {
+ bits = max_length-1;
+ while (s->bl_count[bits] == 0) bits--;
+ s->bl_count[bits]--; /* move one leaf down the tree */
+ s->bl_count[bits+1] += 2; /* move one overflow item as its brother */
+ s->bl_count[max_length]--;
+ /* The brother of the overflow item also moves one step up,
+ * but this does not affect bl_count[max_length]
+ */
+ overflow -= 2;
+ } while (overflow > 0);
+
+ /* Now recompute all bit lengths, scanning in increasing frequency.
+ * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all
+ * lengths instead of fixing only the wrong ones. This idea is taken
+ * from 'ar' written by Haruhiko Okumura.)
+ */
+ for (bits = max_length; bits != 0; bits--) {
+ n = s->bl_count[bits];
+ while (n != 0) {
+ m = s->heap[--h];
+ if (m > max_code) continue;
+ if (tree[m].Len != (unsigned) bits) {
+ Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits));
+ s->opt_len += ((long)bits - (long)tree[m].Len)
+ *(long)tree[m].Freq;
+ tree[m].Len = (ush)bits;
+ }
+ n--;
+ }
+ }
+}
+
+/* ===========================================================================
+ * Generate the codes for a given tree and bit counts (which need not be
+ * optimal).
+ * IN assertion: the array bl_count contains the bit length statistics for
+ * the given tree and the field len is set for all tree elements.
+ * OUT assertion: the field code is set for all tree elements of non
+ * zero code length.
+ */
+local void gen_codes (tree, max_code, bl_count)
+ ct_data *tree; /* the tree to decorate */
+ int max_code; /* largest code with non zero frequency */
+ ushf *bl_count; /* number of codes at each bit length */
+{
+ ush next_code[MAX_BITS+1]; /* next code value for each bit length */
+ ush code = 0; /* running code value */
+ int bits; /* bit index */
+ int n; /* code index */
+
+ /* The distribution counts are first used to generate the code values
+ * without bit reversal.
+ */
+ for (bits = 1; bits <= MAX_BITS; bits++) {
+ next_code[bits] = code = (code + bl_count[bits-1]) << 1;
+ }
+ /* Check that the bit counts in bl_count are consistent. The last code
+ * must be all ones.
+ */
+ Assert (code + bl_count[MAX_BITS]-1 == (1<<MAX_BITS)-1,
+ "inconsistent bit counts");
+ Tracev((stderr,"\ngen_codes: max_code %d ", max_code));
+
+ for (n = 0; n <= max_code; n++) {
+ int len = tree[n].Len;
+ if (len == 0) continue;
+ /* Now reverse the bits */
+ tree[n].Code = bi_reverse(next_code[len]++, len);
+
+ Tracecv(tree != static_ltree, (stderr,"\nn %3d %c l %2d c %4x (%x) ",
+ n, (isgraph(n) ? n : ' '), len, tree[n].Code, next_code[len]-1));
+ }
+}
+
+/* ===========================================================================
+ * Construct one Huffman tree and assigns the code bit strings and lengths.
+ * Update the total bit length for the current block.
+ * IN assertion: the field freq is set for all tree elements.
+ * OUT assertions: the fields len and code are set to the optimal bit length
+ * and corresponding code. The length opt_len is updated; static_len is
+ * also updated if stree is not null. The field max_code is set.
+ */
+local void build_tree(s, desc)
+ deflate_state *s;
+ tree_desc *desc; /* the tree descriptor */
+{
+ ct_data *tree = desc->dyn_tree;
+ ct_data *stree = desc->stat_desc->static_tree;
+ int elems = desc->stat_desc->elems;
+ int n, m; /* iterate over heap elements */
+ int max_code = -1; /* largest code with non zero frequency */
+ int node; /* new node being created */
+
+ /* Construct the initial heap, with least frequent element in
+ * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1].
+ * heap[0] is not used.
+ */
+ s->heap_len = 0, s->heap_max = HEAP_SIZE;
+
+ for (n = 0; n < elems; n++) {
+ if (tree[n].Freq != 0) {
+ s->heap[++(s->heap_len)] = max_code = n;
+ s->depth[n] = 0;
+ } else {
+ tree[n].Len = 0;
+ }
+ }
+
+ /* The pkzip format requires that at least one distance code exists,
+ * and that at least one bit should be sent even if there is only one
+ * possible code. So to avoid special checks later on we force at least
+ * two codes of non zero frequency.
+ */
+ while (s->heap_len < 2) {
+ node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0);
+ tree[node].Freq = 1;
+ s->depth[node] = 0;
+ s->opt_len--; if (stree) s->static_len -= stree[node].Len;
+ /* node is 0 or 1 so it does not have extra bits */
+ }
+ desc->max_code = max_code;
+
+ /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree,
+ * establish sub-heaps of increasing lengths:
+ */
+ for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n);
+
+ /* Construct the Huffman tree by repeatedly combining the least two
+ * frequent nodes.
+ */
+ node = elems; /* next internal node of the tree */
+ do {
+ pqremove(s, tree, n); /* n = node of least frequency */
+ m = s->heap[SMALLEST]; /* m = node of next least frequency */
+
+ s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */
+ s->heap[--(s->heap_max)] = m;
+
+ /* Create a new node father of n and m */
+ tree[node].Freq = tree[n].Freq + tree[m].Freq;
+ s->depth[node] = (uch) (MAX(s->depth[n], s->depth[m]) + 1);
+ tree[n].Dad = tree[m].Dad = (ush)node;
+#ifdef DUMP_BL_TREE
+ if (tree == s->bl_tree) {
+ fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)",
+ node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq);
+ }
+#endif
+ /* and insert the new node in the heap */
+ s->heap[SMALLEST] = node++;
+ pqdownheap(s, tree, SMALLEST);
+
+ } while (s->heap_len >= 2);
+
+ s->heap[--(s->heap_max)] = s->heap[SMALLEST];
+
+ /* At this point, the fields freq and dad are set. We can now
+ * generate the bit lengths.
+ */
+ gen_bitlen(s, (tree_desc *)desc);
+
+ /* The field len is now set, we can generate the bit codes */
+ gen_codes ((ct_data *)tree, max_code, s->bl_count);
+}
+
+/* ===========================================================================
+ * Scan a literal or distance tree to determine the frequencies of the codes
+ * in the bit length tree.
+ */
+local void scan_tree (s, tree, max_code)
+ deflate_state *s;
+ ct_data *tree; /* the tree to be scanned */
+ int max_code; /* and its largest code of non zero frequency */
+{
+ int n; /* iterates over all tree elements */
+ int prevlen = -1; /* last emitted length */
+ int curlen; /* length of current code */
+ int nextlen = tree[0].Len; /* length of next code */
+ int count = 0; /* repeat count of the current code */
+ int max_count = 7; /* max repeat count */
+ int min_count = 4; /* min repeat count */
+
+ if (nextlen == 0) max_count = 138, min_count = 3;
+ tree[max_code+1].Len = (ush)0xffff; /* guard */
+
+ for (n = 0; n <= max_code; n++) {
+ curlen = nextlen; nextlen = tree[n+1].Len;
+ if (++count < max_count && curlen == nextlen) {
+ continue;
+ } else if (count < min_count) {
+ s->bl_tree[curlen].Freq += count;
+ } else if (curlen != 0) {
+ if (curlen != prevlen) s->bl_tree[curlen].Freq++;
+ s->bl_tree[REP_3_6].Freq++;
+ } else if (count <= 10) {
+ s->bl_tree[REPZ_3_10].Freq++;
+ } else {
+ s->bl_tree[REPZ_11_138].Freq++;
+ }
+ count = 0; prevlen = curlen;
+ if (nextlen == 0) {
+ max_count = 138, min_count = 3;
+ } else if (curlen == nextlen) {
+ max_count = 6, min_count = 3;
+ } else {
+ max_count = 7, min_count = 4;
+ }
+ }
+}
+
+/* ===========================================================================
+ * Send a literal or distance tree in compressed form, using the codes in
+ * bl_tree.
+ */
+local void send_tree (s, tree, max_code)
+ deflate_state *s;
+ ct_data *tree; /* the tree to be scanned */
+ int max_code; /* and its largest code of non zero frequency */
+{
+ int n; /* iterates over all tree elements */
+ int prevlen = -1; /* last emitted length */
+ int curlen; /* length of current code */
+ int nextlen = tree[0].Len; /* length of next code */
+ int count = 0; /* repeat count of the current code */
+ int max_count = 7; /* max repeat count */
+ int min_count = 4; /* min repeat count */
+
+ /* tree[max_code+1].Len = -1; */ /* guard already set */
+ if (nextlen == 0) max_count = 138, min_count = 3;
+
+ for (n = 0; n <= max_code; n++) {
+ curlen = nextlen; nextlen = tree[n+1].Len;
+ if (++count < max_count && curlen == nextlen) {
+ continue;
+ } else if (count < min_count) {
+ do { send_code(s, curlen, s->bl_tree); } while (--count != 0);
+
+ } else if (curlen != 0) {
+ if (curlen != prevlen) {
+ send_code(s, curlen, s->bl_tree); count--;
+ }
+ Assert(count >= 3 && count <= 6, " 3_6?");
+ send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2);
+
+ } else if (count <= 10) {
+ send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3);
+
+ } else {
+ send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7);
+ }
+ count = 0; prevlen = curlen;
+ if (nextlen == 0) {
+ max_count = 138, min_count = 3;
+ } else if (curlen == nextlen) {
+ max_count = 6, min_count = 3;
+ } else {
+ max_count = 7, min_count = 4;
+ }
+ }
+}
+
+/* ===========================================================================
+ * Construct the Huffman tree for the bit lengths and return the index in
+ * bl_order of the last bit length code to send.
+ */
+local int build_bl_tree(s)
+ deflate_state *s;
+{
+ int max_blindex; /* index of last bit length code of non zero freq */
+
+ /* Determine the bit length frequencies for literal and distance trees */
+ scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code);
+ scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code);
+
+ /* Build the bit length tree: */
+ build_tree(s, (tree_desc *)(&(s->bl_desc)));
+ /* opt_len now includes the length of the tree representations, except
+ * the lengths of the bit lengths codes and the 5+5+4 bits for the counts.
+ */
+
+ /* Determine the number of bit length codes to send. The pkzip format
+ * requires that at least 4 bit length codes be sent. (appnote.txt says
+ * 3 but the actual value used is 4.)
+ */
+ for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) {
+ if (s->bl_tree[bl_order[max_blindex]].Len != 0) break;
+ }
+ /* Update opt_len to include the bit length tree and counts */
+ s->opt_len += 3*(max_blindex+1) + 5+5+4;
+ Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld",
+ s->opt_len, s->static_len));
+
+ return max_blindex;
+}
+
+/* ===========================================================================
+ * Send the header for a block using dynamic Huffman trees: the counts, the
+ * lengths of the bit length codes, the literal tree and the distance tree.
+ * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4.
+ */
+local void send_all_trees(s, lcodes, dcodes, blcodes)
+ deflate_state *s;
+ int lcodes, dcodes, blcodes; /* number of codes for each tree */
+{
+ int rank; /* index in bl_order */
+
+ Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes");
+ Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES,
+ "too many codes");
+ Tracev((stderr, "\nbl counts: "));
+ send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */
+ send_bits(s, dcodes-1, 5);
+ send_bits(s, blcodes-4, 4); /* not -3 as stated in appnote.txt */
+ for (rank = 0; rank < blcodes; rank++) {
+ Tracev((stderr, "\nbl code %2d ", bl_order[rank]));
+ send_bits(s, s->bl_tree[bl_order[rank]].Len, 3);
+ }
+ Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent));
+
+ send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */
+ Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent));
+
+ send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */
+ Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent));
+}
+
+/* ===========================================================================
+ * Send a stored block
+ */
+void _tr_stored_block(s, buf, stored_len, eof)
+ deflate_state *s;
+ charf *buf; /* input block */
+ ulg stored_len; /* length of input block */
+ int eof; /* true if this is the last block for a file */
+{
+ send_bits(s, (STORED_BLOCK<<1)+eof, 3); /* send block type */
+ s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L;
+ s->compressed_len += (stored_len + 4) << 3;
+
+ copy_block(s, buf, (unsigned)stored_len, 1); /* with header */
+}
+
+/* Send just the `stored block' type code without any length bytes or data.
+ */
+void _tr_stored_type_only(s)
+ deflate_state *s;
+{
+ send_bits(s, (STORED_BLOCK << 1), 3);
+ bi_windup(s);
+ s->compressed_len = (s->compressed_len + 3) & ~7L;
+}
+
+
+/* ===========================================================================
+ * Send one empty static block to give enough lookahead for inflate.
+ * This takes 10 bits, of which 7 may remain in the bit buffer.
+ * The current inflate code requires 9 bits of lookahead. If the
+ * last two codes for the previous block (real code plus EOB) were coded
+ * on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode
+ * the last real code. In this case we send two empty static blocks instead
+ * of one. (There are no problems if the previous block is stored or fixed.)
+ * To simplify the code, we assume the worst case of last real code encoded
+ * on one bit only.
+ */
+void _tr_align(s)
+ deflate_state *s;
+{
+ send_bits(s, STATIC_TREES<<1, 3);
+ send_code(s, END_BLOCK, static_ltree);
+ s->compressed_len += 10L; /* 3 for block type, 7 for EOB */
+ bi_flush(s);
+ /* Of the 10 bits for the empty block, we have already sent
+ * (10 - bi_valid) bits. The lookahead for the last real code (before
+ * the EOB of the previous block) was thus at least one plus the length
+ * of the EOB plus what we have just sent of the empty static block.
+ */
+ if (1 + s->last_eob_len + 10 - s->bi_valid < 9) {
+ send_bits(s, STATIC_TREES<<1, 3);
+ send_code(s, END_BLOCK, static_ltree);
+ s->compressed_len += 10L;
+ bi_flush(s);
+ }
+ s->last_eob_len = 7;
+}
+
+/* ===========================================================================
+ * Determine the best encoding for the current block: dynamic trees, static
+ * trees or store, and output the encoded block to the zip file. This function
+ * returns the total compressed length for the file so far.
+ */
+ulg _tr_flush_block(s, buf, stored_len, eof)
+ deflate_state *s;
+ charf *buf; /* input block, or NULL if too old */
+ ulg stored_len; /* length of input block */
+ int eof; /* true if this is the last block for a file */
+{
+ ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */
+ int max_blindex = 0; /* index of last bit length code of non zero freq */
+
+ /* Build the Huffman trees unless a stored block is forced */
+ if (s->level > 0) {
+
+ /* Check if the file is ascii or binary */
+ if (s->data_type == Z_UNKNOWN) set_data_type(s);
+
+ /* Construct the literal and distance trees */
+ build_tree(s, (tree_desc *)(&(s->l_desc)));
+ Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len,
+ s->static_len));
+
+ build_tree(s, (tree_desc *)(&(s->d_desc)));
+ Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len,
+ s->static_len));
+ /* At this point, opt_len and static_len are the total bit lengths of
+ * the compressed block data, excluding the tree representations.
+ */
+
+ /* Build the bit length tree for the above two trees, and get the index
+ * in bl_order of the last bit length code to send.
+ */
+ max_blindex = build_bl_tree(s);
+
+ /* Determine the best encoding. Compute first the block length in bytes*/
+ opt_lenb = (s->opt_len+3+7)>>3;
+ static_lenb = (s->static_len+3+7)>>3;
+
+ Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ",
+ opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len,
+ s->last_lit));
+
+ if (static_lenb <= opt_lenb) opt_lenb = static_lenb;
+
+ } else {
+ Assert(buf != (char*)0, "lost buf");
+ opt_lenb = static_lenb = stored_len + 5; /* force a stored block */
+ }
+
+ /* If compression failed and this is the first and last block,
+ * and if the .zip file can be seeked (to rewrite the local header),
+ * the whole file is transformed into a stored file:
+ */
+#ifdef STORED_FILE_OK
+# ifdef FORCE_STORED_FILE
+ if (eof && s->compressed_len == 0L) { /* force stored file */
+# else
+ if (stored_len <= opt_lenb && eof && s->compressed_len==0L && seekable()) {
+# endif
+ /* Since LIT_BUFSIZE <= 2*WSIZE, the input data must be there: */
+ if (buf == (charf*)0) error ("block vanished");
+
+ copy_block(s, buf, (unsigned)stored_len, 0); /* without header */
+ s->compressed_len = stored_len << 3;
+ s->method = STORED;
+ } else
+#endif /* STORED_FILE_OK */
+
+#ifdef FORCE_STORED
+ if (buf != (char*)0) { /* force stored block */
+#else
+ if (stored_len+4 <= opt_lenb && buf != (char*)0) {
+ /* 4: two words for the lengths */
+#endif
+ /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE.
+ * Otherwise we can't have processed more than WSIZE input bytes since
+ * the last block flush, because compression would have been
+ * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to
+ * transform a block into a stored block.
+ */
+ _tr_stored_block(s, buf, stored_len, eof);
+
+#ifdef FORCE_STATIC
+ } else if (static_lenb >= 0) { /* force static trees */
+#else
+ } else if (static_lenb == opt_lenb) {
+#endif
+ send_bits(s, (STATIC_TREES<<1)+eof, 3);
+ compress_block(s, (ct_data *)static_ltree, (ct_data *)static_dtree);
+ s->compressed_len += 3 + s->static_len;
+ } else {
+ send_bits(s, (DYN_TREES<<1)+eof, 3);
+ send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1,
+ max_blindex+1);
+ compress_block(s, (ct_data *)s->dyn_ltree, (ct_data *)s->dyn_dtree);
+ s->compressed_len += 3 + s->opt_len;
+ }
+ Assert (s->compressed_len == s->bits_sent, "bad compressed size");
+ init_block(s);
+
+ if (eof) {
+ bi_windup(s);
+ s->compressed_len += 7; /* align on byte boundary */
+ }
+ Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3,
+ s->compressed_len-7*eof));
+
+ return s->compressed_len >> 3;
+}
+
+/* ===========================================================================
+ * Save the match info and tally the frequency counts. Return true if
+ * the current block must be flushed.
+ */
+int _tr_tally (s, dist, lc)
+ deflate_state *s;
+ unsigned dist; /* distance of matched string */
+ unsigned lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */
+{
+ s->d_buf[s->last_lit] = (ush)dist;
+ s->l_buf[s->last_lit++] = (uch)lc;
+ if (dist == 0) {
+ /* lc is the unmatched char */
+ s->dyn_ltree[lc].Freq++;
+ } else {
+ s->matches++;
+ /* Here, lc is the match length - MIN_MATCH */
+ dist--; /* dist = match distance - 1 */
+ Assert((ush)dist < (ush)MAX_DIST(s) &&
+ (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) &&
+ (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match");
+
+ s->dyn_ltree[length_code[lc]+LITERALS+1].Freq++;
+ s->dyn_dtree[d_code(dist)].Freq++;
+ }
+
+ /* Try to guess if it is profitable to stop the current block here */
+ if (s->level > 2 && (s->last_lit & 0xfff) == 0) {
+ /* Compute an upper bound for the compressed length */
+ ulg out_length = (ulg)s->last_lit*8L;
+ ulg in_length = (ulg)((long)s->strstart - s->block_start);
+ int dcode;
+ for (dcode = 0; dcode < D_CODES; dcode++) {
+ out_length += (ulg)s->dyn_dtree[dcode].Freq *
+ (5L+extra_dbits[dcode]);
+ }
+ out_length >>= 3;
+ Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ",
+ s->last_lit, in_length, out_length,
+ 100L - out_length*100L/in_length));
+ if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1;
+ }
+ return (s->last_lit == s->lit_bufsize-1);
+ /* We avoid equality with lit_bufsize because of wraparound at 64K
+ * on 16 bit machines and because stored blocks are restricted to
+ * 64K-1 bytes.
+ */
+}
+
+/* ===========================================================================
+ * Send the block data compressed using the given Huffman trees
+ */
+local void compress_block(s, ltree, dtree)
+ deflate_state *s;
+ ct_data *ltree; /* literal tree */
+ ct_data *dtree; /* distance tree */
+{
+ unsigned dist; /* distance of matched string */
+ int lc; /* match length or unmatched char (if dist == 0) */
+ unsigned lx = 0; /* running index in l_buf */
+ unsigned code; /* the code to send */
+ int extra; /* number of extra bits to send */
+
+ if (s->last_lit != 0) do {
+ dist = s->d_buf[lx];
+ lc = s->l_buf[lx++];
+ if (dist == 0) {
+ send_code(s, lc, ltree); /* send a literal byte */
+ Tracecv(isgraph(lc), (stderr," '%c' ", lc));
+ } else {
+ /* Here, lc is the match length - MIN_MATCH */
+ code = length_code[lc];
+ send_code(s, code+LITERALS+1, ltree); /* send the length code */
+ extra = extra_lbits[code];
+ if (extra != 0) {
+ lc -= base_length[code];
+ send_bits(s, lc, extra); /* send the extra length bits */
+ }
+ dist--; /* dist is now the match distance - 1 */
+ code = d_code(dist);
+ Assert (code < D_CODES, "bad d_code");
+
+ send_code(s, code, dtree); /* send the distance code */
+ extra = extra_dbits[code];
+ if (extra != 0) {
+ dist -= base_dist[code];
+ send_bits(s, dist, extra); /* send the extra distance bits */
+ }
+ } /* literal or match pair ? */
+
+ /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */
+ Assert(s->pending < s->lit_bufsize + 2*lx, "pendingBuf overflow");
+
+ } while (lx < s->last_lit);
+
+ send_code(s, END_BLOCK, ltree);
+ s->last_eob_len = ltree[END_BLOCK].Len;
+}
+
+/* ===========================================================================
+ * Set the data type to ASCII or BINARY, using a crude approximation:
+ * binary if more than 20% of the bytes are <= 6 or >= 128, ascii otherwise.
+ * IN assertion: the fields freq of dyn_ltree are set and the total of all
+ * frequencies does not exceed 64K (to fit in an int on 16 bit machines).
+ */
+local void set_data_type(s)
+ deflate_state *s;
+{
+ int n = 0;
+ unsigned ascii_freq = 0;
+ unsigned bin_freq = 0;
+ while (n < 7) bin_freq += s->dyn_ltree[n++].Freq;
+ while (n < 128) ascii_freq += s->dyn_ltree[n++].Freq;
+ while (n < LITERALS) bin_freq += s->dyn_ltree[n++].Freq;
+ s->data_type = (Byte)(bin_freq > (ascii_freq >> 2) ? Z_BINARY : Z_ASCII);
+}
+
+/* ===========================================================================
+ * Reverse the first len bits of a code, using straightforward code (a faster
+ * method would use a table)
+ * IN assertion: 1 <= len <= 15
+ */
+local unsigned bi_reverse(code, len)
+ unsigned code; /* the value to invert */
+ int len; /* its bit length */
+{
+ register unsigned res = 0;
+ do {
+ res |= code & 1;
+ code >>= 1, res <<= 1;
+ } while (--len > 0);
+ return res >> 1;
+}
+
+/* ===========================================================================
+ * Flush the bit buffer, keeping at most 7 bits in it.
+ */
+local void bi_flush(s)
+ deflate_state *s;
+{
+ if (s->bi_valid == 16) {
+ put_short(s, s->bi_buf);
+ s->bi_buf = 0;
+ s->bi_valid = 0;
+ } else if (s->bi_valid >= 8) {
+ put_byte(s, (Byte)s->bi_buf);
+ s->bi_buf >>= 8;
+ s->bi_valid -= 8;
+ }
+}
+
+/* ===========================================================================
+ * Flush the bit buffer and align the output on a byte boundary
+ */
+local void bi_windup(s)
+ deflate_state *s;
+{
+ if (s->bi_valid > 8) {
+ put_short(s, s->bi_buf);
+ } else if (s->bi_valid > 0) {
+ put_byte(s, (Byte)s->bi_buf);
+ }
+ s->bi_buf = 0;
+ s->bi_valid = 0;
+#ifdef DEBUG_ZLIB
+ s->bits_sent = (s->bits_sent+7) & ~7;
+#endif
+}
+
+/* ===========================================================================
+ * Copy a stored block, storing first the length and its
+ * one's complement if requested.
+ */
+local void copy_block(s, buf, len, header)
+ deflate_state *s;
+ charf *buf; /* the input data */
+ unsigned len; /* its length */
+ int header; /* true if block header must be written */
+{
+ bi_windup(s); /* align on byte boundary */
+ s->last_eob_len = 8; /* enough lookahead for inflate */
+
+ if (header) {
+ put_short(s, (ush)len);
+ put_short(s, (ush)~len);
+#ifdef DEBUG_ZLIB
+ s->bits_sent += 2*16;
+#endif
+ }
+#ifdef DEBUG_ZLIB
+ s->bits_sent += (ulg)len<<3;
+#endif
+ /* bundle up the put_byte(s, *buf++) calls */
+ zmemcpy(&s->pending_buf[s->pending], buf, len);
+ s->pending += len;
+}
+/* --- trees.c */
+
+/* +++ inflate.c */
+/* inflate.c -- zlib interface to inflate modules
+ * Copyright (C) 1995-1996 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* #include "zutil.h" */
+
+/* +++ infblock.h */
+/* infblock.h -- header to use infblock.c
+ * Copyright (C) 1995-1996 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+struct inflate_blocks_state;
+typedef struct inflate_blocks_state FAR inflate_blocks_statef;
+
+extern inflate_blocks_statef * inflate_blocks_new OF((
+ z_streamp z,
+ check_func c, /* check function */
+ uInt w)); /* window size */
+
+extern int inflate_blocks OF((
+ inflate_blocks_statef *,
+ z_streamp ,
+ int)); /* initial return code */
+
+extern void inflate_blocks_reset OF((
+ inflate_blocks_statef *,
+ z_streamp ,
+ uLongf *)); /* check value on output */
+
+extern int inflate_blocks_free OF((
+ inflate_blocks_statef *,
+ z_streamp ,
+ uLongf *)); /* check value on output */
+
+extern void inflate_set_dictionary OF((
+ inflate_blocks_statef *s,
+ const Bytef *d, /* dictionary */
+ uInt n)); /* dictionary length */
+
+extern int inflate_addhistory OF((
+ inflate_blocks_statef *,
+ z_streamp));
+
+extern int inflate_packet_flush OF((
+ inflate_blocks_statef *));
+/* --- infblock.h */
+
+#ifndef NO_DUMMY_DECL
+struct inflate_blocks_state {int dummy;}; /* for buggy compilers */
+#endif
+
+/* inflate private state */
+struct internal_state {
+
+ /* mode */
+ enum {
+ METHOD, /* waiting for method byte */
+ FLAG, /* waiting for flag byte */
+ DICT4, /* four dictionary check bytes to go */
+ DICT3, /* three dictionary check bytes to go */
+ DICT2, /* two dictionary check bytes to go */
+ DICT1, /* one dictionary check byte to go */
+ DICT0, /* waiting for inflateSetDictionary */
+ BLOCKS, /* decompressing blocks */
+ CHECK4, /* four check bytes to go */
+ CHECK3, /* three check bytes to go */
+ CHECK2, /* two check bytes to go */
+ CHECK1, /* one check byte to go */
+ DONE, /* finished check, done */
+ BAD} /* got an error--stay here */
+ mode; /* current inflate mode */
+
+ /* mode dependent information */
+ union {
+ uInt method; /* if FLAGS, method byte */
+ struct {
+ uLong was; /* computed check value */
+ uLong need; /* stream check value */
+ } check; /* if CHECK, check values to compare */
+ uInt marker; /* if BAD, inflateSync's marker bytes count */
+ } sub; /* submode */
+
+ /* mode independent information */
+ int nowrap; /* flag for no wrapper */
+ uInt wbits; /* log2(window size) (8..15, defaults to 15) */
+ inflate_blocks_statef
+ *blocks; /* current inflate_blocks state */
+
+};
+
+
+int inflateReset(z)
+z_streamp z;
+{
+ uLong c;
+
+ if (z == Z_NULL || z->state == Z_NULL)
+ return Z_STREAM_ERROR;
+ z->total_in = z->total_out = 0;
+ z->msg = Z_NULL;
+ z->state->mode = z->state->nowrap ? BLOCKS : METHOD;
+ inflate_blocks_reset(z->state->blocks, z, &c);
+ Trace((stderr, "inflate: reset\n"));
+ return Z_OK;
+}
+
+
+int inflateEnd(z)
+z_streamp z;
+{
+ uLong c;
+
+ if (z == Z_NULL || z->state == Z_NULL || z->zfree == Z_NULL)
+ return Z_STREAM_ERROR;
+ if (z->state->blocks != Z_NULL)
+ inflate_blocks_free(z->state->blocks, z, &c);
+ ZFREE(z, z->state);
+ z->state = Z_NULL;
+ Trace((stderr, "inflate: end\n"));
+ return Z_OK;
+}
+
+
+int inflateInit2_(z, w, version, stream_size)
+z_streamp z;
+int w;
+const char *version;
+int stream_size;
+{
+ if (version == Z_NULL || version[0] != ZLIB_VERSION[0] ||
+ stream_size != sizeof(z_stream))
+ return Z_VERSION_ERROR;
+
+ /* initialize state */
+ if (z == Z_NULL)
+ return Z_STREAM_ERROR;
+ z->msg = Z_NULL;
+#ifndef NO_ZCFUNCS
+ if (z->zalloc == Z_NULL)
+ {
+ z->zalloc = zcalloc;
+ z->opaque = (voidpf)0;
+ }
+ if (z->zfree == Z_NULL) z->zfree = zcfree;
+#endif
+ if ((z->state = (struct internal_state FAR *)
+ ZALLOC(z,1,sizeof(struct internal_state))) == Z_NULL)
+ return Z_MEM_ERROR;
+ z->state->blocks = Z_NULL;
+
+ /* handle undocumented nowrap option (no zlib header or check) */
+ z->state->nowrap = 0;
+ if (w < 0)
+ {
+ w = - w;
+ z->state->nowrap = 1;
+ }
+
+ /* set window size */
+ if (w < 8 || w > 15)
+ {
+ inflateEnd(z);
+ return Z_STREAM_ERROR;
+ }
+ z->state->wbits = (uInt)w;
+
+ /* create inflate_blocks state */
+ if ((z->state->blocks =
+ inflate_blocks_new(z, z->state->nowrap ? Z_NULL : adler32, (uInt)1 << w))
+ == Z_NULL)
+ {
+ inflateEnd(z);
+ return Z_MEM_ERROR;
+ }
+ Trace((stderr, "inflate: allocated\n"));
+
+ /* reset state */
+ inflateReset(z);
+ return Z_OK;
+}
+
+
+int inflateInit_(z, version, stream_size)
+z_streamp z;
+const char *version;
+int stream_size;
+{
+ return inflateInit2_(z, DEF_WBITS, version, stream_size);
+}
+
+
+#define NEEDBYTE {if(z->avail_in==0)goto empty;r=Z_OK;}
+#define NEXTBYTE (z->avail_in--,z->total_in++,*z->next_in++)
+
+int inflate(z, f)
+z_streamp z;
+int f;
+{
+ int r;
+ uInt b;
+
+ if (z == Z_NULL || z->state == Z_NULL || z->next_in == Z_NULL || f < 0)
+ return Z_STREAM_ERROR;
+ r = Z_BUF_ERROR;
+ while (1) switch (z->state->mode)
+ {
+ case METHOD:
+ NEEDBYTE
+ if (((z->state->sub.method = NEXTBYTE) & 0xf) != Z_DEFLATED)
+ {
+ z->state->mode = BAD;
+ z->msg = (char*)"unknown compression method";
+ z->state->sub.marker = 5; /* can't try inflateSync */
+ break;
+ }
+ if ((z->state->sub.method >> 4) + 8 > z->state->wbits)
+ {
+ z->state->mode = BAD;
+ z->msg = (char*)"invalid window size";
+ z->state->sub.marker = 5; /* can't try inflateSync */
+ break;
+ }
+ z->state->mode = FLAG;
+ case FLAG:
+ NEEDBYTE
+ b = NEXTBYTE;
+ if (((z->state->sub.method << 8) + b) % 31)
+ {
+ z->state->mode = BAD;
+ z->msg = (char*)"incorrect header check";
+ z->state->sub.marker = 5; /* can't try inflateSync */
+ break;
+ }
+ Trace((stderr, "inflate: zlib header ok\n"));
+ if (!(b & PRESET_DICT))
+ {
+ z->state->mode = BLOCKS;
+ break;
+ }
+ z->state->mode = DICT4;
+ case DICT4:
+ NEEDBYTE
+ z->state->sub.check.need = (uLong)NEXTBYTE << 24;
+ z->state->mode = DICT3;
+ case DICT3:
+ NEEDBYTE
+ z->state->sub.check.need += (uLong)NEXTBYTE << 16;
+ z->state->mode = DICT2;
+ case DICT2:
+ NEEDBYTE
+ z->state->sub.check.need += (uLong)NEXTBYTE << 8;
+ z->state->mode = DICT1;
+ case DICT1:
+ NEEDBYTE
+ z->state->sub.check.need += (uLong)NEXTBYTE;
+ z->adler = z->state->sub.check.need;
+ z->state->mode = DICT0;
+ return Z_NEED_DICT;
+ case DICT0:
+ z->state->mode = BAD;
+ z->msg = (char*)"need dictionary";
+ z->state->sub.marker = 0; /* can try inflateSync */
+ return Z_STREAM_ERROR;
+ case BLOCKS:
+ r = inflate_blocks(z->state->blocks, z, r);
+ if (f == Z_PACKET_FLUSH && z->avail_in == 0 && z->avail_out != 0)
+ r = inflate_packet_flush(z->state->blocks);
+ if (r == Z_DATA_ERROR)
+ {
+ z->state->mode = BAD;
+ z->state->sub.marker = 0; /* can try inflateSync */
+ break;
+ }
+ if (r != Z_STREAM_END)
+ return r;
+ r = Z_OK;
+ inflate_blocks_reset(z->state->blocks, z, &z->state->sub.check.was);
+ if (z->state->nowrap)
+ {
+ z->state->mode = DONE;
+ break;
+ }
+ z->state->mode = CHECK4;
+ case CHECK4:
+ NEEDBYTE
+ z->state->sub.check.need = (uLong)NEXTBYTE << 24;
+ z->state->mode = CHECK3;
+ case CHECK3:
+ NEEDBYTE
+ z->state->sub.check.need += (uLong)NEXTBYTE << 16;
+ z->state->mode = CHECK2;
+ case CHECK2:
+ NEEDBYTE
+ z->state->sub.check.need += (uLong)NEXTBYTE << 8;
+ z->state->mode = CHECK1;
+ case CHECK1:
+ NEEDBYTE
+ z->state->sub.check.need += (uLong)NEXTBYTE;
+
+ if (z->state->sub.check.was != z->state->sub.check.need)
+ {
+ z->state->mode = BAD;
+ z->msg = (char*)"incorrect data check";
+ z->state->sub.marker = 5; /* can't try inflateSync */
+ break;
+ }
+ Trace((stderr, "inflate: zlib check ok\n"));
+ z->state->mode = DONE;
+ case DONE:
+ return Z_STREAM_END;
+ case BAD:
+ return Z_DATA_ERROR;
+ default:
+ return Z_STREAM_ERROR;
+ }
+
+ empty:
+ if (f != Z_PACKET_FLUSH)
+ return r;
+ z->state->mode = BAD;
+ z->msg = (char *)"need more for packet flush";
+ z->state->sub.marker = 0; /* can try inflateSync */
+ return Z_DATA_ERROR;
+}
+
+
+int inflateSetDictionary(z, dictionary, dictLength)
+z_streamp z;
+const Bytef *dictionary;
+uInt dictLength;
+{
+ uInt length = dictLength;
+
+ if (z == Z_NULL || z->state == Z_NULL || z->state->mode != DICT0)
+ return Z_STREAM_ERROR;
+
+ if (adler32(1L, dictionary, dictLength) != z->adler) return Z_DATA_ERROR;
+ z->adler = 1L;
+
+ if (length >= ((uInt)1<<z->state->wbits))
+ {
+ length = (1<<z->state->wbits)-1;
+ dictionary += dictLength - length;
+ }
+ inflate_set_dictionary(z->state->blocks, dictionary, length);
+ z->state->mode = BLOCKS;
+ return Z_OK;
+}
+
+/*
+ * This subroutine adds the data at next_in/avail_in to the output history
+ * without performing any output. The output buffer must be "caught up";
+ * i.e. no pending output (hence s->read equals s->write), and the state must
+ * be BLOCKS (i.e. we should be willing to see the start of a series of
+ * BLOCKS). On exit, the output will also be caught up, and the checksum
+ * will have been updated if need be.
+ */
+
+int inflateIncomp(z)
+z_stream *z;
+{
+ if (z->state->mode != BLOCKS)
+ return Z_DATA_ERROR;
+ return inflate_addhistory(z->state->blocks, z);
+}
+
+
+int inflateSync(z)
+z_streamp z;
+{
+ uInt n; /* number of bytes to look at */
+ Bytef *p; /* pointer to bytes */
+ uInt m; /* number of marker bytes found in a row */
+ uLong r, w; /* temporaries to save total_in and total_out */
+
+ /* set up */
+ if (z == Z_NULL || z->state == Z_NULL)
+ return Z_STREAM_ERROR;
+ if (z->state->mode != BAD)
+ {
+ z->state->mode = BAD;
+ z->state->sub.marker = 0;
+ }
+ if ((n = z->avail_in) == 0)
+ return Z_BUF_ERROR;
+ p = z->next_in;
+ m = z->state->sub.marker;
+
+ /* search */
+ while (n && m < 4)
+ {
+ if (*p == (Byte)(m < 2 ? 0 : 0xff))
+ m++;
+ else if (*p)
+ m = 0;
+ else
+ m = 4 - m;
+ p++, n--;
+ }
+
+ /* restore */
+ z->total_in += p - z->next_in;
+ z->next_in = p;
+ z->avail_in = n;
+ z->state->sub.marker = m;
+
+ /* return no joy or set up to restart on a new block */
+ if (m != 4)
+ return Z_DATA_ERROR;
+ r = z->total_in; w = z->total_out;
+ inflateReset(z);
+ z->total_in = r; z->total_out = w;
+ z->state->mode = BLOCKS;
+ return Z_OK;
+}
+
+#undef NEEDBYTE
+#undef NEXTBYTE
+/* --- inflate.c */
+
+/* +++ infblock.c */
+/* infblock.c -- interpret and process block types to last block
+ * Copyright (C) 1995-1996 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* #include "zutil.h" */
+/* #include "infblock.h" */
+
+/* +++ inftrees.h */
+/* inftrees.h -- header to use inftrees.c
+ * Copyright (C) 1995-1996 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+/* Huffman code lookup table entry--this entry is four bytes for machines
+ that have 16-bit pointers (e.g. PC's in the small or medium model). */
+
+typedef struct inflate_huft_s FAR inflate_huft;
+
+struct inflate_huft_s {
+ union {
+ struct {
+ Byte Exop; /* number of extra bits or operation */
+ Byte Bits; /* number of bits in this code or subcode */
+ } what;
+ Bytef *pad; /* pad structure to a power of 2 (4 bytes for */
+ } word; /* 16-bit, 8 bytes for 32-bit machines) */
+ union {
+ uInt Base; /* literal, length base, or distance base */
+ inflate_huft *Next; /* pointer to next level of table */
+ } more;
+};
+
+#ifdef DEBUG_ZLIB
+ extern uInt inflate_hufts;
+#endif
+
+extern int inflate_trees_bits OF((
+ uIntf *, /* 19 code lengths */
+ uIntf *, /* bits tree desired/actual depth */
+ inflate_huft * FAR *, /* bits tree result */
+ z_streamp )); /* for zalloc, zfree functions */
+
+extern int inflate_trees_dynamic OF((
+ uInt, /* number of literal/length codes */
+ uInt, /* number of distance codes */
+ uIntf *, /* that many (total) code lengths */
+ uIntf *, /* literal desired/actual bit depth */
+ uIntf *, /* distance desired/actual bit depth */
+ inflate_huft * FAR *, /* literal/length tree result */
+ inflate_huft * FAR *, /* distance tree result */
+ z_streamp )); /* for zalloc, zfree functions */
+
+extern int inflate_trees_fixed OF((
+ uIntf *, /* literal desired/actual bit depth */
+ uIntf *, /* distance desired/actual bit depth */
+ inflate_huft * FAR *, /* literal/length tree result */
+ inflate_huft * FAR *)); /* distance tree result */
+
+extern int inflate_trees_free OF((
+ inflate_huft *, /* tables to free */
+ z_streamp )); /* for zfree function */
+
+/* --- inftrees.h */
+
+/* +++ infcodes.h */
+/* infcodes.h -- header to use infcodes.c
+ * Copyright (C) 1995-1996 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+struct inflate_codes_state;
+typedef struct inflate_codes_state FAR inflate_codes_statef;
+
+extern inflate_codes_statef *inflate_codes_new OF((
+ uInt, uInt,
+ inflate_huft *, inflate_huft *,
+ z_streamp ));
+
+extern int inflate_codes OF((
+ inflate_blocks_statef *,
+ z_streamp ,
+ int));
+
+extern void inflate_codes_free OF((
+ inflate_codes_statef *,
+ z_streamp ));
+
+/* --- infcodes.h */
+
+/* +++ infutil.h */
+/* infutil.h -- types and macros common to blocks and codes
+ * Copyright (C) 1995-1996 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+#ifndef _INFUTIL_H
+#define _INFUTIL_H
+
+typedef enum {
+ TYPE, /* get type bits (3, including end bit) */
+ LENS, /* get lengths for stored */
+ STORED, /* processing stored block */
+ TABLE, /* get table lengths */
+ BTREE, /* get bit lengths tree for a dynamic block */
+ DTREE, /* get length, distance trees for a dynamic block */
+ CODES, /* processing fixed or dynamic block */
+ DRY, /* output remaining window bytes */
+ DONEB, /* finished last block, done */
+ BADB} /* got a data error--stuck here */
+inflate_block_mode;
+
+/* inflate blocks semi-private state */
+struct inflate_blocks_state {
+
+ /* mode */
+ inflate_block_mode mode; /* current inflate_block mode */
+
+ /* mode dependent information */
+ union {
+ uInt left; /* if STORED, bytes left to copy */
+ struct {
+ uInt table; /* table lengths (14 bits) */
+ uInt index; /* index into blens (or border) */
+ uIntf *blens; /* bit lengths of codes */
+ uInt bb; /* bit length tree depth */
+ inflate_huft *tb; /* bit length decoding tree */
+ } trees; /* if DTREE, decoding info for trees */
+ struct {
+ inflate_huft *tl;
+ inflate_huft *td; /* trees to free */
+ inflate_codes_statef
+ *codes;
+ } decode; /* if CODES, current state */
+ } sub; /* submode */
+ uInt last; /* true if this block is the last block */
+
+ /* mode independent information */
+ uInt bitk; /* bits in bit buffer */
+ uLong bitb; /* bit buffer */
+ Bytef *window; /* sliding window */
+ Bytef *end; /* one byte after sliding window */
+ Bytef *read; /* window read pointer */
+ Bytef *write; /* window write pointer */
+ check_func checkfn; /* check function */
+ uLong check; /* check on output */
+
+};
+
+
+/* defines for inflate input/output */
+/* update pointers and return */
+#define UPDBITS {s->bitb=b;s->bitk=k;}
+#define UPDIN {z->avail_in=n;z->total_in+=p-z->next_in;z->next_in=p;}
+#define UPDOUT {s->write=q;}
+#define UPDATE {UPDBITS UPDIN UPDOUT}
+#define LEAVE {UPDATE return inflate_flush(s,z,r);}
+/* get bytes and bits */
+#define LOADIN {p=z->next_in;n=z->avail_in;b=s->bitb;k=s->bitk;}
+#define NEEDBYTE {if(n)r=Z_OK;else LEAVE}
+#define NEXTBYTE (n--,*p++)
+#define NEEDBITS(j) {while(k<(j)){NEEDBYTE;b|=((uLong)NEXTBYTE)<<k;k+=8;}}
+#define DUMPBITS(j) {b>>=(j);k-=(j);}
+/* output bytes */
+#define WAVAIL (uInt)(q<s->read?s->read-q-1:s->end-q)
+#define LOADOUT {q=s->write;m=(uInt)WAVAIL;}
+#define WWRAP {if(q==s->end&&s->read!=s->window){q=s->window;m=(uInt)WAVAIL;}}
+#define FLUSH {UPDOUT r=inflate_flush(s,z,r); LOADOUT}
+#define NEEDOUT {if(m==0){WWRAP if(m==0){FLUSH WWRAP if(m==0) LEAVE}}r=Z_OK;}
+#define OUTBYTE(a) {*q++=(Byte)(a);m--;}
+/* load local pointers */
+#define LOAD {LOADIN LOADOUT}
+
+/* masks for lower bits (size given to avoid silly warnings with Visual C++) */
+extern uInt inflate_mask[17];
+
+/* copy as much as possible from the sliding window to the output area */
+extern int inflate_flush OF((
+ inflate_blocks_statef *,
+ z_streamp ,
+ int));
+
+#ifndef NO_DUMMY_DECL
+struct internal_state {int dummy;}; /* for buggy compilers */
+#endif
+
+#endif
+/* --- infutil.h */
+
+#ifndef NO_DUMMY_DECL
+struct inflate_codes_state {int dummy;}; /* for buggy compilers */
+#endif
+
+/* Table for deflate from PKZIP's appnote.txt. */
+local const uInt border[] = { /* Order of the bit length code lengths */
+ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
+
+/*
+ Notes beyond the 1.93a appnote.txt:
+
+ 1. Distance pointers never point before the beginning of the output
+ stream.
+ 2. Distance pointers can point back across blocks, up to 32k away.
+ 3. There is an implied maximum of 7 bits for the bit length table and
+ 15 bits for the actual data.
+ 4. If only one code exists, then it is encoded using one bit. (Zero
+ would be more efficient, but perhaps a little confusing.) If two
+ codes exist, they are coded using one bit each (0 and 1).
+ 5. There is no way of sending zero distance codes--a dummy must be
+ sent if there are none. (History: a pre 2.0 version of PKZIP would
+ store blocks with no distance codes, but this was discovered to be
+ too harsh a criterion.) Valid only for 1.93a. 2.04c does allow
+ zero distance codes, which is sent as one code of zero bits in
+ length.
+ 6. There are up to 286 literal/length codes. Code 256 represents the
+ end-of-block. Note however that the static length tree defines
+ 288 codes just to fill out the Huffman codes. Codes 286 and 287
+ cannot be used though, since there is no length base or extra bits
+ defined for them. Similarily, there are up to 30 distance codes.
+ However, static trees define 32 codes (all 5 bits) to fill out the
+ Huffman codes, but the last two had better not show up in the data.
+ 7. Unzip can check dynamic Huffman blocks for complete code sets.
+ The exception is that a single code would not be complete (see #4).
+ 8. The five bits following the block type is really the number of
+ literal codes sent minus 257.
+ 9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits
+ (1+6+6). Therefore, to output three times the length, you output
+ three codes (1+1+1), whereas to output four times the same length,
+ you only need two codes (1+3). Hmm.
+ 10. In the tree reconstruction algorithm, Code = Code + Increment
+ only if BitLength(i) is not zero. (Pretty obvious.)
+ 11. Correction: 4 Bits: # of Bit Length codes - 4 (4 - 19)
+ 12. Note: length code 284 can represent 227-258, but length code 285
+ really is 258. The last length deserves its own, short code
+ since it gets used a lot in very redundant files. The length
+ 258 is special since 258 - 3 (the min match length) is 255.
+ 13. The literal/length and distance code bit lengths are read as a
+ single stream of lengths. It is possible (and advantageous) for
+ a repeat code (16, 17, or 18) to go across the boundary between
+ the two sets of lengths.
+ */
+
+
+void inflate_blocks_reset(s, z, c)
+inflate_blocks_statef *s;
+z_streamp z;
+uLongf *c;
+{
+ if (s->checkfn != Z_NULL)
+ *c = s->check;
+ if (s->mode == BTREE || s->mode == DTREE)
+ ZFREE(z, s->sub.trees.blens);
+ if (s->mode == CODES)
+ {
+ inflate_codes_free(s->sub.decode.codes, z);
+ inflate_trees_free(s->sub.decode.td, z);
+ inflate_trees_free(s->sub.decode.tl, z);
+ }
+ s->mode = TYPE;
+ s->bitk = 0;
+ s->bitb = 0;
+ s->read = s->write = s->window;
+ if (s->checkfn != Z_NULL)
+ z->adler = s->check = (*s->checkfn)(0L, Z_NULL, 0);
+ Trace((stderr, "inflate: blocks reset\n"));
+}
+
+
+inflate_blocks_statef *inflate_blocks_new(z, c, w)
+z_streamp z;
+check_func c;
+uInt w;
+{
+ inflate_blocks_statef *s;
+
+ if ((s = (inflate_blocks_statef *)ZALLOC
+ (z,1,sizeof(struct inflate_blocks_state))) == Z_NULL)
+ return s;
+ if ((s->window = (Bytef *)ZALLOC(z, 1, w)) == Z_NULL)
+ {
+ ZFREE(z, s);
+ return Z_NULL;
+ }
+ s->end = s->window + w;
+ s->checkfn = c;
+ s->mode = TYPE;
+ Trace((stderr, "inflate: blocks allocated\n"));
+ inflate_blocks_reset(s, z, &s->check);
+ return s;
+}
+
+
+#ifdef DEBUG_ZLIB
+ extern uInt inflate_hufts;
+#endif
+int inflate_blocks(s, z, r)
+inflate_blocks_statef *s;
+z_streamp z;
+int r;
+{
+ uInt t; /* temporary storage */
+ uLong b; /* bit buffer */
+ uInt k; /* bits in bit buffer */
+ Bytef *p; /* input data pointer */
+ uInt n; /* bytes available there */
+ Bytef *q; /* output window write pointer */
+ uInt m; /* bytes to end of window or read pointer */
+
+ /* copy input/output information to locals (UPDATE macro restores) */
+ LOAD
+
+ /* process input based on current state */
+ while (1) switch (s->mode)
+ {
+ case TYPE:
+ NEEDBITS(3)
+ t = (uInt)b & 7;
+ s->last = t & 1;
+ switch (t >> 1)
+ {
+ case 0: /* stored */
+ Trace((stderr, "inflate: stored block%s\n",
+ s->last ? " (last)" : ""));
+ DUMPBITS(3)
+ t = k & 7; /* go to byte boundary */
+ DUMPBITS(t)
+ s->mode = LENS; /* get length of stored block */
+ break;
+ case 1: /* fixed */
+ Trace((stderr, "inflate: fixed codes block%s\n",
+ s->last ? " (last)" : ""));
+ {
+ uInt bl, bd;
+ inflate_huft *tl, *td;
+
+ inflate_trees_fixed(&bl, &bd, &tl, &td);
+ s->sub.decode.codes = inflate_codes_new(bl, bd, tl, td, z);
+ if (s->sub.decode.codes == Z_NULL)
+ {
+ r = Z_MEM_ERROR;
+ LEAVE
+ }
+ s->sub.decode.tl = Z_NULL; /* don't try to free these */
+ s->sub.decode.td = Z_NULL;
+ }
+ DUMPBITS(3)
+ s->mode = CODES;
+ break;
+ case 2: /* dynamic */
+ Trace((stderr, "inflate: dynamic codes block%s\n",
+ s->last ? " (last)" : ""));
+ DUMPBITS(3)
+ s->mode = TABLE;
+ break;
+ case 3: /* illegal */
+ DUMPBITS(3)
+ s->mode = BADB;
+ z->msg = (char*)"invalid block type";
+ r = Z_DATA_ERROR;
+ LEAVE
+ }
+ break;
+ case LENS:
+ NEEDBITS(32)
+ if ((((~b) >> 16) & 0xffff) != (b & 0xffff))
+ {
+ s->mode = BADB;
+ z->msg = (char*)"invalid stored block lengths";
+ r = Z_DATA_ERROR;
+ LEAVE
+ }
+ s->sub.left = (uInt)b & 0xffff;
+ b = k = 0; /* dump bits */
+ Tracev((stderr, "inflate: stored length %u\n", s->sub.left));
+ s->mode = s->sub.left ? STORED : (s->last ? DRY : TYPE);
+ break;
+ case STORED:
+ if (n == 0)
+ LEAVE
+ NEEDOUT
+ t = s->sub.left;
+ if (t > n) t = n;
+ if (t > m) t = m;
+ zmemcpy(q, p, t);
+ p += t; n -= t;
+ q += t; m -= t;
+ if ((s->sub.left -= t) != 0)
+ break;
+ Tracev((stderr, "inflate: stored end, %lu total out\n",
+ z->total_out + (q >= s->read ? q - s->read :
+ (s->end - s->read) + (q - s->window))));
+ s->mode = s->last ? DRY : TYPE;
+ break;
+ case TABLE:
+ NEEDBITS(14)
+ s->sub.trees.table = t = (uInt)b & 0x3fff;
+#ifndef PKZIP_BUG_WORKAROUND
+ if ((t & 0x1f) > 29 || ((t >> 5) & 0x1f) > 29)
+ {
+ s->mode = BADB;
+ z->msg = (char*)"too many length or distance symbols";
+ r = Z_DATA_ERROR;
+ LEAVE
+ }
+#endif
+ t = 258 + (t & 0x1f) + ((t >> 5) & 0x1f);
+ if (t < 19)
+ t = 19;
+ if ((s->sub.trees.blens = (uIntf*)ZALLOC(z, t, sizeof(uInt))) == Z_NULL)
+ {
+ r = Z_MEM_ERROR;
+ LEAVE
+ }
+ DUMPBITS(14)
+ s->sub.trees.index = 0;
+ Tracev((stderr, "inflate: table sizes ok\n"));
+ s->mode = BTREE;
+ case BTREE:
+ while (s->sub.trees.index < 4 + (s->sub.trees.table >> 10))
+ {
+ NEEDBITS(3)
+ s->sub.trees.blens[border[s->sub.trees.index++]] = (uInt)b & 7;
+ DUMPBITS(3)
+ }
+ while (s->sub.trees.index < 19)
+ s->sub.trees.blens[border[s->sub.trees.index++]] = 0;
+ s->sub.trees.bb = 7;
+ t = inflate_trees_bits(s->sub.trees.blens, &s->sub.trees.bb,
+ &s->sub.trees.tb, z);
+ if (t != Z_OK)
+ {
+ ZFREE(z, s->sub.trees.blens);
+ r = t;
+ if (r == Z_DATA_ERROR)
+ s->mode = BADB;
+ LEAVE
+ }
+ s->sub.trees.index = 0;
+ Tracev((stderr, "inflate: bits tree ok\n"));
+ s->mode = DTREE;
+ case DTREE:
+ while (t = s->sub.trees.table,
+ s->sub.trees.index < 258 + (t & 0x1f) + ((t >> 5) & 0x1f))
+ {
+ inflate_huft *h;
+ uInt i, j, c;
+
+ t = s->sub.trees.bb;
+ NEEDBITS(t)
+ h = s->sub.trees.tb + ((uInt)b & inflate_mask[t]);
+ t = h->word.what.Bits;
+ c = h->more.Base;
+ if (c < 16)
+ {
+ DUMPBITS(t)
+ s->sub.trees.blens[s->sub.trees.index++] = c;
+ }
+ else /* c == 16..18 */
+ {
+ i = c == 18 ? 7 : c - 14;
+ j = c == 18 ? 11 : 3;
+ NEEDBITS(t + i)
+ DUMPBITS(t)
+ j += (uInt)b & inflate_mask[i];
+ DUMPBITS(i)
+ i = s->sub.trees.index;
+ t = s->sub.trees.table;
+ if (i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) ||
+ (c == 16 && i < 1))
+ {
+ inflate_trees_free(s->sub.trees.tb, z);
+ ZFREE(z, s->sub.trees.blens);
+ s->mode = BADB;
+ z->msg = (char*)"invalid bit length repeat";
+ r = Z_DATA_ERROR;
+ LEAVE
+ }
+ c = c == 16 ? s->sub.trees.blens[i - 1] : 0;
+ do {
+ s->sub.trees.blens[i++] = c;
+ } while (--j);
+ s->sub.trees.index = i;
+ }
+ }
+ inflate_trees_free(s->sub.trees.tb, z);
+ s->sub.trees.tb = Z_NULL;
+ {
+ uInt bl, bd;
+ inflate_huft *tl, *td;
+ inflate_codes_statef *c;
+
+ bl = 9; /* must be <= 9 for lookahead assumptions */
+ bd = 6; /* must be <= 9 for lookahead assumptions */
+ t = s->sub.trees.table;
+#ifdef DEBUG_ZLIB
+ inflate_hufts = 0;
+#endif
+ t = inflate_trees_dynamic(257 + (t & 0x1f), 1 + ((t >> 5) & 0x1f),
+ s->sub.trees.blens, &bl, &bd, &tl, &td, z);
+ ZFREE(z, s->sub.trees.blens);
+ if (t != Z_OK)
+ {
+ if (t == (uInt)Z_DATA_ERROR)
+ s->mode = BADB;
+ r = t;
+ LEAVE
+ }
+ Tracev((stderr, "inflate: trees ok, %d * %d bytes used\n",
+ inflate_hufts, sizeof(inflate_huft)));
+ if ((c = inflate_codes_new(bl, bd, tl, td, z)) == Z_NULL)
+ {
+ inflate_trees_free(td, z);
+ inflate_trees_free(tl, z);
+ r = Z_MEM_ERROR;
+ LEAVE
+ }
+ s->sub.decode.codes = c;
+ s->sub.decode.tl = tl;
+ s->sub.decode.td = td;
+ }
+ s->mode = CODES;
+ case CODES:
+ UPDATE
+ if ((r = inflate_codes(s, z, r)) != Z_STREAM_END)
+ return inflate_flush(s, z, r);
+ r = Z_OK;
+ inflate_codes_free(s->sub.decode.codes, z);
+ inflate_trees_free(s->sub.decode.td, z);
+ inflate_trees_free(s->sub.decode.tl, z);
+ LOAD
+ Tracev((stderr, "inflate: codes end, %lu total out\n",
+ z->total_out + (q >= s->read ? q - s->read :
+ (s->end - s->read) + (q - s->window))));
+ if (!s->last)
+ {
+ s->mode = TYPE;
+ break;
+ }
+ if (k > 7) /* return unused byte, if any */
+ {
+ Assert(k < 16, "inflate_codes grabbed too many bytes")
+ k -= 8;
+ n++;
+ p--; /* can always return one */
+ }
+ s->mode = DRY;
+ case DRY:
+ FLUSH
+ if (s->read != s->write)
+ LEAVE
+ s->mode = DONEB;
+ case DONEB:
+ r = Z_STREAM_END;
+ LEAVE
+ case BADB:
+ r = Z_DATA_ERROR;
+ LEAVE
+ default:
+ r = Z_STREAM_ERROR;
+ LEAVE
+ }
+}
+
+
+int inflate_blocks_free(s, z, c)
+inflate_blocks_statef *s;
+z_streamp z;
+uLongf *c;
+{
+ inflate_blocks_reset(s, z, c);
+ ZFREE(z, s->window);
+ ZFREE(z, s);
+ Trace((stderr, "inflate: blocks freed\n"));
+ return Z_OK;
+}
+
+
+void inflate_set_dictionary(s, d, n)
+inflate_blocks_statef *s;
+const Bytef *d;
+uInt n;
+{
+ zmemcpy((charf *)s->window, d, n);
+ s->read = s->write = s->window + n;
+}
+
+/*
+ * This subroutine adds the data at next_in/avail_in to the output history
+ * without performing any output. The output buffer must be "caught up";
+ * i.e. no pending output (hence s->read equals s->write), and the state must
+ * be BLOCKS (i.e. we should be willing to see the start of a series of
+ * BLOCKS). On exit, the output will also be caught up, and the checksum
+ * will have been updated if need be.
+ */
+int inflate_addhistory(s, z)
+inflate_blocks_statef *s;
+z_stream *z;
+{
+ uLong b; /* bit buffer */ /* NOT USED HERE */
+ uInt k; /* bits in bit buffer */ /* NOT USED HERE */
+ uInt t; /* temporary storage */
+ Bytef *p; /* input data pointer */
+ uInt n; /* bytes available there */
+ Bytef *q; /* output window write pointer */
+ uInt m; /* bytes to end of window or read pointer */
+
+ if (s->read != s->write)
+ return Z_STREAM_ERROR;
+ if (s->mode != TYPE)
+ return Z_DATA_ERROR;
+
+ /* we're ready to rock */
+ LOAD
+ /* while there is input ready, copy to output buffer, moving
+ * pointers as needed.
+ */
+ while (n) {
+ t = n; /* how many to do */
+ /* is there room until end of buffer? */
+ if (t > m) t = m;
+ /* update check information */
+ if (s->checkfn != Z_NULL)
+ s->check = (*s->checkfn)(s->check, q, t);
+ zmemcpy(q, p, t);
+ q += t;
+ p += t;
+ n -= t;
+ z->total_out += t;
+ s->read = q; /* drag read pointer forward */
+/* WWRAP */ /* expand WWRAP macro by hand to handle s->read */
+ if (q == s->end) {
+ s->read = q = s->window;
+ m = WAVAIL;
+ }
+ }
+ UPDATE
+ return Z_OK;
+}
+
+
+/*
+ * At the end of a Deflate-compressed PPP packet, we expect to have seen
+ * a `stored' block type value but not the (zero) length bytes.
+ */
+int inflate_packet_flush(s)
+ inflate_blocks_statef *s;
+{
+ if (s->mode != LENS)
+ return Z_DATA_ERROR;
+ s->mode = TYPE;
+ return Z_OK;
+}
+/* --- infblock.c */
+
+/* +++ inftrees.c */
+/* inftrees.c -- generate Huffman trees for efficient decoding
+ * Copyright (C) 1995-1996 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* #include "zutil.h" */
+/* #include "inftrees.h" */
+
+char inflate_copyright[] = " inflate 1.0.4 Copyright 1995-1996 Mark Adler ";
+/*
+ If you use the zlib library in a product, an acknowledgment is welcome
+ in the documentation of your product. If for some reason you cannot
+ include such an acknowledgment, I would appreciate that you keep this
+ copyright string in the executable of your product.
+ */
+
+#ifndef NO_DUMMY_DECL
+struct internal_state {int dummy;}; /* for buggy compilers */
+#endif
+
+/* simplify the use of the inflate_huft type with some defines */
+#define base more.Base
+#define next more.Next
+#define exop word.what.Exop
+#define bits word.what.Bits
+
+
+local int huft_build OF((
+ uIntf *, /* code lengths in bits */
+ uInt, /* number of codes */
+ uInt, /* number of "simple" codes */
+ const uIntf *, /* list of base values for non-simple codes */
+ const uIntf *, /* list of extra bits for non-simple codes */
+ inflate_huft * FAR*,/* result: starting table */
+ uIntf *, /* maximum lookup bits (returns actual) */
+ z_streamp )); /* for zalloc function */
+
+local voidpf falloc OF((
+ voidpf, /* opaque pointer (not used) */
+ uInt, /* number of items */
+ uInt)); /* size of item */
+
+/* Tables for deflate from PKZIP's appnote.txt. */
+local const uInt cplens[31] = { /* Copy lengths for literal codes 257..285 */
+ 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
+ 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
+ /* see note #13 above about 258 */
+local const uInt cplext[31] = { /* Extra bits for literal codes 257..285 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
+ 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 112, 112}; /* 112==invalid */
+local const uInt cpdist[30] = { /* Copy offsets for distance codes 0..29 */
+ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
+ 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
+ 8193, 12289, 16385, 24577};
+local const uInt cpdext[30] = { /* Extra bits for distance codes */
+ 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
+ 7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
+ 12, 12, 13, 13};
+
+/*
+ Huffman code decoding is performed using a multi-level table lookup.
+ The fastest way to decode is to simply build a lookup table whose
+ size is determined by the longest code. However, the time it takes
+ to build this table can also be a factor if the data being decoded
+ is not very long. The most common codes are necessarily the
+ shortest codes, so those codes dominate the decoding time, and hence
+ the speed. The idea is you can have a shorter table that decodes the
+ shorter, more probable codes, and then point to subsidiary tables for
+ the longer codes. The time it costs to decode the longer codes is
+ then traded against the time it takes to make longer tables.
+
+ This results of this trade are in the variables lbits and dbits
+ below. lbits is the number of bits the first level table for literal/
+ length codes can decode in one step, and dbits is the same thing for
+ the distance codes. Subsequent tables are also less than or equal to
+ those sizes. These values may be adjusted either when all of the
+ codes are shorter than that, in which case the longest code length in
+ bits is used, or when the shortest code is *longer* than the requested
+ table size, in which case the length of the shortest code in bits is
+ used.
+
+ There are two different values for the two tables, since they code a
+ different number of possibilities each. The literal/length table
+ codes 286 possible values, or in a flat code, a little over eight
+ bits. The distance table codes 30 possible values, or a little less
+ than five bits, flat. The optimum values for speed end up being
+ about one bit more than those, so lbits is 8+1 and dbits is 5+1.
+ The optimum values may differ though from machine to machine, and
+ possibly even between compilers. Your mileage may vary.
+ */
+
+
+/* If BMAX needs to be larger than 16, then h and x[] should be uLong. */
+#define BMAX 15 /* maximum bit length of any code */
+#define N_MAX 288 /* maximum number of codes in any set */
+
+#ifdef DEBUG_ZLIB
+ uInt inflate_hufts;
+#endif
+
+local int huft_build(b, n, s, d, e, t, m, zs)
+uIntf *b; /* code lengths in bits (all assumed <= BMAX) */
+uInt n; /* number of codes (assumed <= N_MAX) */
+uInt s; /* number of simple-valued codes (0..s-1) */
+const uIntf *d; /* list of base values for non-simple codes */
+const uIntf *e; /* list of extra bits for non-simple codes */
+inflate_huft * FAR *t; /* result: starting table */
+uIntf *m; /* maximum lookup bits, returns actual */
+z_streamp zs; /* for zalloc function */
+/* Given a list of code lengths and a maximum table size, make a set of
+ tables to decode that set of codes. Return Z_OK on success, Z_BUF_ERROR
+ if the given code set is incomplete (the tables are still built in this
+ case), Z_DATA_ERROR if the input is invalid (an over-subscribed set of
+ lengths), or Z_MEM_ERROR if not enough memory. */
+{
+
+ uInt a; /* counter for codes of length k */
+ uInt c[BMAX+1]; /* bit length count table */
+ uInt f; /* i repeats in table every f entries */
+ int g; /* maximum code length */
+ int h; /* table level */
+ register uInt i; /* counter, current code */
+ register uInt j; /* counter */
+ register int k; /* number of bits in current code */
+ int l; /* bits per table (returned in m) */
+ register uIntf *p; /* pointer into c[], b[], or v[] */
+ inflate_huft *q; /* points to current table */
+ struct inflate_huft_s r; /* table entry for structure assignment */
+ inflate_huft *u[BMAX]; /* table stack */
+ uInt v[N_MAX]; /* values in order of bit length */
+ register int w; /* bits before this table == (l * h) */
+ uInt x[BMAX+1]; /* bit offsets, then code stack */
+ uIntf *xp; /* pointer into x */
+ int y; /* number of dummy codes added */
+ uInt z; /* number of entries in current table */
+
+
+ /* Generate counts for each bit length */
+ p = c;
+#define C0 *p++ = 0;
+#define C2 C0 C0 C0 C0
+#define C4 C2 C2 C2 C2
+ C4 /* clear c[]--assume BMAX+1 is 16 */
+ p = b; i = n;
+ do {
+ c[*p++]++; /* assume all entries <= BMAX */
+ } while (--i);
+ if (c[0] == n) /* null input--all zero length codes */
+ {
+ *t = (inflate_huft *)Z_NULL;
+ *m = 0;
+ return Z_OK;
+ }
+
+
+ /* Find minimum and maximum length, bound *m by those */
+ l = *m;
+ for (j = 1; j <= BMAX; j++)
+ if (c[j])
+ break;
+ k = j; /* minimum code length */
+ if ((uInt)l < j)
+ l = j;
+ for (i = BMAX; i; i--)
+ if (c[i])
+ break;
+ g = i; /* maximum code length */
+ if ((uInt)l > i)
+ l = i;
+ *m = l;
+
+
+ /* Adjust last length count to fill out codes, if needed */
+ for (y = 1 << j; j < i; j++, y <<= 1)
+ if ((y -= c[j]) < 0)
+ return Z_DATA_ERROR;
+ if ((y -= c[i]) < 0)
+ return Z_DATA_ERROR;
+ c[i] += y;
+
+
+ /* Generate starting offsets into the value table for each length */
+ x[1] = j = 0;
+ p = c + 1; xp = x + 2;
+ while (--i) { /* note that i == g from above */
+ *xp++ = (j += *p++);
+ }
+
+
+ /* Make a table of values in order of bit lengths */
+ p = b; i = 0;
+ do {
+ if ((j = *p++) != 0)
+ v[x[j]++] = i;
+ } while (++i < n);
+ n = x[g]; /* set n to length of v */
+
+
+ /* Generate the Huffman codes and for each, make the table entries */
+ x[0] = i = 0; /* first Huffman code is zero */
+ p = v; /* grab values in bit order */
+ h = -1; /* no tables yet--level -1 */
+ w = -l; /* bits decoded == (l * h) */
+ u[0] = (inflate_huft *)Z_NULL; /* just to keep compilers happy */
+ q = (inflate_huft *)Z_NULL; /* ditto */
+ z = 0; /* ditto */
+
+ /* go through the bit lengths (k already is bits in shortest code) */
+ for (; k <= g; k++)
+ {
+ a = c[k];
+ while (a--)
+ {
+ /* here i is the Huffman code of length k bits for value *p */
+ /* make tables up to required level */
+ while (k > w + l)
+ {
+ h++;
+ w += l; /* previous table always l bits */
+
+ /* compute minimum size table less than or equal to l bits */
+ z = g - w;
+ z = z > (uInt)l ? l : z; /* table size upper limit */
+ if ((f = 1 << (j = k - w)) > a + 1) /* try a k-w bit table */
+ { /* too few codes for k-w bit table */
+ f -= a + 1; /* deduct codes from patterns left */
+ xp = c + k;
+ if (j < z)
+ while (++j < z) /* try smaller tables up to z bits */
+ {
+ if ((f <<= 1) <= *++xp)
+ break; /* enough codes to use up j bits */
+ f -= *xp; /* else deduct codes from patterns */
+ }
+ }
+ z = 1 << j; /* table entries for j-bit table */
+
+ /* allocate and link in new table */
+ if ((q = (inflate_huft *)ZALLOC
+ (zs,z + 1,sizeof(inflate_huft))) == Z_NULL)
+ {
+ if (h)
+ inflate_trees_free(u[0], zs);
+ return Z_MEM_ERROR; /* not enough memory */
+ }
+#ifdef DEBUG_ZLIB
+ inflate_hufts += z + 1;
+#endif
+ *t = q + 1; /* link to list for huft_free() */
+ *(t = &(q->next)) = Z_NULL;
+ u[h] = ++q; /* table starts after link */
+
+ /* connect to last table, if there is one */
+ if (h)
+ {
+ x[h] = i; /* save pattern for backing up */
+ r.bits = (Byte)l; /* bits to dump before this table */
+ r.exop = (Byte)j; /* bits in this table */
+ r.next = q; /* pointer to this table */
+ j = i >> (w - l); /* (get around Turbo C bug) */
+ u[h-1][j] = r; /* connect to last table */
+ }
+ }
+
+ /* set up table entry in r */
+ r.bits = (Byte)(k - w);
+ if (p >= v + n)
+ r.exop = 128 + 64; /* out of values--invalid code */
+ else if (*p < s)
+ {
+ r.exop = (Byte)(*p < 256 ? 0 : 32 + 64); /* 256 is end-of-block */
+ r.base = *p++; /* simple code is just the value */
+ }
+ else
+ {
+ r.exop = (Byte)(e[*p - s] + 16 + 64);/* non-simple--look up in lists */
+ r.base = d[*p++ - s];
+ }
+
+ /* fill code-like entries with r */
+ f = 1 << (k - w);
+ for (j = i >> w; j < z; j += f)
+ q[j] = r;
+
+ /* backwards increment the k-bit code i */
+ for (j = 1 << (k - 1); i & j; j >>= 1)
+ i ^= j;
+ i ^= j;
+
+ /* backup over finished tables */
+ while ((i & ((1 << w) - 1)) != x[h])
+ {
+ h--; /* don't need to update q */
+ w -= l;
+ }
+ }
+ }
+
+
+ /* Return Z_BUF_ERROR if we were given an incomplete table */
+ return y != 0 && g != 1 ? Z_BUF_ERROR : Z_OK;
+}
+
+
+int inflate_trees_bits(c, bb, tb, z)
+uIntf *c; /* 19 code lengths */
+uIntf *bb; /* bits tree desired/actual depth */
+inflate_huft * FAR *tb; /* bits tree result */
+z_streamp z; /* for zfree function */
+{
+ int r;
+
+ r = huft_build(c, 19, 19, (uIntf*)Z_NULL, (uIntf*)Z_NULL, tb, bb, z);
+ if (r == Z_DATA_ERROR)
+ z->msg = (char*)"oversubscribed dynamic bit lengths tree";
+ else if (r == Z_BUF_ERROR || *bb == 0)
+ {
+ inflate_trees_free(*tb, z);
+ z->msg = (char*)"incomplete dynamic bit lengths tree";
+ r = Z_DATA_ERROR;
+ }
+ return r;
+}
+
+
+int inflate_trees_dynamic(nl, nd, c, bl, bd, tl, td, z)
+uInt nl; /* number of literal/length codes */
+uInt nd; /* number of distance codes */
+uIntf *c; /* that many (total) code lengths */
+uIntf *bl; /* literal desired/actual bit depth */
+uIntf *bd; /* distance desired/actual bit depth */
+inflate_huft * FAR *tl; /* literal/length tree result */
+inflate_huft * FAR *td; /* distance tree result */
+z_streamp z; /* for zfree function */
+{
+ int r;
+
+ /* build literal/length tree */
+ r = huft_build(c, nl, 257, cplens, cplext, tl, bl, z);
+ if (r != Z_OK || *bl == 0)
+ {
+ if (r == Z_DATA_ERROR)
+ z->msg = (char*)"oversubscribed literal/length tree";
+ else if (r != Z_MEM_ERROR)
+ {
+ inflate_trees_free(*tl, z);
+ z->msg = (char*)"incomplete literal/length tree";
+ r = Z_DATA_ERROR;
+ }
+ return r;
+ }
+
+ /* build distance tree */
+ r = huft_build(c + nl, nd, 0, cpdist, cpdext, td, bd, z);
+ if (r != Z_OK || (*bd == 0 && nl > 257))
+ {
+ if (r == Z_DATA_ERROR)
+ z->msg = (char*)"oversubscribed distance tree";
+ else if (r == Z_BUF_ERROR) {
+#ifdef PKZIP_BUG_WORKAROUND
+ r = Z_OK;
+ }
+#else
+ inflate_trees_free(*td, z);
+ z->msg = (char*)"incomplete distance tree";
+ r = Z_DATA_ERROR;
+ }
+ else if (r != Z_MEM_ERROR)
+ {
+ z->msg = (char*)"empty distance tree with lengths";
+ r = Z_DATA_ERROR;
+ }
+ inflate_trees_free(*tl, z);
+ return r;
+#endif
+ }
+
+ /* done */
+ return Z_OK;
+}
+
+
+/* build fixed tables only once--keep them here */
+local int fixed_built = 0;
+#define FIXEDH 530 /* number of hufts used by fixed tables */
+local inflate_huft fixed_mem[FIXEDH];
+local uInt fixed_bl;
+local uInt fixed_bd;
+local inflate_huft *fixed_tl;
+local inflate_huft *fixed_td;
+
+
+local voidpf falloc(q, n, s)
+voidpf q; /* opaque pointer */
+uInt n; /* number of items */
+uInt s; /* size of item */
+{
+ Assert(s == sizeof(inflate_huft) && n <= *(intf *)q,
+ "inflate_trees falloc overflow");
+ *(intf *)q -= n+s-s; /* s-s to avoid warning */
+ return (voidpf)(fixed_mem + *(intf *)q);
+}
+
+
+int inflate_trees_fixed(bl, bd, tl, td)
+uIntf *bl; /* literal desired/actual bit depth */
+uIntf *bd; /* distance desired/actual bit depth */
+inflate_huft * FAR *tl; /* literal/length tree result */
+inflate_huft * FAR *td; /* distance tree result */
+{
+ /* build fixed tables if not already (multiple overlapped executions ok) */
+ if (!fixed_built)
+ {
+ int k; /* temporary variable */
+ unsigned c[288]; /* length list for huft_build */
+ z_stream z; /* for falloc function */
+ int f = FIXEDH; /* number of hufts left in fixed_mem */
+
+ /* set up fake z_stream for memory routines */
+ z.zalloc = falloc;
+ z.zfree = Z_NULL;
+ z.opaque = (voidpf)&f;
+
+ /* literal table */
+ for (k = 0; k < 144; k++)
+ c[k] = 8;
+ for (; k < 256; k++)
+ c[k] = 9;
+ for (; k < 280; k++)
+ c[k] = 7;
+ for (; k < 288; k++)
+ c[k] = 8;
+ fixed_bl = 7;
+ huft_build(c, 288, 257, cplens, cplext, &fixed_tl, &fixed_bl, &z);
+
+ /* distance table */
+ for (k = 0; k < 30; k++)
+ c[k] = 5;
+ fixed_bd = 5;
+ huft_build(c, 30, 0, cpdist, cpdext, &fixed_td, &fixed_bd, &z);
+
+ /* done */
+ Assert(f == 0, "invalid build of fixed tables");
+ fixed_built = 1;
+ }
+ *bl = fixed_bl;
+ *bd = fixed_bd;
+ *tl = fixed_tl;
+ *td = fixed_td;
+ return Z_OK;
+}
+
+
+int inflate_trees_free(t, z)
+inflate_huft *t; /* table to free */
+z_streamp z; /* for zfree function */
+/* Free the malloc'ed tables built by huft_build(), which makes a linked
+ list of the tables it made, with the links in a dummy first entry of
+ each table. */
+{
+ register inflate_huft *p, *q, *r;
+
+ /* Reverse linked list */
+ p = Z_NULL;
+ q = t;
+ while (q != Z_NULL)
+ {
+ r = (q - 1)->next;
+ (q - 1)->next = p;
+ p = q;
+ q = r;
+ }
+ /* Go through linked list, freeing from the malloced (t[-1]) address. */
+ while (p != Z_NULL)
+ {
+ q = (--p)->next;
+ ZFREE(z,p);
+ p = q;
+ }
+ return Z_OK;
+}
+/* --- inftrees.c */
+
+/* +++ infcodes.c */
+/* infcodes.c -- process literals and length/distance pairs
+ * Copyright (C) 1995-1996 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* #include "zutil.h" */
+/* #include "inftrees.h" */
+/* #include "infblock.h" */
+/* #include "infcodes.h" */
+/* #include "infutil.h" */
+
+/* +++ inffast.h */
+/* inffast.h -- header to use inffast.c
+ * Copyright (C) 1995-1996 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+extern int inflate_fast OF((
+ uInt,
+ uInt,
+ inflate_huft *,
+ inflate_huft *,
+ inflate_blocks_statef *,
+ z_streamp ));
+/* --- inffast.h */
+
+/* simplify the use of the inflate_huft type with some defines */
+#define base more.Base
+#define next more.Next
+#define exop word.what.Exop
+#define bits word.what.Bits
+
+/* inflate codes private state */
+struct inflate_codes_state {
+
+ /* mode */
+ enum { /* waiting for "i:"=input, "o:"=output, "x:"=nothing */
+ START, /* x: set up for LEN */
+ LEN, /* i: get length/literal/eob next */
+ LENEXT, /* i: getting length extra (have base) */
+ DIST, /* i: get distance next */
+ DISTEXT, /* i: getting distance extra */
+ COPY, /* o: copying bytes in window, waiting for space */
+ LIT, /* o: got literal, waiting for output space */
+ WASH, /* o: got eob, possibly still output waiting */
+ END, /* x: got eob and all data flushed */
+ BADCODE} /* x: got error */
+ mode; /* current inflate_codes mode */
+
+ /* mode dependent information */
+ uInt len;
+ union {
+ struct {
+ inflate_huft *tree; /* pointer into tree */
+ uInt need; /* bits needed */
+ } code; /* if LEN or DIST, where in tree */
+ uInt lit; /* if LIT, literal */
+ struct {
+ uInt get; /* bits to get for extra */
+ uInt dist; /* distance back to copy from */
+ } copy; /* if EXT or COPY, where and how much */
+ } sub; /* submode */
+
+ /* mode independent information */
+ Byte lbits; /* ltree bits decoded per branch */
+ Byte dbits; /* dtree bits decoder per branch */
+ inflate_huft *ltree; /* literal/length/eob tree */
+ inflate_huft *dtree; /* distance tree */
+
+};
+
+
+inflate_codes_statef *inflate_codes_new(bl, bd, tl, td, z)
+uInt bl, bd;
+inflate_huft *tl;
+inflate_huft *td; /* need separate declaration for Borland C++ */
+z_streamp z;
+{
+ inflate_codes_statef *c;
+
+ if ((c = (inflate_codes_statef *)
+ ZALLOC(z,1,sizeof(struct inflate_codes_state))) != Z_NULL)
+ {
+ c->mode = START;
+ c->lbits = (Byte)bl;
+ c->dbits = (Byte)bd;
+ c->ltree = tl;
+ c->dtree = td;
+ Tracev((stderr, "inflate: codes new\n"));
+ }
+ return c;
+}
+
+
+int inflate_codes(s, z, r)
+inflate_blocks_statef *s;
+z_streamp z;
+int r;
+{
+ uInt j; /* temporary storage */
+ inflate_huft *t; /* temporary pointer */
+ uInt e; /* extra bits or operation */
+ uLong b; /* bit buffer */
+ uInt k; /* bits in bit buffer */
+ Bytef *p; /* input data pointer */
+ uInt n; /* bytes available there */
+ Bytef *q; /* output window write pointer */
+ uInt m; /* bytes to end of window or read pointer */
+ Bytef *f; /* pointer to copy strings from */
+ inflate_codes_statef *c = s->sub.decode.codes; /* codes state */
+
+ /* copy input/output information to locals (UPDATE macro restores) */
+ LOAD
+
+ /* process input and output based on current state */
+ while (1) switch (c->mode)
+ { /* waiting for "i:"=input, "o:"=output, "x:"=nothing */
+ case START: /* x: set up for LEN */
+#ifndef SLOW
+ if (m >= 258 && n >= 10)
+ {
+ UPDATE
+ r = inflate_fast(c->lbits, c->dbits, c->ltree, c->dtree, s, z);
+ LOAD
+ if (r != Z_OK)
+ {
+ c->mode = r == Z_STREAM_END ? WASH : BADCODE;
+ break;
+ }
+ }
+#endif /* !SLOW */
+ c->sub.code.need = c->lbits;
+ c->sub.code.tree = c->ltree;
+ c->mode = LEN;
+ case LEN: /* i: get length/literal/eob next */
+ j = c->sub.code.need;
+ NEEDBITS(j)
+ t = c->sub.code.tree + ((uInt)b & inflate_mask[j]);
+ DUMPBITS(t->bits)
+ e = (uInt)(t->exop);
+ if (e == 0) /* literal */
+ {
+ c->sub.lit = t->base;
+ Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ?
+ "inflate: literal '%c'\n" :
+ "inflate: literal 0x%02x\n", t->base));
+ c->mode = LIT;
+ break;
+ }
+ if (e & 16) /* length */
+ {
+ c->sub.copy.get = e & 15;
+ c->len = t->base;
+ c->mode = LENEXT;
+ break;
+ }
+ if ((e & 64) == 0) /* next table */
+ {
+ c->sub.code.need = e;
+ c->sub.code.tree = t->next;
+ break;
+ }
+ if (e & 32) /* end of block */
+ {
+ Tracevv((stderr, "inflate: end of block\n"));
+ c->mode = WASH;
+ break;
+ }
+ c->mode = BADCODE; /* invalid code */
+ z->msg = (char*)"invalid literal/length code";
+ r = Z_DATA_ERROR;
+ LEAVE
+ case LENEXT: /* i: getting length extra (have base) */
+ j = c->sub.copy.get;
+ NEEDBITS(j)
+ c->len += (uInt)b & inflate_mask[j];
+ DUMPBITS(j)
+ c->sub.code.need = c->dbits;
+ c->sub.code.tree = c->dtree;
+ Tracevv((stderr, "inflate: length %u\n", c->len));
+ c->mode = DIST;
+ case DIST: /* i: get distance next */
+ j = c->sub.code.need;
+ NEEDBITS(j)
+ t = c->sub.code.tree + ((uInt)b & inflate_mask[j]);
+ DUMPBITS(t->bits)
+ e = (uInt)(t->exop);
+ if (e & 16) /* distance */
+ {
+ c->sub.copy.get = e & 15;
+ c->sub.copy.dist = t->base;
+ c->mode = DISTEXT;
+ break;
+ }
+ if ((e & 64) == 0) /* next table */
+ {
+ c->sub.code.need = e;
+ c->sub.code.tree = t->next;
+ break;
+ }
+ c->mode = BADCODE; /* invalid code */
+ z->msg = (char*)"invalid distance code";
+ r = Z_DATA_ERROR;
+ LEAVE
+ case DISTEXT: /* i: getting distance extra */
+ j = c->sub.copy.get;
+ NEEDBITS(j)
+ c->sub.copy.dist += (uInt)b & inflate_mask[j];
+ DUMPBITS(j)
+ Tracevv((stderr, "inflate: distance %u\n", c->sub.copy.dist));
+ c->mode = COPY;
+ case COPY: /* o: copying bytes in window, waiting for space */
+#ifndef __TURBOC__ /* Turbo C bug for following expression */
+ f = (uInt)(q - s->window) < c->sub.copy.dist ?
+ s->end - (c->sub.copy.dist - (q - s->window)) :
+ q - c->sub.copy.dist;
+#else
+ f = q - c->sub.copy.dist;
+ if ((uInt)(q - s->window) < c->sub.copy.dist)
+ f = s->end - (c->sub.copy.dist - (uInt)(q - s->window));
+#endif
+ while (c->len)
+ {
+ NEEDOUT
+ OUTBYTE(*f++)
+ if (f == s->end)
+ f = s->window;
+ c->len--;
+ }
+ c->mode = START;
+ break;
+ case LIT: /* o: got literal, waiting for output space */
+ NEEDOUT
+ OUTBYTE(c->sub.lit)
+ c->mode = START;
+ break;
+ case WASH: /* o: got eob, possibly more output */
+ FLUSH
+ if (s->read != s->write)
+ LEAVE
+ c->mode = END;
+ case END:
+ r = Z_STREAM_END;
+ LEAVE
+ case BADCODE: /* x: got error */
+ r = Z_DATA_ERROR;
+ LEAVE
+ default:
+ r = Z_STREAM_ERROR;
+ LEAVE
+ }
+}
+
+
+void inflate_codes_free(c, z)
+inflate_codes_statef *c;
+z_streamp z;
+{
+ ZFREE(z, c);
+ Tracev((stderr, "inflate: codes free\n"));
+}
+/* --- infcodes.c */
+
+/* +++ infutil.c */
+/* inflate_util.c -- data and routines common to blocks and codes
+ * Copyright (C) 1995-1996 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* #include "zutil.h" */
+/* #include "infblock.h" */
+/* #include "inftrees.h" */
+/* #include "infcodes.h" */
+/* #include "infutil.h" */
+
+#ifndef NO_DUMMY_DECL
+struct inflate_codes_state {int dummy;}; /* for buggy compilers */
+#endif
+
+/* And'ing with mask[n] masks the lower n bits */
+uInt inflate_mask[17] = {
+ 0x0000,
+ 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,
+ 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff
+};
+
+
+/* copy as much as possible from the sliding window to the output area */
+int inflate_flush(s, z, r)
+inflate_blocks_statef *s;
+z_streamp z;
+int r;
+{
+ uInt n;
+ Bytef *p;
+ Bytef *q;
+
+ /* local copies of source and destination pointers */
+ p = z->next_out;
+ q = s->read;
+
+ /* compute number of bytes to copy as far as end of window */
+ n = (uInt)((q <= s->write ? s->write : s->end) - q);
+ if (n > z->avail_out) n = z->avail_out;
+ if (n && r == Z_BUF_ERROR) r = Z_OK;
+
+ /* update counters */
+ z->avail_out -= n;
+ z->total_out += n;
+
+ /* update check information */
+ if (s->checkfn != Z_NULL)
+ z->adler = s->check = (*s->checkfn)(s->check, q, n);
+
+ /* copy as far as end of window */
+ if (p != Z_NULL) {
+ zmemcpy(p, q, n);
+ p += n;
+ }
+ q += n;
+
+ /* see if more to copy at beginning of window */
+ if (q == s->end)
+ {
+ /* wrap pointers */
+ q = s->window;
+ if (s->write == s->end)
+ s->write = s->window;
+
+ /* compute bytes to copy */
+ n = (uInt)(s->write - q);
+ if (n > z->avail_out) n = z->avail_out;
+ if (n && r == Z_BUF_ERROR) r = Z_OK;
+
+ /* update counters */
+ z->avail_out -= n;
+ z->total_out += n;
+
+ /* update check information */
+ if (s->checkfn != Z_NULL)
+ z->adler = s->check = (*s->checkfn)(s->check, q, n);
+
+ /* copy */
+ if (p != Z_NULL) {
+ zmemcpy(p, q, n);
+ p += n;
+ }
+ q += n;
+ }
+
+ /* update pointers */
+ z->next_out = p;
+ s->read = q;
+
+ /* done */
+ return r;
+}
+/* --- infutil.c */
+
+/* +++ inffast.c */
+/* inffast.c -- process literals and length/distance pairs fast
+ * Copyright (C) 1995-1996 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* #include "zutil.h" */
+/* #include "inftrees.h" */
+/* #include "infblock.h" */
+/* #include "infcodes.h" */
+/* #include "infutil.h" */
+/* #include "inffast.h" */
+
+#ifndef NO_DUMMY_DECL
+struct inflate_codes_state {int dummy;}; /* for buggy compilers */
+#endif
+
+/* simplify the use of the inflate_huft type with some defines */
+#define base more.Base
+#define next more.Next
+#define exop word.what.Exop
+#define bits word.what.Bits
+
+/* macros for bit input with no checking and for returning unused bytes */
+#define GRABBITS(j) {while(k<(j)){b|=((uLong)NEXTBYTE)<<k;k+=8;}}
+#define UNGRAB {n+=(c=k>>3);p-=c;k&=7;}
+
+/* Called with number of bytes left to write in window at least 258
+ (the maximum string length) and number of input bytes available
+ at least ten. The ten bytes are six bytes for the longest length/
+ distance pair plus four bytes for overloading the bit buffer. */
+
+int inflate_fast(bl, bd, tl, td, s, z)
+uInt bl, bd;
+inflate_huft *tl;
+inflate_huft *td; /* need separate declaration for Borland C++ */
+inflate_blocks_statef *s;
+z_streamp z;
+{
+ inflate_huft *t; /* temporary pointer */
+ uInt e; /* extra bits or operation */
+ uLong b; /* bit buffer */
+ uInt k; /* bits in bit buffer */
+ Bytef *p; /* input data pointer */
+ uInt n; /* bytes available there */
+ Bytef *q; /* output window write pointer */
+ uInt m; /* bytes to end of window or read pointer */
+ uInt ml; /* mask for literal/length tree */
+ uInt md; /* mask for distance tree */
+ uInt c; /* bytes to copy */
+ uInt d; /* distance back to copy from */
+ Bytef *r; /* copy source pointer */
+
+ /* load input, output, bit values */
+ LOAD
+
+ /* initialize masks */
+ ml = inflate_mask[bl];
+ md = inflate_mask[bd];
+
+ /* do until not enough input or output space for fast loop */
+ do { /* assume called with m >= 258 && n >= 10 */
+ /* get literal/length code */
+ GRABBITS(20) /* max bits for literal/length code */
+ if ((e = (t = tl + ((uInt)b & ml))->exop) == 0)
+ {
+ DUMPBITS(t->bits)
+ Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ?
+ "inflate: * literal '%c'\n" :
+ "inflate: * literal 0x%02x\n", t->base));
+ *q++ = (Byte)t->base;
+ m--;
+ continue;
+ }
+ do {
+ DUMPBITS(t->bits)
+ if (e & 16)
+ {
+ /* get extra bits for length */
+ e &= 15;
+ c = t->base + ((uInt)b & inflate_mask[e]);
+ DUMPBITS(e)
+ Tracevv((stderr, "inflate: * length %u\n", c));
+
+ /* decode distance base of block to copy */
+ GRABBITS(15); /* max bits for distance code */
+ e = (t = td + ((uInt)b & md))->exop;
+ do {
+ DUMPBITS(t->bits)
+ if (e & 16)
+ {
+ /* get extra bits to add to distance base */
+ e &= 15;
+ GRABBITS(e) /* get extra bits (up to 13) */
+ d = t->base + ((uInt)b & inflate_mask[e]);
+ DUMPBITS(e)
+ Tracevv((stderr, "inflate: * distance %u\n", d));
+
+ /* do the copy */
+ m -= c;
+ if ((uInt)(q - s->window) >= d) /* offset before dest */
+ { /* just copy */
+ r = q - d;
+ *q++ = *r++; c--; /* minimum count is three, */
+ *q++ = *r++; c--; /* so unroll loop a little */
+ }
+ else /* else offset after destination */
+ {
+ e = d - (uInt)(q - s->window); /* bytes from offset to end */
+ r = s->end - e; /* pointer to offset */
+ if (c > e) /* if source crosses, */
+ {
+ c -= e; /* copy to end of window */
+ do {
+ *q++ = *r++;
+ } while (--e);
+ r = s->window; /* copy rest from start of window */
+ }
+ }
+ do { /* copy all or what's left */
+ *q++ = *r++;
+ } while (--c);
+ break;
+ }
+ else if ((e & 64) == 0)
+ e = (t = t->next + ((uInt)b & inflate_mask[e]))->exop;
+ else
+ {
+ z->msg = (char*)"invalid distance code";
+ UNGRAB
+ UPDATE
+ return Z_DATA_ERROR;
+ }
+ } while (1);
+ break;
+ }
+ if ((e & 64) == 0)
+ {
+ if ((e = (t = t->next + ((uInt)b & inflate_mask[e]))->exop) == 0)
+ {
+ DUMPBITS(t->bits)
+ Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ?
+ "inflate: * literal '%c'\n" :
+ "inflate: * literal 0x%02x\n", t->base));
+ *q++ = (Byte)t->base;
+ m--;
+ break;
+ }
+ }
+ else if (e & 32)
+ {
+ Tracevv((stderr, "inflate: * end of block\n"));
+ UNGRAB
+ UPDATE
+ return Z_STREAM_END;
+ }
+ else
+ {
+ z->msg = (char*)"invalid literal/length code";
+ UNGRAB
+ UPDATE
+ return Z_DATA_ERROR;
+ }
+ } while (1);
+ } while (m >= 258 && n >= 10);
+
+ /* not enough input or output--restore pointers and return */
+ UNGRAB
+ UPDATE
+ return Z_OK;
+}
+/* --- inffast.c */
+
+/* +++ zutil.c */
+/* zutil.c -- target dependent utility functions for the compression library
+ * Copyright (C) 1995-1996 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* From: zutil.c,v 1.17 1996/07/24 13:41:12 me Exp $ */
+
+#ifdef DEBUG_ZLIB
+#include <stdio.h>
+#endif
+
+/* #include "zutil.h" */
+
+#ifndef NO_DUMMY_DECL
+struct internal_state {int dummy;}; /* for buggy compilers */
+#endif
+
+#ifndef STDC
+extern void exit OF((int));
+#endif
+
+const char *z_errmsg[10] = {
+"need dictionary", /* Z_NEED_DICT 2 */
+"stream end", /* Z_STREAM_END 1 */
+"", /* Z_OK 0 */
+"file error", /* Z_ERRNO (-1) */
+"stream error", /* Z_STREAM_ERROR (-2) */
+"data error", /* Z_DATA_ERROR (-3) */
+"insufficient memory", /* Z_MEM_ERROR (-4) */
+"buffer error", /* Z_BUF_ERROR (-5) */
+"incompatible version",/* Z_VERSION_ERROR (-6) */
+""};
+
+
+const char *zlibVersion()
+{
+ return ZLIB_VERSION;
+}
+
+#ifdef DEBUG_ZLIB
+void z_error (m)
+ char *m;
+{
+ fprintf(stderr, "%s\n", m);
+ exit(1);
+}
+#endif
+
+#ifndef HAVE_MEMCPY
+
+void zmemcpy(dest, source, len)
+ Bytef* dest;
+ Bytef* source;
+ uInt len;
+{
+ if (len == 0) return;
+ do {
+ *dest++ = *source++; /* ??? to be unrolled */
+ } while (--len != 0);
+}
+
+int zmemcmp(s1, s2, len)
+ Bytef* s1;
+ Bytef* s2;
+ uInt len;
+{
+ uInt j;
+
+ for (j = 0; j < len; j++) {
+ if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1;
+ }
+ return 0;
+}
+
+void zmemzero(dest, len)
+ Bytef* dest;
+ uInt len;
+{
+ if (len == 0) return;
+ do {
+ *dest++ = 0; /* ??? to be unrolled */
+ } while (--len != 0);
+}
+#endif
+
+#ifdef __TURBOC__
+#if (defined( __BORLANDC__) || !defined(SMALL_MEDIUM)) && !defined(__32BIT__)
+/* Small and medium model in Turbo C are for now limited to near allocation
+ * with reduced MAX_WBITS and MAX_MEM_LEVEL
+ */
+# define MY_ZCALLOC
+
+/* Turbo C malloc() does not allow dynamic allocation of 64K bytes
+ * and farmalloc(64K) returns a pointer with an offset of 8, so we
+ * must fix the pointer. Warning: the pointer must be put back to its
+ * original form in order to free it, use zcfree().
+ */
+
+#define MAX_PTR 10
+/* 10*64K = 640K */
+
+local int next_ptr = 0;
+
+typedef struct ptr_table_s {
+ voidpf org_ptr;
+ voidpf new_ptr;
+} ptr_table;
+
+local ptr_table table[MAX_PTR];
+/* This table is used to remember the original form of pointers
+ * to large buffers (64K). Such pointers are normalized with a zero offset.
+ * Since MSDOS is not a preemptive multitasking OS, this table is not
+ * protected from concurrent access. This hack doesn't work anyway on
+ * a protected system like OS/2. Use Microsoft C instead.
+ */
+
+voidpf zcalloc (voidpf opaque, unsigned items, unsigned size)
+{
+ voidpf buf = opaque; /* just to make some compilers happy */
+ ulg bsize = (ulg)items*size;
+
+ /* If we allocate less than 65520 bytes, we assume that farmalloc
+ * will return a usable pointer which doesn't have to be normalized.
+ */
+ if (bsize < 65520L) {
+ buf = farmalloc(bsize);
+ if (*(ush*)&buf != 0) return buf;
+ } else {
+ buf = farmalloc(bsize + 16L);
+ }
+ if (buf == NULL || next_ptr >= MAX_PTR) return NULL;
+ table[next_ptr].org_ptr = buf;
+
+ /* Normalize the pointer to seg:0 */
+ *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4;
+ *(ush*)&buf = 0;
+ table[next_ptr++].new_ptr = buf;
+ return buf;
+}
+
+void zcfree (voidpf opaque, voidpf ptr)
+{
+ int n;
+ if (*(ush*)&ptr != 0) { /* object < 64K */
+ farfree(ptr);
+ return;
+ }
+ /* Find the original pointer */
+ for (n = 0; n < next_ptr; n++) {
+ if (ptr != table[n].new_ptr) continue;
+
+ farfree(table[n].org_ptr);
+ while (++n < next_ptr) {
+ table[n-1] = table[n];
+ }
+ next_ptr--;
+ return;
+ }
+ ptr = opaque; /* just to make some compilers happy */
+ Assert(0, "zcfree: ptr not found");
+}
+#endif
+#endif /* __TURBOC__ */
+
+
+#if defined(M_I86) && !defined(__32BIT__)
+/* Microsoft C in 16-bit mode */
+
+# define MY_ZCALLOC
+
+#if (!defined(_MSC_VER) || (_MSC_VER < 600))
+# define _halloc halloc
+# define _hfree hfree
+#endif
+
+voidpf zcalloc (voidpf opaque, unsigned items, unsigned size)
+{
+ if (opaque) opaque = 0; /* to make compiler happy */
+ return _halloc((long)items, size);
+}
+
+void zcfree (voidpf opaque, voidpf ptr)
+{
+ if (opaque) opaque = 0; /* to make compiler happy */
+ _hfree(ptr);
+}
+
+#endif /* MSC */
+
+
+#ifndef MY_ZCALLOC /* Any system without a special alloc function */
+
+#ifndef STDC
+extern voidp calloc OF((uInt items, uInt size));
+extern void free OF((voidpf ptr));
+#endif
+
+voidpf zcalloc (opaque, items, size)
+ voidpf opaque;
+ unsigned items;
+ unsigned size;
+{
+ if (opaque) items += size - size; /* make compiler happy */
+ return (voidpf)calloc(items, size);
+}
+
+void zcfree (opaque, ptr)
+ voidpf opaque;
+ voidpf ptr;
+{
+ free(ptr);
+ if (opaque) return; /* make compiler happy */
+}
+
+#endif /* MY_ZCALLOC */
+/* --- zutil.c */
+
+/* +++ adler32.c */
+/* adler32.c -- compute the Adler-32 checksum of a data stream
+ * Copyright (C) 1995-1996 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* From: adler32.c,v 1.10 1996/05/22 11:52:18 me Exp $ */
+
+/* #include "zlib.h" */
+
+#define BASE 65521L /* largest prime smaller than 65536 */
+#define NMAX 5552
+/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
+
+#define DO1(buf,i) {s1 += buf[i]; s2 += s1;}
+#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1);
+#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2);
+#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4);
+#define DO16(buf) DO8(buf,0); DO8(buf,8);
+
+/* ========================================================================= */
+uLong adler32(adler, buf, len)
+ uLong adler;
+ const Bytef *buf;
+ uInt len;
+{
+ unsigned long s1 = adler & 0xffff;
+ unsigned long s2 = (adler >> 16) & 0xffff;
+ int k;
+
+ if (buf == Z_NULL) return 1L;
+
+ while (len > 0) {
+ k = len < NMAX ? len : NMAX;
+ len -= k;
+ while (k >= 16) {
+ DO16(buf);
+ buf += 16;
+ k -= 16;
+ }
+ if (k != 0) do {
+ s1 += *buf++;
+ s2 += s1;
+ } while (--k);
+ s1 %= BASE;
+ s2 %= BASE;
+ }
+ return (s2 << 16) | s1;
+}
+/* --- adler32.c */
diff --git a/mdk-stage1/ppp/common/zlib.h b/mdk-stage1/ppp/common/zlib.h
new file mode 100644
index 000000000..936851f8f
--- /dev/null
+++ b/mdk-stage1/ppp/common/zlib.h
@@ -0,0 +1,1010 @@
+/* $Id: zlib.h 195720 2001-06-11 11:44:34Z gc $ */
+
+/*
+ * This file is derived from zlib.h and zconf.h from the zlib-1.0.4
+ * distribution by Jean-loup Gailly and Mark Adler, with some additions
+ * by Paul Mackerras to aid in implementing Deflate compression and
+ * decompression for PPP packets.
+ */
+
+/*
+ * ==FILEVERSION 971127==
+ *
+ * This marker is used by the Linux installation script to determine
+ * whether an up-to-date version of this file is already installed.
+ */
+
+
+/* +++ zlib.h */
+/* zlib.h -- interface of the 'zlib' general purpose compression library
+ version 1.0.4, Jul 24th, 1996.
+
+ Copyright (C) 1995-1996 Jean-loup Gailly and Mark Adler
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Jean-loup Gailly Mark Adler
+ gzip@prep.ai.mit.edu madler@alumni.caltech.edu
+
+
+ The data format used by the zlib library is described by RFCs (Request for
+ Comments) 1950 to 1952 in the files ftp://ds.internic.net/rfc/rfc1950.txt
+ (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format).
+*/
+
+#ifndef _ZLIB_H
+#define _ZLIB_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/* +++ zconf.h */
+/* zconf.h -- configuration of the zlib compression library
+ * Copyright (C) 1995-1996 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* From: zconf.h,v 1.20 1996/07/02 15:09:28 me Exp $ */
+
+#ifndef _ZCONF_H
+#define _ZCONF_H
+
+/*
+ * If you *really* need a unique prefix for all types and library functions,
+ * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it.
+ */
+#ifdef Z_PREFIX
+# define deflateInit_ z_deflateInit_
+# define deflate z_deflate
+# define deflateEnd z_deflateEnd
+# define inflateInit_ z_inflateInit_
+# define inflate z_inflate
+# define inflateEnd z_inflateEnd
+# define deflateInit2_ z_deflateInit2_
+# define deflateSetDictionary z_deflateSetDictionary
+# define deflateCopy z_deflateCopy
+# define deflateReset z_deflateReset
+# define deflateParams z_deflateParams
+# define inflateInit2_ z_inflateInit2_
+# define inflateSetDictionary z_inflateSetDictionary
+# define inflateSync z_inflateSync
+# define inflateReset z_inflateReset
+# define compress z_compress
+# define uncompress z_uncompress
+# define adler32 z_adler32
+# define crc32 z_crc32
+# define get_crc_table z_get_crc_table
+
+# define Byte z_Byte
+# define uInt z_uInt
+# define uLong z_uLong
+# define Bytef z_Bytef
+# define charf z_charf
+# define intf z_intf
+# define uIntf z_uIntf
+# define uLongf z_uLongf
+# define voidpf z_voidpf
+# define voidp z_voidp
+#endif
+
+#if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32)
+# define WIN32
+#endif
+#if defined(__GNUC__) || defined(WIN32) || defined(__386__) || defined(i386)
+# ifndef __32BIT__
+# define __32BIT__
+# endif
+#endif
+#if defined(__MSDOS__) && !defined(MSDOS)
+# define MSDOS
+#endif
+
+/*
+ * Compile with -DMAXSEG_64K if the alloc function cannot allocate more
+ * than 64k bytes at a time (needed on systems with 16-bit int).
+ */
+#if defined(MSDOS) && !defined(__32BIT__)
+# define MAXSEG_64K
+#endif
+#ifdef MSDOS
+# define UNALIGNED_OK
+#endif
+
+#if (defined(MSDOS) || defined(_WINDOWS) || defined(WIN32)) && !defined(STDC)
+# define STDC
+#endif
+#if (defined(__STDC__) || defined(__cplusplus)) && !defined(STDC)
+# define STDC
+#endif
+
+#ifndef STDC
+# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */
+# define const
+# endif
+#endif
+
+/* Some Mac compilers merge all .h files incorrectly: */
+#if defined(__MWERKS__) || defined(applec) ||defined(THINK_C) ||defined(__SC__)
+# define NO_DUMMY_DECL
+#endif
+
+/* Maximum value for memLevel in deflateInit2 */
+#ifndef MAX_MEM_LEVEL
+# ifdef MAXSEG_64K
+# define MAX_MEM_LEVEL 8
+# else
+# define MAX_MEM_LEVEL 9
+# endif
+#endif
+
+/* Maximum value for windowBits in deflateInit2 and inflateInit2 */
+#ifndef MAX_WBITS
+# define MAX_WBITS 15 /* 32K LZ77 window */
+#endif
+
+/* The memory requirements for deflate are (in bytes):
+ 1 << (windowBits+2) + 1 << (memLevel+9)
+ that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values)
+ plus a few kilobytes for small objects. For example, if you want to reduce
+ the default memory requirements from 256K to 128K, compile with
+ make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7"
+ Of course this will generally degrade compression (there's no free lunch).
+
+ The memory requirements for inflate are (in bytes) 1 << windowBits
+ that is, 32K for windowBits=15 (default value) plus a few kilobytes
+ for small objects.
+*/
+
+ /* Type declarations */
+
+#ifndef OF /* function prototypes */
+# ifdef STDC
+# define OF(args) args
+# else
+# define OF(args) ()
+# endif
+#endif
+
+/* The following definitions for FAR are needed only for MSDOS mixed
+ * model programming (small or medium model with some far allocations).
+ * This was tested only with MSC; for other MSDOS compilers you may have
+ * to define NO_MEMCPY in zutil.h. If you don't need the mixed model,
+ * just define FAR to be empty.
+ */
+#if (defined(M_I86SM) || defined(M_I86MM)) && !defined(__32BIT__)
+ /* MSC small or medium model */
+# define SMALL_MEDIUM
+# ifdef _MSC_VER
+# define FAR __far
+# else
+# define FAR far
+# endif
+#endif
+#if defined(__BORLANDC__) && (defined(__SMALL__) || defined(__MEDIUM__))
+# ifndef __32BIT__
+# define SMALL_MEDIUM
+# define FAR __far
+# endif
+#endif
+#ifndef FAR
+# define FAR
+#endif
+
+typedef unsigned char Byte; /* 8 bits */
+typedef unsigned int uInt; /* 16 bits or more */
+typedef unsigned long uLong; /* 32 bits or more */
+
+#if defined(__BORLANDC__) && defined(SMALL_MEDIUM)
+ /* Borland C/C++ ignores FAR inside typedef */
+# define Bytef Byte FAR
+#else
+ typedef Byte FAR Bytef;
+#endif
+typedef char FAR charf;
+typedef int FAR intf;
+typedef uInt FAR uIntf;
+typedef uLong FAR uLongf;
+
+#ifdef STDC
+ typedef void FAR *voidpf;
+ typedef void *voidp;
+#else
+ typedef Byte FAR *voidpf;
+ typedef Byte *voidp;
+#endif
+
+
+/* Compile with -DZLIB_DLL for Windows DLL support */
+#if (defined(_WINDOWS) || defined(WINDOWS)) && defined(ZLIB_DLL)
+# include <windows.h>
+# define EXPORT WINAPI
+#else
+# define EXPORT
+#endif
+
+#endif /* _ZCONF_H */
+/* --- zconf.h */
+
+#define ZLIB_VERSION "1.0.4P"
+
+/*
+ The 'zlib' compression library provides in-memory compression and
+ decompression functions, including integrity checks of the uncompressed
+ data. This version of the library supports only one compression method
+ (deflation) but other algorithms may be added later and will have the same
+ stream interface.
+
+ For compression the application must provide the output buffer and
+ may optionally provide the input buffer for optimization. For decompression,
+ the application must provide the input buffer and may optionally provide
+ the output buffer for optimization.
+
+ Compression can be done in a single step if the buffers are large
+ enough (for example if an input file is mmap'ed), or can be done by
+ repeated calls of the compression function. In the latter case, the
+ application must provide more input and/or consume the output
+ (providing more output space) before each call.
+
+ The library does not install any signal handler. It is recommended to
+ add at least a handler for SIGSEGV when decompressing; the library checks
+ the consistency of the input data whenever possible but may go nuts
+ for some forms of corrupted input.
+*/
+
+typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size));
+typedef void (*free_func) OF((voidpf opaque, voidpf address));
+
+struct internal_state;
+
+typedef struct z_stream_s {
+ Bytef *next_in; /* next input byte */
+ uInt avail_in; /* number of bytes available at next_in */
+ uLong total_in; /* total nb of input bytes read so far */
+
+ Bytef *next_out; /* next output byte should be put there */
+ uInt avail_out; /* remaining free space at next_out */
+ uLong total_out; /* total nb of bytes output so far */
+
+ char *msg; /* last error message, NULL if no error */
+ struct internal_state FAR *state; /* not visible by applications */
+
+ alloc_func zalloc; /* used to allocate the internal state */
+ free_func zfree; /* used to free the internal state */
+ voidpf opaque; /* private data object passed to zalloc and zfree */
+
+ int data_type; /* best guess about the data type: ascii or binary */
+ uLong adler; /* adler32 value of the uncompressed data */
+ uLong reserved; /* reserved for future use */
+} z_stream;
+
+typedef z_stream FAR *z_streamp;
+
+/*
+ The application must update next_in and avail_in when avail_in has
+ dropped to zero. It must update next_out and avail_out when avail_out
+ has dropped to zero. The application must initialize zalloc, zfree and
+ opaque before calling the init function. All other fields are set by the
+ compression library and must not be updated by the application.
+
+ The opaque value provided by the application will be passed as the first
+ parameter for calls of zalloc and zfree. This can be useful for custom
+ memory management. The compression library attaches no meaning to the
+ opaque value.
+
+ zalloc must return Z_NULL if there is not enough memory for the object.
+ On 16-bit systems, the functions zalloc and zfree must be able to allocate
+ exactly 65536 bytes, but will not be required to allocate more than this
+ if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS,
+ pointers returned by zalloc for objects of exactly 65536 bytes *must*
+ have their offset normalized to zero. The default allocation function
+ provided by this library ensures this (see zutil.c). To reduce memory
+ requirements and avoid any allocation of 64K objects, at the expense of
+ compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h).
+
+ The fields total_in and total_out can be used for statistics or
+ progress reports. After compression, total_in holds the total size of
+ the uncompressed data and may be saved for use in the decompressor
+ (particularly if the decompressor wants to decompress everything in
+ a single step).
+*/
+
+ /* constants */
+
+#define Z_NO_FLUSH 0
+#define Z_PARTIAL_FLUSH 1
+#define Z_PACKET_FLUSH 2
+#define Z_SYNC_FLUSH 3
+#define Z_FULL_FLUSH 4
+#define Z_FINISH 5
+/* Allowed flush values; see deflate() below for details */
+
+#define Z_OK 0
+#define Z_STREAM_END 1
+#define Z_NEED_DICT 2
+#define Z_ERRNO (-1)
+#define Z_STREAM_ERROR (-2)
+#define Z_DATA_ERROR (-3)
+#define Z_MEM_ERROR (-4)
+#define Z_BUF_ERROR (-5)
+#define Z_VERSION_ERROR (-6)
+/* Return codes for the compression/decompression functions. Negative
+ * values are errors, positive values are used for special but normal events.
+ */
+
+#define Z_NO_COMPRESSION 0
+#define Z_BEST_SPEED 1
+#define Z_BEST_COMPRESSION 9
+#define Z_DEFAULT_COMPRESSION (-1)
+/* compression levels */
+
+#define Z_FILTERED 1
+#define Z_HUFFMAN_ONLY 2
+#define Z_DEFAULT_STRATEGY 0
+/* compression strategy; see deflateInit2() below for details */
+
+#define Z_BINARY 0
+#define Z_ASCII 1
+#define Z_UNKNOWN 2
+/* Possible values of the data_type field */
+
+#define Z_DEFLATED 8
+/* The deflate compression method (the only one supported in this version) */
+
+#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */
+
+#define zlib_version zlibVersion()
+/* for compatibility with versions < 1.0.2 */
+
+ /* basic functions */
+
+extern const char * EXPORT zlibVersion OF((void));
+/* The application can compare zlibVersion and ZLIB_VERSION for consistency.
+ If the first character differs, the library code actually used is
+ not compatible with the zlib.h header file used by the application.
+ This check is automatically made by deflateInit and inflateInit.
+ */
+
+/*
+extern int EXPORT deflateInit OF((z_streamp strm, int level));
+
+ Initializes the internal stream state for compression. The fields
+ zalloc, zfree and opaque must be initialized before by the caller.
+ If zalloc and zfree are set to Z_NULL, deflateInit updates them to
+ use default allocation functions.
+
+ The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9:
+ 1 gives best speed, 9 gives best compression, 0 gives no compression at
+ all (the input data is simply copied a block at a time).
+ Z_DEFAULT_COMPRESSION requests a default compromise between speed and
+ compression (currently equivalent to level 6).
+
+ deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_STREAM_ERROR if level is not a valid compression level,
+ Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible
+ with the version assumed by the caller (ZLIB_VERSION).
+ msg is set to null if there is no error message. deflateInit does not
+ perform any compression: this will be done by deflate().
+*/
+
+
+extern int EXPORT deflate OF((z_streamp strm, int flush));
+/*
+ Performs one or both of the following actions:
+
+ - Compress more input starting at next_in and update next_in and avail_in
+ accordingly. If not all input can be processed (because there is not
+ enough room in the output buffer), next_in and avail_in are updated and
+ processing will resume at this point for the next call of deflate().
+
+ - Provide more output starting at next_out and update next_out and avail_out
+ accordingly. This action is forced if the parameter flush is non zero.
+ Forcing flush frequently degrades the compression ratio, so this parameter
+ should be set only when necessary (in interactive applications).
+ Some output may be provided even if flush is not set.
+
+ Before the call of deflate(), the application should ensure that at least
+ one of the actions is possible, by providing more input and/or consuming
+ more output, and updating avail_in or avail_out accordingly; avail_out
+ should never be zero before the call. The application can consume the
+ compressed output when it wants, for example when the output buffer is full
+ (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK
+ and with zero avail_out, it must be called again after making room in the
+ output buffer because there might be more output pending.
+
+ If the parameter flush is set to Z_PARTIAL_FLUSH, the current compression
+ block is terminated and flushed to the output buffer so that the
+ decompressor can get all input data available so far. For method 9, a future
+ variant on method 8, the current block will be flushed but not terminated.
+ Z_SYNC_FLUSH has the same effect as partial flush except that the compressed
+ output is byte aligned (the compressor can clear its internal bit buffer)
+ and the current block is always terminated; this can be useful if the
+ compressor has to be restarted from scratch after an interruption (in which
+ case the internal state of the compressor may be lost).
+ If flush is set to Z_FULL_FLUSH, the compression block is terminated, a
+ special marker is output and the compression dictionary is discarded; this
+ is useful to allow the decompressor to synchronize if one compressed block
+ has been damaged (see inflateSync below). Flushing degrades compression and
+ so should be used only when necessary. Using Z_FULL_FLUSH too often can
+ seriously degrade the compression. If deflate returns with avail_out == 0,
+ this function must be called again with the same value of the flush
+ parameter and more output space (updated avail_out), until the flush is
+ complete (deflate returns with non-zero avail_out).
+
+ If the parameter flush is set to Z_PACKET_FLUSH, the compression
+ block is terminated, and a zero-length stored block is output,
+ omitting the length bytes (the effect of this is that the 3-bit type
+ code 000 for a stored block is output, and the output is then
+ byte-aligned). This is designed for use at the end of a PPP packet.
+
+ If the parameter flush is set to Z_FINISH, pending input is processed,
+ pending output is flushed and deflate returns with Z_STREAM_END if there
+ was enough output space; if deflate returns with Z_OK, this function must be
+ called again with Z_FINISH and more output space (updated avail_out) but no
+ more input data, until it returns with Z_STREAM_END or an error. After
+ deflate has returned Z_STREAM_END, the only possible operations on the
+ stream are deflateReset or deflateEnd.
+
+ Z_FINISH can be used immediately after deflateInit if all the compression
+ is to be done in a single step. In this case, avail_out must be at least
+ 0.1% larger than avail_in plus 12 bytes. If deflate does not return
+ Z_STREAM_END, then it must be called again as described above.
+
+ deflate() may update data_type if it can make a good guess about
+ the input data type (Z_ASCII or Z_BINARY). In doubt, the data is considered
+ binary. This field is only for information purposes and does not affect
+ the compression algorithm in any manner.
+
+ deflate() returns Z_OK if some progress has been made (more input
+ processed or more output produced), Z_STREAM_END if all input has been
+ consumed and all output has been produced (only when flush is set to
+ Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example
+ if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible.
+*/
+
+
+extern int EXPORT deflateEnd OF((z_streamp strm));
+/*
+ All dynamically allocated data structures for this stream are freed.
+ This function discards any unprocessed input and does not flush any
+ pending output.
+
+ deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the
+ stream state was inconsistent, Z_DATA_ERROR if the stream was freed
+ prematurely (some input or output was discarded). In the error case,
+ msg may be set but then points to a static string (which must not be
+ deallocated).
+*/
+
+
+/*
+extern int EXPORT inflateInit OF((z_streamp strm));
+
+ Initializes the internal stream state for decompression. The fields
+ zalloc, zfree and opaque must be initialized before by the caller. If
+ zalloc and zfree are set to Z_NULL, inflateInit updates them to use default
+ allocation functions.
+
+ inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_VERSION_ERROR if the zlib library version is incompatible
+ with the version assumed by the caller. msg is set to null if there is no
+ error message. inflateInit does not perform any decompression: this will be
+ done by inflate().
+*/
+
+
+extern int EXPORT inflate OF((z_streamp strm, int flush));
+/*
+ Performs one or both of the following actions:
+
+ - Decompress more input starting at next_in and update next_in and avail_in
+ accordingly. If not all input can be processed (because there is not
+ enough room in the output buffer), next_in is updated and processing
+ will resume at this point for the next call of inflate().
+
+ - Provide more output starting at next_out and update next_out and avail_out
+ accordingly. inflate() provides as much output as possible, until there
+ is no more input data or no more space in the output buffer (see below
+ about the flush parameter).
+
+ Before the call of inflate(), the application should ensure that at least
+ one of the actions is possible, by providing more input and/or consuming
+ more output, and updating the next_* and avail_* values accordingly.
+ The application can consume the uncompressed output when it wants, for
+ example when the output buffer is full (avail_out == 0), or after each
+ call of inflate(). If inflate returns Z_OK and with zero avail_out, it
+ must be called again after making room in the output buffer because there
+ might be more output pending.
+
+ If the parameter flush is set to Z_PARTIAL_FLUSH or Z_PACKET_FLUSH,
+ inflate flushes as much output as possible to the output buffer. The
+ flushing behavior of inflate is not specified for values of the flush
+ parameter other than Z_PARTIAL_FLUSH, Z_PACKET_FLUSH or Z_FINISH, but the
+ current implementation actually flushes as much output as possible
+ anyway. For Z_PACKET_FLUSH, inflate checks that once all the input data
+ has been consumed, it is expecting to see the length field of a stored
+ block; if not, it returns Z_DATA_ERROR.
+
+ inflate() should normally be called until it returns Z_STREAM_END or an
+ error. However if all decompression is to be performed in a single step
+ (a single call of inflate), the parameter flush should be set to
+ Z_FINISH. In this case all pending input is processed and all pending
+ output is flushed; avail_out must be large enough to hold all the
+ uncompressed data. (The size of the uncompressed data may have been saved
+ by the compressor for this purpose.) The next operation on this stream must
+ be inflateEnd to deallocate the decompression state. The use of Z_FINISH
+ is never required, but can be used to inform inflate that a faster routine
+ may be used for the single inflate() call.
+
+ inflate() returns Z_OK if some progress has been made (more input
+ processed or more output produced), Z_STREAM_END if the end of the
+ compressed data has been reached and all uncompressed output has been
+ produced, Z_NEED_DICT if a preset dictionary is needed at this point (see
+ inflateSetDictionary below), Z_DATA_ERROR if the input data was corrupted,
+ Z_STREAM_ERROR if the stream structure was inconsistent (for example if
+ next_in or next_out was NULL), Z_MEM_ERROR if there was not enough memory,
+ Z_BUF_ERROR if no progress is possible or if there was not enough room in
+ the output buffer when Z_FINISH is used. In the Z_DATA_ERROR case, the
+ application may then call inflateSync to look for a good compression block.
+ In the Z_NEED_DICT case, strm->adler is set to the Adler32 value of the
+ dictionary chosen by the compressor.
+*/
+
+
+extern int EXPORT inflateEnd OF((z_streamp strm));
+/*
+ All dynamically allocated data structures for this stream are freed.
+ This function discards any unprocessed input and does not flush any
+ pending output.
+
+ inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state
+ was inconsistent. In the error case, msg may be set but then points to a
+ static string (which must not be deallocated).
+*/
+
+ /* Advanced functions */
+
+/*
+ The following functions are needed only in some special applications.
+*/
+
+/*
+extern int EXPORT deflateInit2 OF((z_streamp strm,
+ int level,
+ int method,
+ int windowBits,
+ int memLevel,
+ int strategy));
+
+ This is another version of deflateInit with more compression options. The
+ fields next_in, zalloc, zfree and opaque must be initialized before by
+ the caller.
+
+ The method parameter is the compression method. It must be Z_DEFLATED in
+ this version of the library. (Method 9 will allow a 64K history buffer and
+ partial block flushes.)
+
+ The windowBits parameter is the base two logarithm of the window size
+ (the size of the history buffer). It should be in the range 8..15 for this
+ version of the library (the value 16 will be allowed for method 9). Larger
+ values of this parameter result in better compression at the expense of
+ memory usage. The default value is 15 if deflateInit is used instead.
+
+ The memLevel parameter specifies how much memory should be allocated
+ for the internal compression state. memLevel=1 uses minimum memory but
+ is slow and reduces compression ratio; memLevel=9 uses maximum memory
+ for optimal speed. The default value is 8. See zconf.h for total memory
+ usage as a function of windowBits and memLevel.
+
+ The strategy parameter is used to tune the compression algorithm. Use the
+ value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a
+ filter (or predictor), or Z_HUFFMAN_ONLY to force Huffman encoding only (no
+ string match). Filtered data consists mostly of small values with a
+ somewhat random distribution. In this case, the compression algorithm is
+ tuned to compress them better. The effect of Z_FILTERED is to force more
+ Huffman coding and less string matching; it is somewhat intermediate
+ between Z_DEFAULT and Z_HUFFMAN_ONLY. The strategy parameter only affects
+ the compression ratio but not the correctness of the compressed output even
+ if it is not set appropriately.
+
+ If next_in is not null, the library will use this buffer to hold also
+ some history information; the buffer must either hold the entire input
+ data, or have at least 1<<(windowBits+1) bytes and be writable. If next_in
+ is null, the library will allocate its own history buffer (and leave next_in
+ null). next_out need not be provided here but must be provided by the
+ application for the next call of deflate().
+
+ If the history buffer is provided by the application, next_in must
+ must never be changed by the application since the compressor maintains
+ information inside this buffer from call to call; the application
+ must provide more input only by increasing avail_in. next_in is always
+ reset by the library in this case.
+
+ deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was
+ not enough memory, Z_STREAM_ERROR if a parameter is invalid (such as
+ an invalid method). msg is set to null if there is no error message.
+ deflateInit2 does not perform any compression: this will be done by
+ deflate().
+*/
+
+extern int EXPORT deflateSetDictionary OF((z_streamp strm,
+ const Bytef *dictionary,
+ uInt dictLength));
+/*
+ Initializes the compression dictionary (history buffer) from the given
+ byte sequence without producing any compressed output. This function must
+ be called immediately after deflateInit or deflateInit2, before any call
+ of deflate. The compressor and decompressor must use exactly the same
+ dictionary (see inflateSetDictionary).
+ The dictionary should consist of strings (byte sequences) that are likely
+ to be encountered later in the data to be compressed, with the most commonly
+ used strings preferably put towards the end of the dictionary. Using a
+ dictionary is most useful when the data to be compressed is short and
+ can be predicted with good accuracy; the data can then be compressed better
+ than with the default empty dictionary. In this version of the library,
+ only the last 32K bytes of the dictionary are used.
+ Upon return of this function, strm->adler is set to the Adler32 value
+ of the dictionary; the decompressor may later use this value to determine
+ which dictionary has been used by the compressor. (The Adler32 value
+ applies to the whole dictionary even if only a subset of the dictionary is
+ actually used by the compressor.)
+
+ deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a
+ parameter is invalid (such as NULL dictionary) or the stream state
+ is inconsistent (for example if deflate has already been called for this
+ stream). deflateSetDictionary does not perform any compression: this will
+ be done by deflate().
+*/
+
+extern int EXPORT deflateCopy OF((z_streamp dest,
+ z_streamp source));
+/*
+ Sets the destination stream as a complete copy of the source stream. If
+ the source stream is using an application-supplied history buffer, a new
+ buffer is allocated for the destination stream. The compressed output
+ buffer is always application-supplied. It's the responsibility of the
+ application to provide the correct values of next_out and avail_out for the
+ next call of deflate.
+
+ This function can be useful when several compression strategies will be
+ tried, for example when there are several ways of pre-processing the input
+ data with a filter. The streams that will be discarded should then be freed
+ by calling deflateEnd. Note that deflateCopy duplicates the internal
+ compression state which can be quite large, so this strategy is slow and
+ can consume lots of memory.
+
+ deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
+ (such as zalloc being NULL). msg is left unchanged in both source and
+ destination.
+*/
+
+extern int EXPORT deflateReset OF((z_streamp strm));
+/*
+ This function is equivalent to deflateEnd followed by deflateInit,
+ but does not free and reallocate all the internal compression state.
+ The stream will keep the same compression level and any other attributes
+ that may have been set by deflateInit2.
+
+ deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent (such as zalloc or state being NULL).
+*/
+
+extern int EXPORT deflateParams OF((z_streamp strm, int level, int strategy));
+/*
+ Dynamically update the compression level and compression strategy.
+ This can be used to switch between compression and straight copy of
+ the input data, or to switch to a different kind of input data requiring
+ a different strategy. If the compression level is changed, the input
+ available so far is compressed with the old level (and may be flushed);
+ the new level will take effect only at the next call of deflate().
+
+ Before the call of deflateParams, the stream state must be set as for
+ a call of deflate(), since the currently available input may have to
+ be compressed and flushed. In particular, strm->avail_out must be non-zero.
+
+ deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source
+ stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR
+ if strm->avail_out was zero.
+*/
+
+extern int EXPORT deflateOutputPending OF((z_streamp strm));
+/*
+ Returns the number of bytes of output which are immediately
+ available from the compressor (i.e. without any further input
+ or flush).
+*/
+
+/*
+extern int EXPORT inflateInit2 OF((z_streamp strm,
+ int windowBits));
+
+ This is another version of inflateInit with more compression options. The
+ fields next_out, zalloc, zfree and opaque must be initialized before by
+ the caller.
+
+ The windowBits parameter is the base two logarithm of the maximum window
+ size (the size of the history buffer). It should be in the range 8..15 for
+ this version of the library (the value 16 will be allowed soon). The
+ default value is 15 if inflateInit is used instead. If a compressed stream
+ with a larger window size is given as input, inflate() will return with
+ the error code Z_DATA_ERROR instead of trying to allocate a larger window.
+
+ If next_out is not null, the library will use this buffer for the history
+ buffer; the buffer must either be large enough to hold the entire output
+ data, or have at least 1<<windowBits bytes. If next_out is null, the
+ library will allocate its own buffer (and leave next_out null). next_in
+ need not be provided here but must be provided by the application for the
+ next call of inflate().
+
+ If the history buffer is provided by the application, next_out must
+ never be changed by the application since the decompressor maintains
+ history information inside this buffer from call to call; the application
+ can only reset next_out to the beginning of the history buffer when
+ avail_out is zero and all output has been consumed.
+
+ inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was
+ not enough memory, Z_STREAM_ERROR if a parameter is invalid (such as
+ windowBits < 8). msg is set to null if there is no error message.
+ inflateInit2 does not perform any decompression: this will be done by
+ inflate().
+*/
+
+extern int EXPORT inflateSetDictionary OF((z_streamp strm,
+ const Bytef *dictionary,
+ uInt dictLength));
+/*
+ Initializes the decompression dictionary (history buffer) from the given
+ uncompressed byte sequence. This function must be called immediately after
+ a call of inflate if this call returned Z_NEED_DICT. The dictionary chosen
+ by the compressor can be determined from the Adler32 value returned by this
+ call of inflate. The compressor and decompressor must use exactly the same
+ dictionary (see deflateSetDictionary).
+
+ inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a
+ parameter is invalid (such as NULL dictionary) or the stream state is
+ inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the
+ expected one (incorrect Adler32 value). inflateSetDictionary does not
+ perform any decompression: this will be done by subsequent calls of
+ inflate().
+*/
+
+extern int EXPORT inflateSync OF((z_streamp strm));
+/*
+ Skips invalid compressed data until the special marker (see deflate()
+ above) can be found, or until all available input is skipped. No output
+ is provided.
+
+ inflateSync returns Z_OK if the special marker has been found, Z_BUF_ERROR
+ if no more input was provided, Z_DATA_ERROR if no marker has been found,
+ or Z_STREAM_ERROR if the stream structure was inconsistent. In the success
+ case, the application may save the current current value of total_in which
+ indicates where valid compressed data was found. In the error case, the
+ application may repeatedly call inflateSync, providing more input each time,
+ until success or end of the input data.
+*/
+
+extern int EXPORT inflateReset OF((z_streamp strm));
+/*
+ This function is equivalent to inflateEnd followed by inflateInit,
+ but does not free and reallocate all the internal decompression state.
+ The stream will keep attributes that may have been set by inflateInit2.
+
+ inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent (such as zalloc or state being NULL).
+*/
+
+extern int inflateIncomp OF((z_stream *strm));
+/*
+ This function adds the data at next_in (avail_in bytes) to the output
+ history without performing any output. There must be no pending output,
+ and the decompressor must be expecting to see the start of a block.
+ Calling this function is equivalent to decompressing a stored block
+ containing the data at next_in (except that the data is not output).
+*/
+
+ /* utility functions */
+
+/*
+ The following utility functions are implemented on top of the
+ basic stream-oriented functions. To simplify the interface, some
+ default options are assumed (compression level, window size,
+ standard memory allocation functions). The source code of these
+ utility functions can easily be modified if you need special options.
+*/
+
+extern int EXPORT compress OF((Bytef *dest, uLongf *destLen,
+ const Bytef *source, uLong sourceLen));
+/*
+ Compresses the source buffer into the destination buffer. sourceLen is
+ the byte length of the source buffer. Upon entry, destLen is the total
+ size of the destination buffer, which must be at least 0.1% larger than
+ sourceLen plus 12 bytes. Upon exit, destLen is the actual size of the
+ compressed buffer.
+ This function can be used to compress a whole file at once if the
+ input file is mmap'ed.
+ compress returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_BUF_ERROR if there was not enough room in the output
+ buffer.
+*/
+
+extern int EXPORT uncompress OF((Bytef *dest, uLongf *destLen,
+ const Bytef *source, uLong sourceLen));
+/*
+ Decompresses the source buffer into the destination buffer. sourceLen is
+ the byte length of the source buffer. Upon entry, destLen is the total
+ size of the destination buffer, which must be large enough to hold the
+ entire uncompressed data. (The size of the uncompressed data must have
+ been saved previously by the compressor and transmitted to the decompressor
+ by some mechanism outside the scope of this compression library.)
+ Upon exit, destLen is the actual size of the compressed buffer.
+ This function can be used to decompress a whole file at once if the
+ input file is mmap'ed.
+
+ uncompress returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_BUF_ERROR if there was not enough room in the output
+ buffer, or Z_DATA_ERROR if the input data was corrupted.
+*/
+
+
+typedef voidp gzFile;
+
+extern gzFile EXPORT gzopen OF((const char *path, const char *mode));
+/*
+ Opens a gzip (.gz) file for reading or writing. The mode parameter
+ is as in fopen ("rb" or "wb") but can also include a compression level
+ ("wb9"). gzopen can be used to read a file which is not in gzip format;
+ in this case gzread will directly read from the file without decompression.
+ gzopen returns NULL if the file could not be opened or if there was
+ insufficient memory to allocate the (de)compression state; errno
+ can be checked to distinguish the two cases (if errno is zero, the
+ zlib error is Z_MEM_ERROR).
+*/
+
+extern gzFile EXPORT gzdopen OF((int fd, const char *mode));
+/*
+ gzdopen() associates a gzFile with the file descriptor fd. File
+ descriptors are obtained from calls like open, dup, creat, pipe or
+ fileno (in the file has been previously opened with fopen).
+ The mode parameter is as in gzopen.
+ The next call of gzclose on the returned gzFile will also close the
+ file descriptor fd, just like fclose(fdopen(fd), mode) closes the file
+ descriptor fd. If you want to keep fd open, use gzdopen(dup(fd), mode).
+ gzdopen returns NULL if there was insufficient memory to allocate
+ the (de)compression state.
+*/
+
+extern int EXPORT gzread OF((gzFile file, voidp buf, unsigned len));
+/*
+ Reads the given number of uncompressed bytes from the compressed file.
+ If the input file was not in gzip format, gzread copies the given number
+ of bytes into the buffer.
+ gzread returns the number of uncompressed bytes actually read (0 for
+ end of file, -1 for error). */
+
+extern int EXPORT gzwrite OF((gzFile file, const voidp buf, unsigned len));
+/*
+ Writes the given number of uncompressed bytes into the compressed file.
+ gzwrite returns the number of uncompressed bytes actually written
+ (0 in case of error).
+*/
+
+extern int EXPORT gzflush OF((gzFile file, int flush));
+/*
+ Flushes all pending output into the compressed file. The parameter
+ flush is as in the deflate() function. The return value is the zlib
+ error number (see function gzerror below). gzflush returns Z_OK if
+ the flush parameter is Z_FINISH and all output could be flushed.
+ gzflush should be called only when strictly necessary because it can
+ degrade compression.
+*/
+
+extern int EXPORT gzclose OF((gzFile file));
+/*
+ Flushes all pending output if necessary, closes the compressed file
+ and deallocates all the (de)compression state. The return value is the zlib
+ error number (see function gzerror below).
+*/
+
+extern const char * EXPORT gzerror OF((gzFile file, int *errnum));
+/*
+ Returns the error message for the last error which occurred on the
+ given compressed file. errnum is set to zlib error number. If an
+ error occurred in the file system and not in the compression library,
+ errnum is set to Z_ERRNO and the application may consult errno
+ to get the exact error code.
+*/
+
+ /* checksum functions */
+
+/*
+ These functions are not related to compression but are exported
+ anyway because they might be useful in applications using the
+ compression library.
+*/
+
+extern uLong EXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len));
+
+/*
+ Update a running Adler-32 checksum with the bytes buf[0..len-1] and
+ return the updated checksum. If buf is NULL, this function returns
+ the required initial value for the checksum.
+ An Adler-32 checksum is almost as reliable as a CRC32 but can be computed
+ much faster. Usage example:
+
+ uLong adler = adler32(0L, Z_NULL, 0);
+
+ while (read_buffer(buffer, length) != EOF) {
+ adler = adler32(adler, buffer, length);
+ }
+ if (adler != original_adler) error();
+*/
+
+extern uLong EXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len));
+/*
+ Update a running crc with the bytes buf[0..len-1] and return the updated
+ crc. If buf is NULL, this function returns the required initial value
+ for the crc. Pre- and post-conditioning (one's complement) is performed
+ within this function so it shouldn't be done by the application.
+ Usage example:
+
+ uLong crc = crc32(0L, Z_NULL, 0);
+
+ while (read_buffer(buffer, length) != EOF) {
+ crc = crc32(crc, buffer, length);
+ }
+ if (crc != original_crc) error();
+*/
+
+
+ /* various hacks, don't look :) */
+
+/* deflateInit and inflateInit are macros to allow checking the zlib version
+ * and the compiler's view of z_stream:
+ */
+extern int EXPORT deflateInit_ OF((z_streamp strm, int level,
+ const char *version, int stream_size));
+extern int EXPORT inflateInit_ OF((z_streamp strm,
+ const char *version, int stream_size));
+extern int EXPORT deflateInit2_ OF((z_streamp strm, int level, int method,
+ int windowBits, int memLevel, int strategy,
+ const char *version, int stream_size));
+extern int EXPORT inflateInit2_ OF((z_streamp strm, int windowBits,
+ const char *version, int stream_size));
+#define deflateInit(strm, level) \
+ deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream))
+#define inflateInit(strm) \
+ inflateInit_((strm), ZLIB_VERSION, sizeof(z_stream))
+#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \
+ deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\
+ (strategy), ZLIB_VERSION, sizeof(z_stream))
+#define inflateInit2(strm, windowBits) \
+ inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream))
+
+#if !defined(_Z_UTIL_H) && !defined(NO_DUMMY_DECL)
+ struct internal_state {int dummy;}; /* hack for buggy compilers */
+#endif
+
+uLongf *get_crc_table OF((void)); /* can be used by asm versions of crc32() */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _ZLIB_H */
+/* --- zlib.h */
diff --git a/mdk-stage1/ppp/configure b/mdk-stage1/ppp/configure
new file mode 100755
index 000000000..2e3b3b291
--- /dev/null
+++ b/mdk-stage1/ppp/configure
@@ -0,0 +1,141 @@
+#!/bin/sh
+# $Id: configure 195720 2001-06-11 11:44:34Z gc $
+
+# if [ -d /NextApps ]; then
+# system="NeXTStep"
+# else
+ system=`uname -s`
+ release=`uname -r`
+ machine=`uname -p`
+ arch=`uname -m`
+# fi
+state="unknown"
+
+case $system in
+ Linux)
+ makext="linux";
+ ksrc="linux";
+ state="known";;
+ SunOS)
+ case $release in
+# [0-3]*) state="ancient";;
+# 4*) state="known"; ksrc="sunos4"; makext="sunos4";;
+ 5.[1-6]*) state="known"; ksrc="solaris"; makext="sol2";;
+ 5.[7-9]*) state="known"; ksrc="solaris"; makext="sol2";
+ case $arch in
+ sun4u) lp64='y';;
+ *) ;;
+ esac;;
+ esac;;
+ NetBSD|FreeBSD|ULTRIX|OSF1|NeXTStep|SINIX-?|UNIX_SV|UNIX_System_V)
+ state="notincluded";;
+# NetBSD)
+# makext="bsd";
+# case $release in
+# 0.*) state="ancient";;
+# 1.0*) state="ancient";;
+# 1.1*) state="known"; ksrc="netbsd-1.1";;
+# 1.2*) state="known"; ksrc="netbsd-1.2"; makext="netbsd-1.2";;
+# 1.[3-9]*|[2-9]*)
+# state="late"; ksrc="netbsd-1.2";;
+# esac;;
+# ULTRIX)
+# makext="ultrix";
+# case $release in
+# [0-3]*) state="ancient";;
+# 4.[01]*) state="early"; ksrc="ultrix";;
+# 4.[234]) state="known"; ksrc="ultrix";;
+# esac;;
+# OSF1)
+# makext="osf";
+# case $release in
+# V1.*) state="neolithic"; ksrc="osf1";;
+# V[23].*) state="neolithic"; ksrc="osf1";;
+# V4.*) state="known"; ksrc="osf1";;
+# V[5-9]*) state="late"; ksrc="osf1";;
+# esac;;
+# FreeBSD)
+# makext="bsd";
+# case $release in
+# 1.*) state="known"; ksrc="freebsd-old";;
+# 2.[01]*) state="known"; ksrc="freebsd-2.0";;
+# 2.2.[2-7]*) state="late"; ksrc="freebsd-2.0";;
+# 2.2.8*) state="known"; ksrc="freebsd-2.2.8";;
+# 3.[0-1]*) state="known"; ksrc="freebsd-3.0";;
+# esac;;
+# NeXTStep)
+# makext="NeXT";
+# ksrc="NeXT";
+# state="known";;
+# SINIX-?)
+# case $release in
+# 5.4[01]) state=known; ksrc=svr4; makext=svr4;;
+# 5.4[2-9]) state=late; ksrc=svr4; makext=svr4;;
+# esac;;
+# # Intel SVR4 systems come with a bug in the uname program. Unless
+# # your provider fixed the bug, or you get a fix for it, uname -S will
+# # overwrite the system name with the node name!
+# UNIX_SV|UNIX_System_V|`uname -n`)
+# case $release in
+# 4.0) state=known; ksrc=svr4; makext=svr4;;
+# 4.2) state=late; ksrc=svr4; makext=svr4;;
+# esac;;
+esac
+
+if [ -d "$ksrc" ]; then :; else
+ state="notincluded"
+ unset ksrc
+fi
+
+case $state in
+ neolithic)
+ echo "This is a newer release on an outdated OS ($system)."
+ echo " This software may or may not work on this OS."
+ echo " You may want to download an older version of PPP for this OS.";;
+ ancient)
+ echo "This is an old release of a supported OS ($system)."
+ echo "This software cannot be used as-is on this system,"
+ echo "but you may be able to port it. Good luck!"
+ exit;;
+ early)
+ echo "This is an old release of a supported OS ($system)."
+ echo "This software should install and run on this system,"
+ echo "but it hasn't been tested.";;
+ late)
+ echo "This is a newer release of $system than is supported by"
+ echo "this software. It may or may not work.";;
+ unknown)
+ echo "This software has not been ported to this system. Sorry.";;
+ notincluded)
+ echo "Support for this system has not been included"
+ echo "in this distribution. Sorry.";;
+esac
+
+orig_makext=$makext
+
+if [ -d "$ksrc" ]; then
+ echo "Creating links to Makefiles."
+ rm -f Makefile
+ ln -s $ksrc/Makefile.top Makefile
+ echo " Makefile -> $ksrc/Makefile.top"
+ if [ "$ksrc" = solaris ]; then
+ # Point to 64-bit Makefile extension
+ if [ "$lp64" = y ]; then
+ makext=$makext-64
+ fi
+ rm -f $ksrc/Makefile
+ ln -s Makefile.$makext $ksrc/Makefile
+ echo " $ksrc/Makefile -> Makefile.$makext"
+ # Restore extension
+ if [ "$lp64" = y ]; then
+ makext=$orig_makext
+ fi
+ fi
+ for dir in pppd pppstats chat pppdump; do
+ rm -f $dir/Makefile
+ if [ -f $dir/Makefile.$makext ]; then
+ ln -s Makefile.$makext $dir/Makefile
+ echo " $dir/Makefile -> Makefile.$makext"
+ fi
+ done
+fi
diff --git a/mdk-stage1/ppp/contrib/pppgetpass/Makefile.linux b/mdk-stage1/ppp/contrib/pppgetpass/Makefile.linux
new file mode 100644
index 000000000..7eb217dac
--- /dev/null
+++ b/mdk-stage1/ppp/contrib/pppgetpass/Makefile.linux
@@ -0,0 +1,16 @@
+all: pppgetpass.vt pppgetpass.gtk
+
+pppgetpass.vt: pppgetpass.vt.o
+
+pppgetpass.gtk: pppgetpass.gtk.o
+ $(CC) $(LDFLAGS) pppgetpass.gtk.o `gtk-config --libs` -o pppgetpass.gtk
+pppgetpass.gtk.o: pppgetpass.gtk.c
+ $(CC) $(CFLAGS) -c pppgetpass.gtk.c `gtk-config --cflags`
+
+install: all
+ install -m 755 pppgetpass.sh /usr/bin/pppgetpass
+ install -m 4755 -o root -g root pppgetpass.vt /usr/bin/
+ install -m 755 -o root -g root pppgetpass.gtk /usr/X11/bin/
+
+clean:
+ rm -f *.o pppgetpass.gtk pppgetpass.vt core
diff --git a/mdk-stage1/ppp/contrib/pppgetpass/pppgetpass.8 b/mdk-stage1/ppp/contrib/pppgetpass/pppgetpass.8
new file mode 100644
index 000000000..ade576970
--- /dev/null
+++ b/mdk-stage1/ppp/contrib/pppgetpass/pppgetpass.8
@@ -0,0 +1,18 @@
+.TH PPPGETPASS 8 "26 Sep 1999"
+.SH NAME
+pppgetpass \- prompt for PAP password
+.SH SYNOPSIS
+.B pppgetpass
+.I client server fd
+.SH DESCRIPTION
+.B pppgetpass
+the outer half of a plugin for PAP password prompting in pppd.
+If the peer requires PAP, and the
+.B passprompt.so
+plugin is loaded into pppd, it will run
+.B /usr/sbin/pppgetpass
+(or another program specified by the
+.B promptprog
+option) to prompt the user for the password.
+.SH SEE ALSO
+pppd(8)
diff --git a/mdk-stage1/ppp/contrib/pppgetpass/pppgetpass.gtk.c b/mdk-stage1/ppp/contrib/pppgetpass/pppgetpass.gtk.c
new file mode 100644
index 000000000..48ca04202
--- /dev/null
+++ b/mdk-stage1/ppp/contrib/pppgetpass/pppgetpass.gtk.c
@@ -0,0 +1,92 @@
+#include <glib.h>
+#include <gdk/gdk.h>
+#include <gtk/gtkwindow.h>
+#include <gtk/gtkmain.h>
+#include <gtk/gtkbutton.h>
+#include <gtk/gtkvbox.h>
+#include <gtk/gtklabel.h>
+#include <gtk/gtkentry.h>
+#include <gtk/gtksignal.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <syslog.h>
+
+int outfd;
+int err;
+
+static void okpressed(void *widget, void *clientdata)
+{
+ GtkWidget *answer=clientdata;
+ gchar *pass;
+ int passlen;
+ ssize_t wrote;
+ (void)widget;
+
+ pass=gtk_entry_get_text(GTK_ENTRY(answer));
+
+ passlen=strlen(pass);
+ if(!passlen)
+ return;
+
+ if((wrote=write(outfd, pass, passlen))!=passlen) {
+ if(wrote<0)
+ syslog(LOG_ERR, "write error on outpipe: %m");
+ else
+ syslog(LOG_ERR, "short write on outpipe");
+ err=1;
+ }
+ gtk_main_quit();
+}
+
+int main(int argc, char **argv)
+{
+ GtkWidget *mainwindow, *vbox, *question, *answer, *ok;
+ char buf[1024];
+ gtk_init(&argc, &argv);
+
+ openlog(argv[0], LOG_PID, LOG_DAEMON);
+ if(argc!=4) {
+ syslog(LOG_WARNING, "Usage error");
+ return 1;
+ }
+ outfd=atoi(argv[3]);
+ mainwindow=gtk_window_new(GTK_WINDOW_TOPLEVEL);
+ gtk_window_set_title(GTK_WINDOW(mainwindow), "pppgetpass");
+ gtk_signal_connect(GTK_OBJECT(mainwindow), "destroy",
+ GTK_SIGNAL_FUNC(gtk_main_quit), 0);
+
+ vbox=gtk_vbox_new(FALSE, 5);
+ gtk_container_add(GTK_CONTAINER(mainwindow), vbox);
+ gtk_widget_show(vbox);
+
+ if(argv[1][0] && argv[2][0])
+ snprintf(buf, sizeof buf, "Password for PPP client %s on server %s: ", argv[1], argv[2]);
+ else if(argv[1][0] && !argv[2][0])
+ snprintf(buf, sizeof buf, "Password for PPP client %s: ", argv[1]);
+ else if(!argv[1][0] && argv[2][0])
+ snprintf(buf, sizeof buf, "Password for PPP on server %s: ", argv[2]);
+ else
+ snprintf(buf, sizeof buf, "Enter PPP password: ");
+ question=gtk_label_new(buf);
+ gtk_box_pack_start(GTK_BOX(vbox), question, FALSE, TRUE, 0);
+ gtk_widget_show(question);
+
+ answer=gtk_entry_new();
+ gtk_entry_set_visibility(GTK_ENTRY(answer), 0);
+ gtk_box_pack_start(GTK_BOX(vbox), answer, FALSE, TRUE, 0);
+ gtk_widget_show(answer);
+
+ ok=gtk_button_new_with_label("OK");
+ gtk_box_pack_start(GTK_BOX(vbox), ok, FALSE, TRUE, 0);
+ gtk_signal_connect(GTK_OBJECT(ok), "clicked",
+ GTK_SIGNAL_FUNC(okpressed), answer);
+ gtk_widget_show(ok);
+
+ gtk_widget_show(mainwindow);
+ gtk_main();
+
+ return err;
+}
diff --git a/mdk-stage1/ppp/contrib/pppgetpass/pppgetpass.sh b/mdk-stage1/ppp/contrib/pppgetpass/pppgetpass.sh
new file mode 100755
index 000000000..09c480519
--- /dev/null
+++ b/mdk-stage1/ppp/contrib/pppgetpass/pppgetpass.sh
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+if [ -z "$DISPLAY" ]; then
+ exec pppgetpass.vt "$@"
+else
+ exec pppgetpass.gtk "$@"
+fi
diff --git a/mdk-stage1/ppp/contrib/pppgetpass/pppgetpass.vt.c b/mdk-stage1/ppp/contrib/pppgetpass/pppgetpass.vt.c
new file mode 100644
index 000000000..a1520883c
--- /dev/null
+++ b/mdk-stage1/ppp/contrib/pppgetpass/pppgetpass.vt.c
@@ -0,0 +1,218 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <syslog.h>
+#include <termios.h>
+#include <sys/vt.h>
+
+static int console_owner(uid_t, int);
+
+int main(int argc, char **argv)
+{
+ int console;
+ uid_t uid;
+ struct vt_stat origstate;
+ int openvtnum;
+ char openvtname[256];
+ int openvt;
+ gid_t gid;
+ int chowned;
+ FILE *fp;
+ struct termios t;
+ char pass[256], *nl;
+ int outfd, passlen;
+ ssize_t wrote;
+ console=open("/dev/console", O_RDWR);
+
+ uid=getuid();
+ gid=getgid();
+ seteuid(uid);
+
+ openlog(argv[0], LOG_PID, LOG_DAEMON);
+
+ if(argc!=4) {
+ syslog(LOG_WARNING, "Usage error");
+ return 1;
+ }
+
+ if(console<0) {
+ syslog(LOG_ERR, "open(/dev/console): %m");
+ return 1;
+ }
+
+ if(ioctl(console, VT_GETSTATE, &origstate)<0) {
+ syslog(LOG_ERR, "VT_GETSTATE: %m");
+ return 1;
+ }
+
+ if(uid) {
+ if(!console_owner(uid, origstate.v_active)) {
+ int i;
+ for(i=0;i<64;++i) {
+ if(i!=origstate.v_active && console_owner(uid, i))
+ break;
+ }
+ if(i==64) {
+ syslog(LOG_WARNING, "run by uid %lu not at console", (unsigned long)uid);
+ return 1;
+ }
+ }
+ }
+
+ if(ioctl(console, VT_OPENQRY, &openvtnum)<0) {
+ syslog(LOG_ERR, "VT_OPENQRY: %m");
+ return 1;
+ }
+ if(openvtnum==-1) {
+ syslog(LOG_ERR, "No free VTs");
+ return 1;
+ }
+
+ snprintf(openvtname, sizeof openvtname, "/dev/tty%d", openvtnum);
+ seteuid(0);
+ openvt=open(openvtname, O_RDWR);
+ if(openvt<0) {
+ seteuid(uid);
+ syslog(LOG_ERR, "open(%s): %m", openvtname);
+ return 1;
+ }
+
+ chowned=fchown(openvt, uid, gid);
+ if(chowned<0) {
+ seteuid(uid);
+ syslog(LOG_ERR, "fchown(%s): %m", openvtname);
+ return 1;
+ }
+
+ close(console);
+
+ if(ioctl(openvt, VT_ACTIVATE, openvtnum)<0) {
+ seteuid(uid);
+ syslog(LOG_ERR, "VT_ACTIVATE(%d): %m", openvtnum);
+ return 1;
+ }
+
+ while(ioctl(openvt, VT_WAITACTIVE, openvtnum)<0) {
+ if(errno!=EINTR) {
+ ioctl(openvt, VT_ACTIVATE, origstate.v_active);
+ seteuid(uid);
+ syslog(LOG_ERR, "VT_WAITACTIVE(%d): %m", openvtnum);
+ return 1;
+ }
+ }
+
+ seteuid(uid);
+ fp=fdopen(openvt, "r+");
+ if(!fp) {
+ seteuid(0);
+ ioctl(openvt, VT_ACTIVATE, origstate.v_active);
+ seteuid(uid);
+ syslog(LOG_ERR, "fdopen(%s): %m", openvtname);
+ return 1;
+ }
+
+ if(tcgetattr(openvt, &t)<0) {
+ seteuid(0);
+ ioctl(openvt, VT_ACTIVATE, origstate.v_active);
+ seteuid(uid);
+ syslog(LOG_ERR, "tcgetattr(%s): %m", openvtname);
+ return 1;
+ }
+ t.c_lflag &= ~ECHO;
+ if(tcsetattr(openvt, TCSANOW, &t)<0) {
+ seteuid(0);
+ ioctl(openvt, VT_ACTIVATE, origstate.v_active);
+ seteuid(uid);
+ syslog(LOG_ERR, "tcsetattr(%s): %m", openvtname);
+ return 1;
+ }
+
+ if(fprintf(fp, "\033[2J\033[H")<0) {
+ seteuid(0);
+ ioctl(openvt, VT_ACTIVATE, origstate.v_active);
+ seteuid(uid);
+ syslog(LOG_ERR, "write error on %s: %m", openvtname);
+ return 1;
+ }
+ if(argv[1][0] && argv[2][0]) {
+ if(fprintf(fp, "Password for PPP client %s on server %s: ", argv[1], argv[2])<0) {
+ seteuid(0);
+ ioctl(openvt, VT_ACTIVATE, origstate.v_active);
+ seteuid(uid);
+ syslog(LOG_ERR, "write error on %s: %m", openvtname);
+ return 1;
+ }
+ } else if(argv[1][0] && !argv[2][0]) {
+ if(fprintf(fp, "Password for PPP client %s: ", argv[1])<0) {
+ syslog(LOG_ERR, "write error on %s: %m", openvtname);
+ seteuid(0);
+ ioctl(openvt, VT_ACTIVATE, origstate.v_active);
+ seteuid(uid);
+ return 1;
+ }
+ } else if(!argv[1][0] && argv[2][0]) {
+ if(fprintf(fp, "Password for PPP on server %s: ", argv[2])<0) {
+ seteuid(0);
+ ioctl(openvt, VT_ACTIVATE, origstate.v_active);
+ seteuid(uid);
+ syslog(LOG_ERR, "write error on %s: %m", openvtname);
+ return 1;
+ }
+ } else {
+ if(fprintf(fp, "Enter PPP password: ")<0) {
+ seteuid(0);
+ ioctl(openvt, VT_ACTIVATE, origstate.v_active);
+ seteuid(uid);
+ syslog(LOG_ERR, "write error on %s: %m", openvtname);
+ return 1;
+ }
+ }
+
+ if(!fgets(pass, sizeof pass, fp)) {
+ seteuid(0);
+ ioctl(openvt, VT_ACTIVATE, origstate.v_active);
+ seteuid(uid);
+ if(ferror(fp)) {
+ syslog(LOG_ERR, "read error on %s: %m", openvtname);
+ }
+ return 1;
+ }
+ if((nl=strchr(pass, '\n')))
+ *nl=0;
+ passlen=strlen(pass);
+
+ outfd=atoi(argv[3]);
+ if((wrote=write(outfd, pass, passlen))!=passlen) {
+ seteuid(0);
+ ioctl(openvt, VT_ACTIVATE, origstate.v_active);
+ seteuid(uid);
+ if(wrote<0)
+ syslog(LOG_ERR, "write error on outpipe: %m");
+ else
+ syslog(LOG_ERR, "short write on outpipe");
+ return 1;
+ }
+
+ seteuid(0);
+ ioctl(openvt, VT_ACTIVATE, origstate.v_active);
+ seteuid(uid);
+ return 0;
+}
+
+static int console_owner(uid_t uid, int cons)
+{
+ char name[256];
+ struct stat st;
+ snprintf(name, sizeof name, "/dev/tty%d", cons);
+ if(stat(name, &st)<0) {
+ if(errno!=ENOENT)
+ syslog(LOG_ERR, "stat(%s): %m", name);
+ return 0;
+ }
+ return uid==st.st_uid;
+}
diff --git a/mdk-stage1/ppp/etc.ppp/chap-secrets b/mdk-stage1/ppp/etc.ppp/chap-secrets
new file mode 100644
index 000000000..7d1c3cd7c
--- /dev/null
+++ b/mdk-stage1/ppp/etc.ppp/chap-secrets
@@ -0,0 +1,2 @@
+# Secrets for authentication using CHAP
+# client server secret IP addresses
diff --git a/mdk-stage1/ppp/etc.ppp/options b/mdk-stage1/ppp/etc.ppp/options
new file mode 100644
index 000000000..0f77a9aa0
--- /dev/null
+++ b/mdk-stage1/ppp/etc.ppp/options
@@ -0,0 +1,5 @@
+lock
+noauth
+noipdefault
+usepeerdns
+
diff --git a/mdk-stage1/ppp/etc.ppp/options.options b/mdk-stage1/ppp/etc.ppp/options.options
new file mode 100644
index 000000000..4b67b6a0d
--- /dev/null
+++ b/mdk-stage1/ppp/etc.ppp/options.options
@@ -0,0 +1 @@
+lock
diff --git a/mdk-stage1/ppp/etc.ppp/pap-secrets b/mdk-stage1/ppp/etc.ppp/pap-secrets
new file mode 100644
index 000000000..f8b7dce3c
--- /dev/null
+++ b/mdk-stage1/ppp/etc.ppp/pap-secrets
@@ -0,0 +1,2 @@
+# Secrets for authentication using PAP
+# client server secret IP addresses
diff --git a/mdk-stage1/ppp/include/linux/if_ppp.h b/mdk-stage1/ppp/include/linux/if_ppp.h
new file mode 100644
index 000000000..f794da06a
--- /dev/null
+++ b/mdk-stage1/ppp/include/linux/if_ppp.h
@@ -0,0 +1,155 @@
+/* $Id: if_ppp.h 195720 2001-06-11 11:44:34Z gc $ */
+
+/*
+ * if_ppp.h - Point-to-Point Protocol definitions.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ */
+
+/*
+ * ==FILEVERSION 20000724==
+ *
+ * NOTE TO MAINTAINERS:
+ * If you modify this file at all, please set the above date.
+ * if_ppp.h is shipped with a PPP distribution as well as with the kernel;
+ * if everyone increases the FILEVERSION number above, then scripts
+ * can do the right thing when deciding whether to install a new if_ppp.h
+ * file. Don't change the format of that line otherwise, so the
+ * installation script can recognize it.
+ */
+
+#ifndef _IF_PPP_H_
+#define _IF_PPP_H_
+
+/*
+ * Packet sizes
+ */
+
+#define PPP_MTU 1500 /* Default MTU (size of Info field) */
+#define PPP_MAXMRU 65000 /* Largest MRU we allow */
+#define PROTO_IPX 0x002b /* protocol numbers */
+#define PROTO_DNA_RT 0x0027 /* DNA Routing */
+
+
+/*
+ * Bit definitions for flags.
+ */
+
+#define SC_COMP_PROT 0x00000001 /* protocol compression (output) */
+#define SC_COMP_AC 0x00000002 /* header compression (output) */
+#define SC_COMP_TCP 0x00000004 /* TCP (VJ) compression (output) */
+#define SC_NO_TCP_CCID 0x00000008 /* disable VJ connection-id comp. */
+#define SC_REJ_COMP_AC 0x00000010 /* reject adrs/ctrl comp. on input */
+#define SC_REJ_COMP_TCP 0x00000020 /* reject TCP (VJ) comp. on input */
+#define SC_CCP_OPEN 0x00000040 /* Look at CCP packets */
+#define SC_CCP_UP 0x00000080 /* May send/recv compressed packets */
+#define SC_ENABLE_IP 0x00000100 /* IP packets may be exchanged */
+#define SC_LOOP_TRAFFIC 0x00000200 /* send traffic to pppd */
+#define SC_MULTILINK 0x00000400 /* do multilink encapsulation */
+#define SC_MP_SHORTSEQ 0x00000800 /* use short MP sequence numbers */
+#define SC_COMP_RUN 0x00001000 /* compressor has been inited */
+#define SC_DECOMP_RUN 0x00002000 /* decompressor has been inited */
+#define SC_MP_XSHORTSEQ 0x00004000 /* transmit short MP seq numbers */
+#define SC_DEBUG 0x00010000 /* enable debug messages */
+#define SC_LOG_INPKT 0x00020000 /* log contents of good pkts recvd */
+#define SC_LOG_OUTPKT 0x00040000 /* log contents of pkts sent */
+#define SC_LOG_RAWIN 0x00080000 /* log all chars received */
+#define SC_LOG_FLUSH 0x00100000 /* log all chars flushed */
+#define SC_SYNC 0x00200000 /* synchronous serial mode */
+#define SC_MASK 0x0f200fff /* bits that user can change */
+
+/* state bits */
+#define SC_XMIT_BUSY 0x10000000 /* (used by isdn_ppp?) */
+#define SC_RCV_ODDP 0x08000000 /* have rcvd char with odd parity */
+#define SC_RCV_EVNP 0x04000000 /* have rcvd char with even parity */
+#define SC_RCV_B7_1 0x02000000 /* have rcvd char with bit 7 = 1 */
+#define SC_RCV_B7_0 0x01000000 /* have rcvd char with bit 7 = 0 */
+#define SC_DC_FERROR 0x00800000 /* fatal decomp error detected */
+#define SC_DC_ERROR 0x00400000 /* non-fatal decomp error detected */
+
+/*
+ * Ioctl definitions.
+ */
+
+struct npioctl {
+ int protocol; /* PPP protocol, e.g. PPP_IP */
+ enum NPmode mode;
+};
+
+/* Structure describing a CCP configuration option, for PPPIOCSCOMPRESS */
+struct ppp_option_data {
+ __u8 *ptr;
+ __u32 length;
+ int transmit;
+};
+
+struct ifpppstatsreq {
+ struct ifreq b;
+ struct ppp_stats stats; /* statistic information */
+};
+
+struct ifpppcstatsreq {
+ struct ifreq b;
+ struct ppp_comp_stats stats;
+};
+
+#define ifr__name b.ifr_ifrn.ifrn_name
+#define stats_ptr b.ifr_ifru.ifru_data
+
+/*
+ * Ioctl definitions.
+ */
+
+#define PPPIOCGFLAGS _IOR('t', 90, int) /* get configuration flags */
+#define PPPIOCSFLAGS _IOW('t', 89, int) /* set configuration flags */
+#define PPPIOCGASYNCMAP _IOR('t', 88, int) /* get async map */
+#define PPPIOCSASYNCMAP _IOW('t', 87, int) /* set async map */
+#define PPPIOCGUNIT _IOR('t', 86, int) /* get ppp unit number */
+#define PPPIOCGRASYNCMAP _IOR('t', 85, int) /* get receive async map */
+#define PPPIOCSRASYNCMAP _IOW('t', 84, int) /* set receive async map */
+#define PPPIOCGMRU _IOR('t', 83, int) /* get max receive unit */
+#define PPPIOCSMRU _IOW('t', 82, int) /* set max receive unit */
+#define PPPIOCSMAXCID _IOW('t', 81, int) /* set VJ max slot ID */
+#define PPPIOCGXASYNCMAP _IOR('t', 80, ext_accm) /* get extended ACCM */
+#define PPPIOCSXASYNCMAP _IOW('t', 79, ext_accm) /* set extended ACCM */
+#define PPPIOCXFERUNIT _IO('t', 78) /* transfer PPP unit */
+#define PPPIOCSCOMPRESS _IOW('t', 77, struct ppp_option_data)
+#define PPPIOCGNPMODE _IOWR('t', 76, struct npioctl) /* get NP mode */
+#define PPPIOCSNPMODE _IOW('t', 75, struct npioctl) /* set NP mode */
+#define PPPIOCSPASS _IOW('t', 71, struct sock_fprog) /* set pass filter */
+#define PPPIOCSACTIVE _IOW('t', 70, struct sock_fprog) /* set active filt */
+#define PPPIOCGDEBUG _IOR('t', 65, int) /* Read debug level */
+#define PPPIOCSDEBUG _IOW('t', 64, int) /* Set debug level */
+#define PPPIOCGIDLE _IOR('t', 63, struct ppp_idle) /* get idle time */
+#define PPPIOCNEWUNIT _IOWR('t', 62, int) /* create new ppp unit */
+#define PPPIOCATTACH _IOW('t', 61, int) /* attach to ppp unit */
+#define PPPIOCDETACH _IOW('t', 60, int) /* detach from ppp unit/chan */
+#define PPPIOCSMRRU _IOW('t', 59, int) /* set multilink MRU */
+#define PPPIOCCONNECT _IOW('t', 58, int) /* connect channel to unit */
+#define PPPIOCDISCONN _IO('t', 57) /* disconnect channel */
+#define PPPIOCATTCHAN _IOW('t', 56, int) /* attach to ppp channel */
+#define PPPIOCGCHAN _IOR('t', 55, int) /* get ppp channel number */
+
+#define SIOCGPPPSTATS (SIOCDEVPRIVATE + 0)
+#define SIOCGPPPVER (SIOCDEVPRIVATE + 1) /* NEVER change this!! */
+#define SIOCGPPPCSTATS (SIOCDEVPRIVATE + 2)
+
+#if !defined(ifr_mtu)
+#define ifr_mtu ifr_ifru.ifru_metric
+#endif
+
+#endif /* _IF_PPP_H_ */
diff --git a/mdk-stage1/ppp/include/linux/if_pppvar.h b/mdk-stage1/ppp/include/linux/if_pppvar.h
new file mode 100644
index 000000000..b2485cd9d
--- /dev/null
+++ b/mdk-stage1/ppp/include/linux/if_pppvar.h
@@ -0,0 +1,138 @@
+/* From: if_pppvar.h,v 1.2 1995/06/12 11:36:51 paulus Exp */
+/*
+ * if_pppvar.h - private structures and declarations for PPP.
+ *
+ * Copyright (c) 1994 The Australian National University.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation is hereby granted, provided that the above copyright
+ * notice appears in all copies. This software is provided without any
+ * warranty, express or implied. The Australian National University
+ * makes no representations about the suitability of this software for
+ * any purpose.
+ *
+ * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
+ * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
+ * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
+ * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
+ * OR MODIFICATIONS.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/*
+ * ==FILEVERSION 990911==
+ *
+ * NOTE TO MAINTAINERS:
+ * If you modify this file at all, please set the above date.
+ * if_pppvar.h is shipped with a PPP distribution as well as with the kernel;
+ * if everyone increases the FILEVERSION number above, then scripts
+ * can do the right thing when deciding whether to install a new if_pppvar.h
+ * file. Don't change the format of that line otherwise, so the
+ * installation script can recognize it.
+ */
+
+/*
+ * Supported network protocols. These values are used for
+ * indexing sc_npmode.
+ */
+
+#define NP_IP 0 /* Internet Protocol */
+#define NP_IPX 1 /* IPX protocol */
+#define NP_AT 2 /* Appletalk protocol */
+#define NP_IPV6 3 /* Internet Protocol */
+#define NUM_NP 4 /* Number of NPs. */
+
+#define OBUFSIZE 256 /* # chars of output buffering */
+
+/*
+ * Structure describing each ppp unit.
+ */
+
+struct ppp {
+ int magic; /* magic value for structure */
+ struct ppp *next; /* unit with next index */
+ unsigned long inuse; /* are we allocated? */
+ int line; /* network interface unit # */
+ __u32 flags; /* miscellaneous control flags */
+ int mtu; /* maximum xmit frame size */
+ int mru; /* maximum receive frame size */
+ struct slcompress *slcomp; /* for TCP header compression */
+ struct sk_buff_head xmt_q; /* frames to send from pppd */
+ struct sk_buff_head rcv_q; /* frames for pppd to read */
+ unsigned long xmit_busy; /* bit 0 set when xmitter busy */
+
+ /* Information specific to using ppp on async serial lines. */
+ struct tty_struct *tty; /* ptr to TTY structure */
+ struct tty_struct *backup_tty; /* TTY to use if tty gets closed */
+ __u8 escape; /* 0x20 if prev char was PPP_ESC */
+ __u8 toss; /* toss this frame */
+ volatile __u8 tty_pushing; /* internal state flag */
+ volatile __u8 woke_up; /* internal state flag */
+ __u32 xmit_async_map[8]; /* 1 bit means that given control
+ character is quoted on output*/
+ __u32 recv_async_map; /* 1 bit means that given control
+ character is ignored on input*/
+ __u32 bytes_sent; /* Bytes sent on frame */
+ __u32 bytes_rcvd; /* Bytes recvd on frame */
+
+ /* Async transmission information */
+ struct sk_buff *tpkt; /* frame currently being sent */
+ int tpkt_pos; /* how much of it we've done */
+ __u16 tfcs; /* FCS so far for it */
+ unsigned char *optr; /* where we're up to in sending */
+ unsigned char *olim; /* points past last valid char */
+
+ /* Async reception information */
+ struct sk_buff *rpkt; /* frame currently being rcvd */
+ __u16 rfcs; /* FCS so far of rpkt */
+
+ /* Queues for select() functionality */
+ struct wait_queue *read_wait; /* queue for reading processes */
+
+ /* info for detecting idle channels */
+ unsigned long last_xmit; /* time of last transmission */
+ unsigned long last_recv; /* time last packet received */
+
+ /* Statistic information */
+ struct pppstat stats; /* statistic information */
+
+ /* PPP compression protocol information */
+ struct compressor *sc_xcomp; /* transmit compressor */
+ void *sc_xc_state; /* transmit compressor state */
+ struct compressor *sc_rcomp; /* receive decompressor */
+ void *sc_rc_state; /* receive decompressor state */
+
+ enum NPmode sc_npmode[NUM_NP]; /* what to do with each NP */
+ int sc_xfer; /* PID of reserved PPP table */
+ char name[8]; /* space for unit name */
+ struct device dev; /* net device structure */
+ struct enet_statistics estats; /* more detailed stats */
+
+ /* tty output buffer */
+ unsigned char obuf[OBUFSIZE]; /* buffer for characters to send */
+};
+
+#define PPP_MAGIC 0x5002
+#define PPP_VERSION "2.3.11"
diff --git a/mdk-stage1/ppp/include/linux/ppp-comp.h b/mdk-stage1/ppp/include/linux/ppp-comp.h
new file mode 100644
index 000000000..a116be0cf
--- /dev/null
+++ b/mdk-stage1/ppp/include/linux/ppp-comp.h
@@ -0,0 +1,203 @@
+/*
+ * ppp-comp.h - Definitions for doing PPP packet compression.
+ *
+ * Copyright (c) 1994 The Australian National University.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation is hereby granted, provided that the above copyright
+ * notice appears in all copies. This software is provided without any
+ * warranty, express or implied. The Australian National University
+ * makes no representations about the suitability of this software for
+ * any purpose.
+ *
+ * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
+ * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
+ * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
+ * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
+ * OR MODIFICATIONS.
+ *
+ * $Id: ppp-comp.h 195720 2001-06-11 11:44:34Z gc $
+ */
+
+/*
+ * ==FILEVERSION 980319==
+ *
+ * NOTE TO MAINTAINERS:
+ * If you modify this file at all, please set the above date.
+ * ppp-comp.h is shipped with a PPP distribution as well as with the kernel;
+ * if everyone increases the FILEVERSION number above, then scripts
+ * can do the right thing when deciding whether to install a new ppp-comp.h
+ * file. Don't change the format of that line otherwise, so the
+ * installation script can recognize it.
+ */
+
+#ifndef _NET_PPP_COMP_H
+#define _NET_PPP_COMP_H
+
+/*
+ * The following symbols control whether we include code for
+ * various compression methods.
+ */
+
+#ifndef DO_BSD_COMPRESS
+#define DO_BSD_COMPRESS 1 /* by default, include BSD-Compress */
+#endif
+#ifndef DO_DEFLATE
+#define DO_DEFLATE 1 /* by default, include Deflate */
+#endif
+#define DO_PREDICTOR_1 0
+#define DO_PREDICTOR_2 0
+
+/*
+ * Structure giving methods for compression/decompression.
+ */
+
+struct compressor {
+ int compress_proto; /* CCP compression protocol number */
+
+ /* Allocate space for a compressor (transmit side) */
+ void *(*comp_alloc) (unsigned char *options, int opt_len);
+
+ /* Free space used by a compressor */
+ void (*comp_free) (void *state);
+
+ /* Initialize a compressor */
+ int (*comp_init) (void *state, unsigned char *options,
+ int opt_len, int unit, int opthdr, int debug);
+
+ /* Reset a compressor */
+ void (*comp_reset) (void *state);
+
+ /* Compress a packet */
+ int (*compress) (void *state, unsigned char *rptr,
+ unsigned char *obuf, int isize, int osize);
+
+ /* Return compression statistics */
+ void (*comp_stat) (void *state, struct compstat *stats);
+
+ /* Allocate space for a decompressor (receive side) */
+ void *(*decomp_alloc) (unsigned char *options, int opt_len);
+
+ /* Free space used by a decompressor */
+ void (*decomp_free) (void *state);
+
+ /* Initialize a decompressor */
+ int (*decomp_init) (void *state, unsigned char *options,
+ int opt_len, int unit, int opthdr, int mru,
+ int debug);
+
+ /* Reset a decompressor */
+ void (*decomp_reset) (void *state);
+
+ /* Decompress a packet. */
+ int (*decompress) (void *state, unsigned char *ibuf, int isize,
+ unsigned char *obuf, int osize);
+
+ /* Update state for an incompressible packet received */
+ void (*incomp) (void *state, unsigned char *ibuf, int icnt);
+
+ /* Return decompression statistics */
+ void (*decomp_stat) (void *state, struct compstat *stats);
+};
+
+/*
+ * The return value from decompress routine is the length of the
+ * decompressed packet if successful, otherwise DECOMP_ERROR
+ * or DECOMP_FATALERROR if an error occurred.
+ *
+ * We need to make this distinction so that we can disable certain
+ * useful functionality, namely sending a CCP reset-request as a result
+ * of an error detected after decompression. This is to avoid infringing
+ * a patent held by Motorola.
+ * Don't you just lurve software patents.
+ */
+
+#define DECOMP_ERROR -1 /* error detected before decomp. */
+#define DECOMP_FATALERROR -2 /* error detected after decomp. */
+
+/*
+ * CCP codes.
+ */
+
+#define CCP_CONFREQ 1
+#define CCP_CONFACK 2
+#define CCP_TERMREQ 5
+#define CCP_TERMACK 6
+#define CCP_RESETREQ 14
+#define CCP_RESETACK 15
+
+/*
+ * Max # bytes for a CCP option
+ */
+
+#define CCP_MAX_OPTION_LENGTH 32
+
+/*
+ * Parts of a CCP packet.
+ */
+
+#define CCP_CODE(dp) ((dp)[0])
+#define CCP_ID(dp) ((dp)[1])
+#define CCP_LENGTH(dp) (((dp)[2] << 8) + (dp)[3])
+#define CCP_HDRLEN 4
+
+#define CCP_OPT_CODE(dp) ((dp)[0])
+#define CCP_OPT_LENGTH(dp) ((dp)[1])
+#define CCP_OPT_MINLEN 2
+
+/*
+ * Definitions for BSD-Compress.
+ */
+
+#define CI_BSD_COMPRESS 21 /* config. option for BSD-Compress */
+#define CILEN_BSD_COMPRESS 3 /* length of config. option */
+
+/* Macros for handling the 3rd byte of the BSD-Compress config option. */
+#define BSD_NBITS(x) ((x) & 0x1F) /* number of bits requested */
+#define BSD_VERSION(x) ((x) >> 5) /* version of option format */
+#define BSD_CURRENT_VERSION 1 /* current version number */
+#define BSD_MAKE_OPT(v, n) (((v) << 5) | (n))
+
+#define BSD_MIN_BITS 9 /* smallest code size supported */
+#define BSD_MAX_BITS 15 /* largest code size supported */
+
+/*
+ * Definitions for Deflate.
+ */
+
+#define CI_DEFLATE 26 /* config option for Deflate */
+#define CI_DEFLATE_DRAFT 24 /* value used in original draft RFC */
+#define CILEN_DEFLATE 4 /* length of its config option */
+
+#define DEFLATE_MIN_SIZE 8
+#define DEFLATE_MAX_SIZE 15
+#define DEFLATE_METHOD_VAL 8
+#define DEFLATE_SIZE(x) (((x) >> 4) + DEFLATE_MIN_SIZE)
+#define DEFLATE_METHOD(x) ((x) & 0x0F)
+#define DEFLATE_MAKE_OPT(w) ((((w) - DEFLATE_MIN_SIZE) << 4) \
+ + DEFLATE_METHOD_VAL)
+#define DEFLATE_CHK_SEQUENCE 0
+
+/*
+ * Definitions for other, as yet unsupported, compression methods.
+ */
+
+#define CI_PREDICTOR_1 1 /* config option for Predictor-1 */
+#define CILEN_PREDICTOR_1 2 /* length of its config option */
+#define CI_PREDICTOR_2 2 /* config option for Predictor-2 */
+#define CILEN_PREDICTOR_2 2 /* length of its config option */
+
+#ifdef __KERNEL__
+extern int ppp_register_compressor(struct compressor *);
+extern void ppp_unregister_compressor(struct compressor *);
+#endif /* __KERNEL__ */
+
+#endif /* _NET_PPP_COMP_H */
diff --git a/mdk-stage1/ppp/include/linux/ppp_defs.h b/mdk-stage1/ppp/include/linux/ppp_defs.h
new file mode 100644
index 000000000..4e737b40f
--- /dev/null
+++ b/mdk-stage1/ppp/include/linux/ppp_defs.h
@@ -0,0 +1,185 @@
+/* $Id: ppp_defs.h 195720 2001-06-11 11:44:34Z gc $ */
+
+/*
+ * ppp_defs.h - PPP definitions.
+ *
+ * Copyright (c) 1994 The Australian National University.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation is hereby granted, provided that the above copyright
+ * notice appears in all copies. This software is provided without any
+ * warranty, express or implied. The Australian National University
+ * makes no representations about the suitability of this software for
+ * any purpose.
+ *
+ * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
+ * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
+ * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
+ * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
+ * OR MODIFICATIONS.
+ */
+
+/*
+ * ==FILEVERSION 20000114==
+ *
+ * NOTE TO MAINTAINERS:
+ * If you modify this file at all, please set the above date.
+ * ppp_defs.h is shipped with a PPP distribution as well as with the kernel;
+ * if everyone increases the FILEVERSION number above, then scripts
+ * can do the right thing when deciding whether to install a new ppp_defs.h
+ * file. Don't change the format of that line otherwise, so the
+ * installation script can recognize it.
+ */
+
+#ifndef _PPP_DEFS_H_
+#define _PPP_DEFS_H_
+
+/*
+ * The basic PPP frame.
+ */
+#define PPP_HDRLEN 4 /* octets for standard ppp header */
+#define PPP_FCSLEN 2 /* octets for FCS */
+#define PPP_MRU 1500 /* default MRU = max length of info field */
+
+#define PPP_ADDRESS(p) (((__u8 *)(p))[0])
+#define PPP_CONTROL(p) (((__u8 *)(p))[1])
+#define PPP_PROTOCOL(p) ((((__u8 *)(p))[2] << 8) + ((__u8 *)(p))[3])
+
+/*
+ * Significant octet values.
+ */
+#define PPP_ALLSTATIONS 0xff /* All-Stations broadcast address */
+#define PPP_UI 0x03 /* Unnumbered Information */
+#define PPP_FLAG 0x7e /* Flag Sequence */
+#define PPP_ESCAPE 0x7d /* Asynchronous Control Escape */
+#define PPP_TRANS 0x20 /* Asynchronous transparency modifier */
+
+/*
+ * Protocol field values.
+ */
+#define PPP_IP 0x21 /* Internet Protocol */
+#define PPP_AT 0x29 /* AppleTalk Protocol */
+#define PPP_IPX 0x2b /* IPX protocol */
+#define PPP_VJC_COMP 0x2d /* VJ compressed TCP */
+#define PPP_VJC_UNCOMP 0x2f /* VJ uncompressed TCP */
+#define PPP_MP 0x3d /* Multilink protocol */
+#define PPP_IPV6 0x57 /* Internet Protocol Version 6 */
+#define PPP_COMPFRAG 0xfb /* fragment compressed below bundle */
+#define PPP_COMP 0xfd /* compressed packet */
+#define PPP_IPCP 0x8021 /* IP Control Protocol */
+#define PPP_ATCP 0x8029 /* AppleTalk Control Protocol */
+#define PPP_IPXCP 0x802b /* IPX Control Protocol */
+#define PPP_IPV6CP 0x8057 /* IPv6 Control Protocol */
+#define PPP_CCPFRAG 0x80fb /* CCP at link level (below MP bundle) */
+#define PPP_CCP 0x80fd /* Compression Control Protocol */
+#define PPP_LCP 0xc021 /* Link Control Protocol */
+#define PPP_PAP 0xc023 /* Password Authentication Protocol */
+#define PPP_LQR 0xc025 /* Link Quality Report protocol */
+#define PPP_CHAP 0xc223 /* Cryptographic Handshake Auth. Protocol */
+#define PPP_CBCP 0xc029 /* Callback Control Protocol */
+
+/*
+ * Values for FCS calculations.
+ */
+
+#define PPP_INITFCS 0xffff /* Initial FCS value */
+#define PPP_GOODFCS 0xf0b8 /* Good final FCS value */
+#define PPP_FCS(fcs, c) (((fcs) >> 8) ^ fcstab[((fcs) ^ (c)) & 0xff])
+
+/*
+ * Extended asyncmap - allows any character to be escaped.
+ */
+
+typedef __u32 ext_accm[8];
+
+/*
+ * What to do with network protocol (NP) packets.
+ */
+enum NPmode {
+ NPMODE_PASS, /* pass the packet through */
+ NPMODE_DROP, /* silently drop the packet */
+ NPMODE_ERROR, /* return an error */
+ NPMODE_QUEUE /* save it up for later. */
+};
+
+/*
+ * Statistics for LQRP and pppstats
+ */
+struct pppstat {
+ __u32 ppp_discards; /* # frames discarded */
+
+ __u32 ppp_ibytes; /* bytes received */
+ __u32 ppp_ioctects; /* bytes received not in error */
+ __u32 ppp_ipackets; /* packets received */
+ __u32 ppp_ierrors; /* receive errors */
+ __u32 ppp_ilqrs; /* # LQR frames received */
+
+ __u32 ppp_obytes; /* raw bytes sent */
+ __u32 ppp_ooctects; /* frame bytes sent */
+ __u32 ppp_opackets; /* packets sent */
+ __u32 ppp_oerrors; /* transmit errors */
+ __u32 ppp_olqrs; /* # LQR frames sent */
+};
+
+struct vjstat {
+ __u32 vjs_packets; /* outbound packets */
+ __u32 vjs_compressed; /* outbound compressed packets */
+ __u32 vjs_searches; /* searches for connection state */
+ __u32 vjs_misses; /* times couldn't find conn. state */
+ __u32 vjs_uncompressedin; /* inbound uncompressed packets */
+ __u32 vjs_compressedin; /* inbound compressed packets */
+ __u32 vjs_errorin; /* inbound unknown type packets */
+ __u32 vjs_tossed; /* inbound packets tossed because of error */
+};
+
+struct compstat {
+ __u32 unc_bytes; /* total uncompressed bytes */
+ __u32 unc_packets; /* total uncompressed packets */
+ __u32 comp_bytes; /* compressed bytes */
+ __u32 comp_packets; /* compressed packets */
+ __u32 inc_bytes; /* incompressible bytes */
+ __u32 inc_packets; /* incompressible packets */
+
+ /* the compression ratio is defined as in_count / bytes_out */
+ __u32 in_count; /* Bytes received */
+ __u32 bytes_out; /* Bytes transmitted */
+
+ double ratio; /* not computed in kernel. */
+};
+
+struct ppp_stats {
+ struct pppstat p; /* basic PPP statistics */
+ struct vjstat vj; /* VJ header compression statistics */
+};
+
+struct ppp_comp_stats {
+ struct compstat c; /* packet compression statistics */
+ struct compstat d; /* packet decompression statistics */
+};
+
+/*
+ * The following structure records the time in seconds since
+ * the last NP packet was sent or received.
+ */
+struct ppp_idle {
+ time_t xmit_idle; /* time since last NP packet sent */
+ time_t recv_idle; /* time since last NP packet received */
+};
+
+#ifndef __P
+#ifdef __STDC__
+#define __P(x) x
+#else
+#define __P(x) ()
+#endif
+#endif
+
+#endif /* _PPP_DEFS_H_ */
diff --git a/mdk-stage1/ppp/include/net/if_ppp.h b/mdk-stage1/ppp/include/net/if_ppp.h
new file mode 100644
index 000000000..c64484e84
--- /dev/null
+++ b/mdk-stage1/ppp/include/net/if_ppp.h
@@ -0,0 +1,133 @@
+/* $Id: if_ppp.h 195720 2001-06-11 11:44:34Z gc $ */
+
+/*
+ * if_ppp.h - Point-to-Point Protocol definitions.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef _IF_PPP_H_
+#define _IF_PPP_H_
+
+/*
+ * Bit definitions for flags.
+ */
+#define SC_COMP_PROT 0x00000001 /* protocol compression (output) */
+#define SC_COMP_AC 0x00000002 /* header compression (output) */
+#define SC_COMP_TCP 0x00000004 /* TCP (VJ) compression (output) */
+#define SC_NO_TCP_CCID 0x00000008 /* disable VJ connection-id comp. */
+#define SC_REJ_COMP_AC 0x00000010 /* reject adrs/ctrl comp. on input */
+#define SC_REJ_COMP_TCP 0x00000020 /* reject TCP (VJ) comp. on input */
+#define SC_CCP_OPEN 0x00000040 /* Look at CCP packets */
+#define SC_CCP_UP 0x00000080 /* May send/recv compressed packets */
+#define SC_DEBUG 0x00010000 /* enable debug messages */
+#define SC_LOG_INPKT 0x00020000 /* log contents of good pkts recvd */
+#define SC_LOG_OUTPKT 0x00040000 /* log contents of pkts sent */
+#define SC_LOG_RAWIN 0x00080000 /* log all chars received */
+#define SC_LOG_FLUSH 0x00100000 /* log all chars flushed */
+#define SC_RCV_B7_0 0x01000000 /* have rcvd char with bit 7 = 0 */
+#define SC_RCV_B7_1 0x02000000 /* have rcvd char with bit 7 = 1 */
+#define SC_RCV_EVNP 0x04000000 /* have rcvd char with even parity */
+#define SC_RCV_ODDP 0x08000000 /* have rcvd char with odd parity */
+#define SC_SYNC 0x00200000 /* use synchronous HDLC framing */
+#define SC_MASK 0x0fff00ff /* bits that user can change */
+
+/*
+ * State bits in sc_flags, not changeable by user.
+ */
+#define SC_TIMEOUT 0x00000400 /* timeout is currently pending */
+#define SC_VJ_RESET 0x00000800 /* need to reset VJ decomp */
+#define SC_COMP_RUN 0x00001000 /* compressor has been inited */
+#define SC_DECOMP_RUN 0x00002000 /* decompressor has been inited */
+#define SC_DC_ERROR 0x00004000 /* non-fatal decomp error detected */
+#define SC_DC_FERROR 0x00008000 /* fatal decomp error detected */
+#define SC_TBUSY 0x10000000 /* xmitter doesn't need a packet yet */
+#define SC_PKTLOST 0x20000000 /* have lost or dropped a packet */
+#define SC_FLUSH 0x40000000 /* flush input until next PPP_FLAG */
+#define SC_ESCAPED 0x80000000 /* saw a PPP_ESCAPE */
+
+/*
+ * Ioctl definitions.
+ */
+
+struct npioctl {
+ int protocol; /* PPP procotol, e.g. PPP_IP */
+ enum NPmode mode;
+};
+
+/* Structure describing a CCP configuration option, for PPPIOCSCOMPRESS */
+struct ppp_option_data {
+ u_char *ptr;
+ u_int length;
+ int transmit;
+};
+
+struct ifpppstatsreq {
+ char ifr_name[IFNAMSIZ];
+ struct ppp_stats stats;
+};
+
+struct ifpppcstatsreq {
+ char ifr_name[IFNAMSIZ];
+ struct ppp_comp_stats stats;
+};
+
+/*
+ * Ioctl definitions.
+ */
+
+#define PPPIOCGFLAGS _IOR('t', 90, int) /* get configuration flags */
+#define PPPIOCSFLAGS _IOW('t', 89, int) /* set configuration flags */
+#define PPPIOCGASYNCMAP _IOR('t', 88, int) /* get async map */
+#define PPPIOCSASYNCMAP _IOW('t', 87, int) /* set async map */
+#define PPPIOCGUNIT _IOR('t', 86, int) /* get ppp unit number */
+#define PPPIOCGRASYNCMAP _IOR('t', 85, int) /* get receive async map */
+#define PPPIOCSRASYNCMAP _IOW('t', 84, int) /* set receive async map */
+#define PPPIOCGMRU _IOR('t', 83, int) /* get max receive unit */
+#define PPPIOCSMRU _IOW('t', 82, int) /* set max receive unit */
+#define PPPIOCSMAXCID _IOW('t', 81, int) /* set VJ max slot ID */
+#define PPPIOCGXASYNCMAP _IOR('t', 80, ext_accm) /* get extended ACCM */
+#define PPPIOCSXASYNCMAP _IOW('t', 79, ext_accm) /* set extended ACCM */
+#define PPPIOCXFERUNIT _IO('t', 78) /* transfer PPP unit */
+#define PPPIOCSCOMPRESS _IOW('t', 77, struct ppp_option_data)
+#define PPPIOCGNPMODE _IOWR('t', 76, struct npioctl) /* get NP mode */
+#define PPPIOCSNPMODE _IOW('t', 75, struct npioctl) /* set NP mode */
+#define PPPIOCGIDLE _IOR('t', 74, struct ppp_idle) /* get idle time */
+#ifdef PPP_FILTER
+#define PPPIOCSPASS _IOW('t', 71, struct bpf_program) /* set pass filter */
+#define PPPIOCSACTIVE _IOW('t', 70, struct bpf_program) /* set active filt */
+#endif /* PPP_FILTER */
+
+/* PPPIOC[GS]MTU are alternatives to SIOC[GS]IFMTU, used under Ultrix */
+#define PPPIOCGMTU _IOR('t', 73, int) /* get interface MTU */
+#define PPPIOCSMTU _IOW('t', 72, int) /* set interface MTU */
+
+/*
+ * These two are interface ioctls so that pppstats can do them on
+ * a socket without having to open the serial device.
+ */
+#define SIOCGPPPSTATS _IOWR('i', 123, struct ifpppstatsreq)
+#define SIOCGPPPCSTATS _IOWR('i', 122, struct ifpppcstatsreq)
+
+#if !defined(ifr_mtu)
+#define ifr_mtu ifr_ifru.ifru_metric
+#endif
+
+#if (defined(_KERNEL) || defined(KERNEL)) && !defined(NeXT)
+void pppattach __P((void));
+void pppintr __P((void));
+#endif
+#endif /* _IF_PPP_H_ */
diff --git a/mdk-stage1/ppp/include/net/ppp-comp.h b/mdk-stage1/ppp/include/net/ppp-comp.h
new file mode 100644
index 000000000..30b0def68
--- /dev/null
+++ b/mdk-stage1/ppp/include/net/ppp-comp.h
@@ -0,0 +1,165 @@
+/*
+ * ppp-comp.h - Definitions for doing PPP packet compression.
+ *
+ * Copyright (c) 1994 The Australian National University.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation is hereby granted, provided that the above copyright
+ * notice appears in all copies. This software is provided without any
+ * warranty, express or implied. The Australian National University
+ * makes no representations about the suitability of this software for
+ * any purpose.
+ *
+ * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
+ * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
+ * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
+ * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
+ * OR MODIFICATIONS.
+ *
+ * $Id: ppp-comp.h 195720 2001-06-11 11:44:34Z gc $
+ */
+
+#ifndef _NET_PPP_COMP_H
+#define _NET_PPP_COMP_H
+
+/*
+ * The following symbols control whether we include code for
+ * various compression methods.
+ */
+#ifndef DO_BSD_COMPRESS
+#define DO_BSD_COMPRESS 1 /* by default, include BSD-Compress */
+#endif
+#ifndef DO_DEFLATE
+#define DO_DEFLATE 1 /* by default, include Deflate */
+#endif
+#define DO_PREDICTOR_1 0
+#define DO_PREDICTOR_2 0
+
+/*
+ * Structure giving methods for compression/decompression.
+ */
+#ifdef PACKETPTR
+struct compressor {
+ int compress_proto; /* CCP compression protocol number */
+
+ /* Allocate space for a compressor (transmit side) */
+ void *(*comp_alloc) __P((u_char *options, int opt_len));
+ /* Free space used by a compressor */
+ void (*comp_free) __P((void *state));
+ /* Initialize a compressor */
+ int (*comp_init) __P((void *state, u_char *options, int opt_len,
+ int unit, int hdrlen, int debug));
+ /* Reset a compressor */
+ void (*comp_reset) __P((void *state));
+ /* Compress a packet */
+ int (*compress) __P((void *state, PACKETPTR *mret,
+ PACKETPTR mp, int orig_len, int max_len));
+ /* Return compression statistics */
+ void (*comp_stat) __P((void *state, struct compstat *stats));
+
+ /* Allocate space for a decompressor (receive side) */
+ void *(*decomp_alloc) __P((u_char *options, int opt_len));
+ /* Free space used by a decompressor */
+ void (*decomp_free) __P((void *state));
+ /* Initialize a decompressor */
+ int (*decomp_init) __P((void *state, u_char *options, int opt_len,
+ int unit, int hdrlen, int mru, int debug));
+ /* Reset a decompressor */
+ void (*decomp_reset) __P((void *state));
+ /* Decompress a packet. */
+ int (*decompress) __P((void *state, PACKETPTR mp,
+ PACKETPTR *dmpp));
+ /* Update state for an incompressible packet received */
+ void (*incomp) __P((void *state, PACKETPTR mp));
+ /* Return decompression statistics */
+ void (*decomp_stat) __P((void *state, struct compstat *stats));
+};
+#endif /* PACKETPTR */
+
+/*
+ * Return values for decompress routine.
+ * We need to make these distinctions so that we can disable certain
+ * useful functionality, namely sending a CCP reset-request as a result
+ * of an error detected after decompression. This is to avoid infringing
+ * a patent held by Motorola.
+ * Don't you just lurve software patents.
+ */
+#define DECOMP_OK 0 /* everything went OK */
+#define DECOMP_ERROR 1 /* error detected before decomp. */
+#define DECOMP_FATALERROR 2 /* error detected after decomp. */
+
+/*
+ * CCP codes.
+ */
+#define CCP_CONFREQ 1
+#define CCP_CONFACK 2
+#define CCP_TERMREQ 5
+#define CCP_TERMACK 6
+#define CCP_RESETREQ 14
+#define CCP_RESETACK 15
+
+/*
+ * Max # bytes for a CCP option
+ */
+#define CCP_MAX_OPTION_LENGTH 32
+
+/*
+ * Parts of a CCP packet.
+ */
+#define CCP_CODE(dp) ((dp)[0])
+#define CCP_ID(dp) ((dp)[1])
+#define CCP_LENGTH(dp) (((dp)[2] << 8) + (dp)[3])
+#define CCP_HDRLEN 4
+
+#define CCP_OPT_CODE(dp) ((dp)[0])
+#define CCP_OPT_LENGTH(dp) ((dp)[1])
+#define CCP_OPT_MINLEN 2
+
+/*
+ * Definitions for BSD-Compress.
+ */
+#define CI_BSD_COMPRESS 21 /* config. option for BSD-Compress */
+#define CILEN_BSD_COMPRESS 3 /* length of config. option */
+
+/* Macros for handling the 3rd byte of the BSD-Compress config option. */
+#define BSD_NBITS(x) ((x) & 0x1F) /* number of bits requested */
+#define BSD_VERSION(x) ((x) >> 5) /* version of option format */
+#define BSD_CURRENT_VERSION 1 /* current version number */
+#define BSD_MAKE_OPT(v, n) (((v) << 5) | (n))
+
+#define BSD_MIN_BITS 9 /* smallest code size supported */
+#define BSD_MAX_BITS 15 /* largest code size supported */
+
+/*
+ * Definitions for Deflate.
+ */
+#define CI_DEFLATE 26 /* config option for Deflate */
+#define CI_DEFLATE_DRAFT 24 /* value used in original draft RFC */
+#define CILEN_DEFLATE 4 /* length of its config option */
+
+#define DEFLATE_MIN_SIZE 8
+#define DEFLATE_MAX_SIZE 15
+#define DEFLATE_METHOD_VAL 8
+#define DEFLATE_SIZE(x) (((x) >> 4) + DEFLATE_MIN_SIZE)
+#define DEFLATE_METHOD(x) ((x) & 0x0F)
+#define DEFLATE_MAKE_OPT(w) ((((w) - DEFLATE_MIN_SIZE) << 4) \
+ + DEFLATE_METHOD_VAL)
+#define DEFLATE_CHK_SEQUENCE 0
+
+/*
+ * Definitions for other, as yet unsupported, compression methods.
+ */
+#define CI_PREDICTOR_1 1 /* config option for Predictor-1 */
+#define CILEN_PREDICTOR_1 2 /* length of its config option */
+#define CI_PREDICTOR_2 2 /* config option for Predictor-2 */
+#define CILEN_PREDICTOR_2 2 /* length of its config option */
+
+#endif /* _NET_PPP_COMP_H */
diff --git a/mdk-stage1/ppp/include/net/ppp_defs.h b/mdk-stage1/ppp/include/net/ppp_defs.h
new file mode 100644
index 000000000..ecd0528ec
--- /dev/null
+++ b/mdk-stage1/ppp/include/net/ppp_defs.h
@@ -0,0 +1,184 @@
+/* $Id: ppp_defs.h 203043 2003-06-04 18:31:57Z gbeauchesne $ */
+
+/*
+ * ppp_defs.h - PPP definitions.
+ *
+ * Copyright (c) 1994 The Australian National University.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation is hereby granted, provided that the above copyright
+ * notice appears in all copies. This software is provided without any
+ * warranty, express or implied. The Australian National University
+ * makes no representations about the suitability of this software for
+ * any purpose.
+ *
+ * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
+ * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
+ * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
+ * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
+ * OR MODIFICATIONS.
+ */
+
+#ifndef _PPP_DEFS_H_
+#define _PPP_DEFS_H_
+
+/*
+ * The basic PPP frame.
+ */
+#define PPP_HDRLEN 4 /* octets for standard ppp header */
+#define PPP_FCSLEN 2 /* octets for FCS */
+
+/*
+ * Packet sizes
+ *
+ * Note - lcp shouldn't be allowed to negotiate stuff outside these
+ * limits. See lcp.h in the pppd directory.
+ * (XXX - these constants should simply be shared by lcp.c instead
+ * of living in lcp.h)
+ */
+#define PPP_MTU 1500 /* Default MTU (size of Info field) */
+#define PPP_MAXMTU 65535 - (PPP_HDRLEN + PPP_FCSLEN)
+#define PPP_MINMTU 64
+#define PPP_MRU 1500 /* default MRU = max length of info field */
+#define PPP_MAXMRU 65000 /* Largest MRU we allow */
+#define PPP_MINMRU 128
+
+#define PPP_ADDRESS(p) (((u_char *)(p))[0])
+#define PPP_CONTROL(p) (((u_char *)(p))[1])
+#define PPP_PROTOCOL(p) ((((u_char *)(p))[2] << 8) + ((u_char *)(p))[3])
+
+/*
+ * Significant octet values.
+ */
+#define PPP_ALLSTATIONS 0xff /* All-Stations broadcast address */
+#define PPP_UI 0x03 /* Unnumbered Information */
+#define PPP_FLAG 0x7e /* Flag Sequence */
+#define PPP_ESCAPE 0x7d /* Asynchronous Control Escape */
+#define PPP_TRANS 0x20 /* Asynchronous transparency modifier */
+
+/*
+ * Protocol field values.
+ */
+#define PPP_IP 0x21 /* Internet Protocol */
+#define PPP_AT 0x29 /* AppleTalk Protocol */
+#define PPP_IPX 0x2b /* IPX protocol */
+#define PPP_VJC_COMP 0x2d /* VJ compressed TCP */
+#define PPP_VJC_UNCOMP 0x2f /* VJ uncompressed TCP */
+#define PPP_IPV6 0x57 /* Internet Protocol Version 6 */
+#define PPP_COMP 0xfd /* compressed packet */
+#define PPP_IPCP 0x8021 /* IP Control Protocol */
+#define PPP_ATCP 0x8029 /* AppleTalk Control Protocol */
+#define PPP_IPXCP 0x802b /* IPX Control Protocol */
+#define PPP_IPV6CP 0x8057 /* IPv6 Control Protocol */
+#define PPP_CCP 0x80fd /* Compression Control Protocol */
+#define PPP_LCP 0xc021 /* Link Control Protocol */
+#define PPP_PAP 0xc023 /* Password Authentication Protocol */
+#define PPP_LQR 0xc025 /* Link Quality Report protocol */
+#define PPP_CHAP 0xc223 /* Cryptographic Handshake Auth. Protocol */
+#define PPP_CBCP 0xc029 /* Callback Control Protocol */
+
+/*
+ * Values for FCS calculations.
+ */
+#define PPP_INITFCS 0xffff /* Initial FCS value */
+#define PPP_GOODFCS 0xf0b8 /* Good final FCS value */
+#define PPP_FCS(fcs, c) (((fcs) >> 8) ^ fcstab[((fcs) ^ (c)) & 0xff])
+
+/*
+ * A 32-bit unsigned integral type.
+ */
+
+#if !defined(__BIT_TYPES_DEFINED__) && !defined(_BITYPES) \
+ && !defined(__FreeBSD__) && (NS_TARGET < 40) && !defined(__dietlibc__)
+#ifdef UINT32_T
+typedef UINT32_T u_int32_t;
+#else
+typedef unsigned int u_int32_t;
+typedef unsigned short u_int16_t;
+#endif
+#endif
+
+/*
+ * Extended asyncmap - allows any character to be escaped.
+ */
+typedef u_int32_t ext_accm[8];
+
+/*
+ * What to do with network protocol (NP) packets.
+ */
+enum NPmode {
+ NPMODE_PASS, /* pass the packet through */
+ NPMODE_DROP, /* silently drop the packet */
+ NPMODE_ERROR, /* return an error */
+ NPMODE_QUEUE /* save it up for later. */
+};
+
+/*
+ * Statistics.
+ */
+struct pppstat {
+ unsigned int ppp_ibytes; /* bytes received */
+ unsigned int ppp_ipackets; /* packets received */
+ unsigned int ppp_ierrors; /* receive errors */
+ unsigned int ppp_obytes; /* bytes sent */
+ unsigned int ppp_opackets; /* packets sent */
+ unsigned int ppp_oerrors; /* transmit errors */
+};
+
+struct vjstat {
+ unsigned int vjs_packets; /* outbound packets */
+ unsigned int vjs_compressed; /* outbound compressed packets */
+ unsigned int vjs_searches; /* searches for connection state */
+ unsigned int vjs_misses; /* times couldn't find conn. state */
+ unsigned int vjs_uncompressedin; /* inbound uncompressed packets */
+ unsigned int vjs_compressedin; /* inbound compressed packets */
+ unsigned int vjs_errorin; /* inbound unknown type packets */
+ unsigned int vjs_tossed; /* inbound packets tossed because of error */
+};
+
+struct ppp_stats {
+ struct pppstat p; /* basic PPP statistics */
+ struct vjstat vj; /* VJ header compression statistics */
+};
+
+struct compstat {
+ unsigned int unc_bytes; /* total uncompressed bytes */
+ unsigned int unc_packets; /* total uncompressed packets */
+ unsigned int comp_bytes; /* compressed bytes */
+ unsigned int comp_packets; /* compressed packets */
+ unsigned int inc_bytes; /* incompressible bytes */
+ unsigned int inc_packets; /* incompressible packets */
+ unsigned int ratio; /* recent compression ratio << 8 */
+};
+
+struct ppp_comp_stats {
+ struct compstat c; /* packet compression statistics */
+ struct compstat d; /* packet decompression statistics */
+};
+
+/*
+ * The following structure records the time in seconds since
+ * the last NP packet was sent or received.
+ */
+struct ppp_idle {
+ time_t xmit_idle; /* time since last NP packet sent */
+ time_t recv_idle; /* time since last NP packet received */
+};
+
+#ifndef __P
+#ifdef __STDC__
+#define __P(x) x
+#else
+#define __P(x) ()
+#endif
+#endif
+
+#endif /* _PPP_DEFS_H_ */
diff --git a/mdk-stage1/ppp/include/net/pppio.h b/mdk-stage1/ppp/include/net/pppio.h
new file mode 100644
index 000000000..e327db3ce
--- /dev/null
+++ b/mdk-stage1/ppp/include/net/pppio.h
@@ -0,0 +1,99 @@
+/*
+ * pppio.h - ioctl and other misc. definitions for STREAMS modules.
+ *
+ * Copyright (c) 1994 The Australian National University.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation is hereby granted, provided that the above copyright
+ * notice appears in all copies. This software is provided without any
+ * warranty, express or implied. The Australian National University
+ * makes no representations about the suitability of this software for
+ * any purpose.
+ *
+ * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
+ * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
+ * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
+ * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
+ * OR MODIFICATIONS.
+ *
+ * $Id: pppio.h 195720 2001-06-11 11:44:34Z gc $
+ */
+
+#define _PPPIO(n) (('p' << 8) + (n))
+
+#define PPPIO_NEWPPA _PPPIO(130) /* allocate a new PPP unit */
+#define PPPIO_GETSTAT _PPPIO(131) /* get PPP statistics */
+#define PPPIO_GETCSTAT _PPPIO(132) /* get PPP compression stats */
+#define PPPIO_MTU _PPPIO(133) /* set max transmission unit */
+#define PPPIO_MRU _PPPIO(134) /* set max receive unit */
+#define PPPIO_CFLAGS _PPPIO(135) /* set/clear/get compression flags */
+#define PPPIO_XCOMP _PPPIO(136) /* alloc transmit compressor */
+#define PPPIO_RCOMP _PPPIO(137) /* alloc receive decompressor */
+#define PPPIO_XACCM _PPPIO(138) /* set transmit asyncmap */
+#define PPPIO_RACCM _PPPIO(139) /* set receive asyncmap */
+#define PPPIO_VJINIT _PPPIO(140) /* initialize VJ comp/decomp */
+#define PPPIO_ATTACH _PPPIO(141) /* attach to a ppa (without putmsg) */
+#define PPPIO_LASTMOD _PPPIO(142) /* mark last ppp module */
+#define PPPIO_GCLEAN _PPPIO(143) /* get 8-bit-clean flags */
+#define PPPIO_DEBUG _PPPIO(144) /* request debug information */
+#define PPPIO_BIND _PPPIO(145) /* bind to SAP */
+#define PPPIO_NPMODE _PPPIO(146) /* set mode for handling data pkts */
+#define PPPIO_GIDLE _PPPIO(147) /* get time since last data pkt */
+#define PPPIO_PASSFILT _PPPIO(148) /* set filter for packets to pass */
+#define PPPIO_ACTIVEFILT _PPPIO(149) /* set filter for "link active" pkts */
+
+/*
+ * Values for PPPIO_CFLAGS
+ */
+#define COMP_AC 0x1 /* compress address/control */
+#define DECOMP_AC 0x2 /* decompress address/control */
+#define COMP_PROT 0x4 /* compress PPP protocol */
+#define DECOMP_PROT 0x8 /* decompress PPP protocol */
+
+#define COMP_VJC 0x10 /* compress TCP/IP headers */
+#define COMP_VJCCID 0x20 /* compress connection ID as well */
+#define DECOMP_VJC 0x40 /* decompress TCP/IP headers */
+#define DECOMP_VJCCID 0x80 /* accept compressed connection ID */
+
+#define CCP_ISOPEN 0x100 /* look at CCP packets */
+#define CCP_ISUP 0x200 /* do packet comp/decomp */
+#define CCP_ERROR 0x400 /* (status) error in packet decomp */
+#define CCP_FATALERROR 0x800 /* (status) fatal error ditto */
+#define CCP_COMP_RUN 0x1000 /* (status) seen CCP ack sent */
+#define CCP_DECOMP_RUN 0x2000 /* (status) seen CCP ack rcvd */
+
+/*
+ * Values for 8-bit-clean flags.
+ */
+#define RCV_B7_0 1 /* have rcvd char with bit 7 = 0 */
+#define RCV_B7_1 2 /* have rcvd char with bit 7 = 1 */
+#define RCV_EVNP 4 /* have rcvd char with even parity */
+#define RCV_ODDP 8 /* have rcvd char with odd parity */
+
+/*
+ * Values for the first byte of M_CTL messages passed between
+ * PPP modules.
+ */
+#define PPPCTL_OERROR 0xe0 /* output error [up] */
+#define PPPCTL_IERROR 0xe1 /* input error (e.g. FCS) [up] */
+#define PPPCTL_MTU 0xe2 /* set MTU [down] */
+#define PPPCTL_MRU 0xe3 /* set MRU [down] */
+#define PPPCTL_UNIT 0xe4 /* note PPP unit number [down] */
+
+/*
+ * Values for the integer argument to PPPIO_DEBUG.
+ */
+#define PPPDBG_DUMP 0x10000 /* print out debug info now */
+#define PPPDBG_LOG 0x100 /* log various things */
+#define PPPDBG_DRIVER 0 /* identifies ppp driver as target */
+#define PPPDBG_IF 1 /* identifies ppp network i/f target */
+#define PPPDBG_COMP 2 /* identifies ppp compression target */
+#define PPPDBG_AHDLC 3 /* identifies ppp async hdlc target */
diff --git a/mdk-stage1/ppp/include/net/slcompress.h b/mdk-stage1/ppp/include/net/slcompress.h
new file mode 100644
index 000000000..d7b7dc4ee
--- /dev/null
+++ b/mdk-stage1/ppp/include/net/slcompress.h
@@ -0,0 +1,148 @@
+/*
+ * Definitions for tcp compression routines.
+ *
+ * $Id: slcompress.h 195720 2001-06-11 11:44:34Z gc $
+ *
+ * Copyright (c) 1989 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Van Jacobson (van@helios.ee.lbl.gov), Dec 31, 1989:
+ * - Initial distribution.
+ */
+
+#ifndef _SLCOMPRESS_H_
+#define _SLCOMPRESS_H_
+
+#define MAX_STATES 16 /* must be > 2 and < 256 */
+#define MAX_HDR MLEN /* XXX 4bsd-ism: should really be 128 */
+
+/*
+ * Compressed packet format:
+ *
+ * The first octet contains the packet type (top 3 bits), TCP
+ * 'push' bit, and flags that indicate which of the 4 TCP sequence
+ * numbers have changed (bottom 5 bits). The next octet is a
+ * conversation number that associates a saved IP/TCP header with
+ * the compressed packet. The next two octets are the TCP checksum
+ * from the original datagram. The next 0 to 15 octets are
+ * sequence number changes, one change per bit set in the header
+ * (there may be no changes and there are two special cases where
+ * the receiver implicitly knows what changed -- see below).
+ *
+ * There are 5 numbers which can change (they are always inserted
+ * in the following order): TCP urgent pointer, window,
+ * acknowlegement, sequence number and IP ID. (The urgent pointer
+ * is different from the others in that its value is sent, not the
+ * change in value.) Since typical use of SLIP links is biased
+ * toward small packets (see comments on MTU/MSS below), changes
+ * use a variable length coding with one octet for numbers in the
+ * range 1 - 255 and 3 octets (0, MSB, LSB) for numbers in the
+ * range 256 - 65535 or 0. (If the change in sequence number or
+ * ack is more than 65535, an uncompressed packet is sent.)
+ */
+
+/*
+ * Packet types (must not conflict with IP protocol version)
+ *
+ * The top nibble of the first octet is the packet type. There are
+ * three possible types: IP (not proto TCP or tcp with one of the
+ * control flags set); uncompressed TCP (a normal IP/TCP packet but
+ * with the 8-bit protocol field replaced by an 8-bit connection id --
+ * this type of packet syncs the sender & receiver); and compressed
+ * TCP (described above).
+ *
+ * LSB of 4-bit field is TCP "PUSH" bit (a worthless anachronism) and
+ * is logically part of the 4-bit "changes" field that follows. Top
+ * three bits are actual packet type. For backward compatibility
+ * and in the interest of conserving bits, numbers are chosen so the
+ * IP protocol version number (4) which normally appears in this nibble
+ * means "IP packet".
+ */
+
+/* packet types */
+#define TYPE_IP 0x40
+#define TYPE_UNCOMPRESSED_TCP 0x70
+#define TYPE_COMPRESSED_TCP 0x80
+#define TYPE_ERROR 0x00
+
+/* Bits in first octet of compressed packet */
+#define NEW_C 0x40 /* flag bits for what changed in a packet */
+#define NEW_I 0x20
+#define NEW_S 0x08
+#define NEW_A 0x04
+#define NEW_W 0x02
+#define NEW_U 0x01
+
+/* reserved, special-case values of above */
+#define SPECIAL_I (NEW_S|NEW_W|NEW_U) /* echoed interactive traffic */
+#define SPECIAL_D (NEW_S|NEW_A|NEW_W|NEW_U) /* unidirectional data */
+#define SPECIALS_MASK (NEW_S|NEW_A|NEW_W|NEW_U)
+
+#define TCP_PUSH_BIT 0x10
+
+
+/*
+ * "state" data for each active tcp conversation on the wire. This is
+ * basically a copy of the entire IP/TCP header from the last packet
+ * we saw from the conversation together with a small identifier
+ * the transmit & receive ends of the line use to locate saved header.
+ */
+struct cstate {
+ struct cstate *cs_next; /* next most recently used cstate (xmit only) */
+ u_short cs_hlen; /* size of hdr (receive only) */
+ u_char cs_id; /* connection # associated with this state */
+ u_char cs_filler;
+ union {
+ char csu_hdr[MAX_HDR];
+ struct ip csu_ip; /* ip/tcp hdr from most recent packet */
+ } slcs_u;
+};
+#define cs_ip slcs_u.csu_ip
+#define cs_hdr slcs_u.csu_hdr
+
+/*
+ * all the state data for one serial line (we need one of these
+ * per line).
+ */
+struct slcompress {
+ struct cstate *last_cs; /* most recently used tstate */
+ u_char last_recv; /* last rcvd conn. id */
+ u_char last_xmit; /* last sent conn. id */
+ u_short flags;
+#ifndef SL_NO_STATS
+ int sls_packets; /* outbound packets */
+ int sls_compressed; /* outbound compressed packets */
+ int sls_searches; /* searches for connection state */
+ int sls_misses; /* times couldn't find conn. state */
+ int sls_uncompressedin; /* inbound uncompressed packets */
+ int sls_compressedin; /* inbound compressed packets */
+ int sls_errorin; /* inbound unknown type packets */
+ int sls_tossed; /* inbound packets tossed because of error */
+#endif
+ struct cstate tstate[MAX_STATES]; /* xmit connection states */
+ struct cstate rstate[MAX_STATES]; /* receive connection states */
+};
+/* flag values */
+#define SLF_TOSS 1 /* tossing rcvd frames because of input err */
+
+void sl_compress_init __P((struct slcompress *));
+void sl_compress_setup __P((struct slcompress *, int));
+u_int sl_compress_tcp __P((struct mbuf *,
+ struct ip *, struct slcompress *, int));
+int sl_uncompress_tcp __P((u_char **, int, u_int, struct slcompress *));
+int sl_uncompress_tcp_core __P((u_char *, int, int, u_int,
+ struct slcompress *, u_char **, u_int *));
+
+#endif /* _SLCOMPRESS_H_ */
diff --git a/mdk-stage1/ppp/include/net/vjcompress.h b/mdk-stage1/ppp/include/net/vjcompress.h
new file mode 100644
index 000000000..0ff6d3943
--- /dev/null
+++ b/mdk-stage1/ppp/include/net/vjcompress.h
@@ -0,0 +1,144 @@
+/*
+ * Definitions for tcp compression routines.
+ *
+ * $Id: vjcompress.h 195720 2001-06-11 11:44:34Z gc $
+ *
+ * Copyright (c) 1989 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Van Jacobson (van@helios.ee.lbl.gov), Dec 31, 1989:
+ * - Initial distribution.
+ */
+
+#ifndef _VJCOMPRESS_H_
+#define _VJCOMPRESS_H_
+
+#define MAX_STATES 16 /* must be > 2 and < 256 */
+#define MAX_HDR 128
+
+/*
+ * Compressed packet format:
+ *
+ * The first octet contains the packet type (top 3 bits), TCP
+ * 'push' bit, and flags that indicate which of the 4 TCP sequence
+ * numbers have changed (bottom 5 bits). The next octet is a
+ * conversation number that associates a saved IP/TCP header with
+ * the compressed packet. The next two octets are the TCP checksum
+ * from the original datagram. The next 0 to 15 octets are
+ * sequence number changes, one change per bit set in the header
+ * (there may be no changes and there are two special cases where
+ * the receiver implicitly knows what changed -- see below).
+ *
+ * There are 5 numbers which can change (they are always inserted
+ * in the following order): TCP urgent pointer, window,
+ * acknowlegement, sequence number and IP ID. (The urgent pointer
+ * is different from the others in that its value is sent, not the
+ * change in value.) Since typical use of SLIP links is biased
+ * toward small packets (see comments on MTU/MSS below), changes
+ * use a variable length coding with one octet for numbers in the
+ * range 1 - 255 and 3 octets (0, MSB, LSB) for numbers in the
+ * range 256 - 65535 or 0. (If the change in sequence number or
+ * ack is more than 65535, an uncompressed packet is sent.)
+ */
+
+/*
+ * Packet types (must not conflict with IP protocol version)
+ *
+ * The top nibble of the first octet is the packet type. There are
+ * three possible types: IP (not proto TCP or tcp with one of the
+ * control flags set); uncompressed TCP (a normal IP/TCP packet but
+ * with the 8-bit protocol field replaced by an 8-bit connection id --
+ * this type of packet syncs the sender & receiver); and compressed
+ * TCP (described above).
+ *
+ * LSB of 4-bit field is TCP "PUSH" bit (a worthless anachronism) and
+ * is logically part of the 4-bit "changes" field that follows. Top
+ * three bits are actual packet type. For backward compatibility
+ * and in the interest of conserving bits, numbers are chosen so the
+ * IP protocol version number (4) which normally appears in this nibble
+ * means "IP packet".
+ */
+
+/* packet types */
+#define TYPE_IP 0x40
+#define TYPE_UNCOMPRESSED_TCP 0x70
+#define TYPE_COMPRESSED_TCP 0x80
+#define TYPE_ERROR 0x00
+
+/* Bits in first octet of compressed packet */
+#define NEW_C 0x40 /* flag bits for what changed in a packet */
+#define NEW_I 0x20
+#define NEW_S 0x08
+#define NEW_A 0x04
+#define NEW_W 0x02
+#define NEW_U 0x01
+
+/* reserved, special-case values of above */
+#define SPECIAL_I (NEW_S|NEW_W|NEW_U) /* echoed interactive traffic */
+#define SPECIAL_D (NEW_S|NEW_A|NEW_W|NEW_U) /* unidirectional data */
+#define SPECIALS_MASK (NEW_S|NEW_A|NEW_W|NEW_U)
+
+#define TCP_PUSH_BIT 0x10
+
+
+/*
+ * "state" data for each active tcp conversation on the wire. This is
+ * basically a copy of the entire IP/TCP header from the last packet
+ * we saw from the conversation together with a small identifier
+ * the transmit & receive ends of the line use to locate saved header.
+ */
+struct cstate {
+ struct cstate *cs_next; /* next most recently used state (xmit only) */
+ u_short cs_hlen; /* size of hdr (receive only) */
+ u_char cs_id; /* connection # associated with this state */
+ u_char cs_filler;
+ union {
+ char csu_hdr[MAX_HDR];
+ struct ip csu_ip; /* ip/tcp hdr from most recent packet */
+ } vjcs_u;
+};
+#define cs_ip vjcs_u.csu_ip
+#define cs_hdr vjcs_u.csu_hdr
+
+/*
+ * all the state data for one serial line (we need one of these per line).
+ */
+struct vjcompress {
+ struct cstate *last_cs; /* most recently used tstate */
+ u_char last_recv; /* last rcvd conn. id */
+ u_char last_xmit; /* last sent conn. id */
+ u_short flags;
+#ifndef VJ_NO_STATS
+ struct vjstat stats;
+#endif
+ struct cstate tstate[MAX_STATES]; /* xmit connection states */
+ struct cstate rstate[MAX_STATES]; /* receive connection states */
+};
+
+/* flag values */
+#define VJF_TOSS 1 /* tossing rcvd frames because of input err */
+
+extern void vj_compress_init __P((struct vjcompress *comp, int max_state));
+extern u_int vj_compress_tcp __P((struct ip *ip, u_int mlen,
+ struct vjcompress *comp, int compress_cid_flag,
+ u_char **vjhdrp));
+extern void vj_uncompress_err __P((struct vjcompress *comp));
+extern int vj_uncompress_uncomp __P((u_char *buf, int buflen,
+ struct vjcompress *comp));
+extern int vj_uncompress_tcp __P((u_char *buf, int buflen, int total_len,
+ struct vjcompress *comp, u_char **hdrp,
+ u_int *hlenp));
+
+#endif /* _VJCOMPRESS_H_ */
diff --git a/mdk-stage1/ppp/include/pcap-int.h b/mdk-stage1/ppp/include/pcap-int.h
new file mode 100644
index 000000000..323994929
--- /dev/null
+++ b/mdk-stage1/ppp/include/pcap-int.h
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 1994, 1995, 1996
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the Computer Systems
+ * Engineering Group at Lawrence Berkeley Laboratory.
+ * 4. Neither the name of the University nor of the Laboratory may be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#) $Header$ (LBL)
+ */
+
+#ifndef pcap_int_h
+#define pcap_int_h
+
+#include <pcap.h>
+
+/*
+ * Savefile
+ */
+struct pcap_sf {
+ FILE *rfile;
+ int swapped;
+ int version_major;
+ int version_minor;
+ u_char *base;
+};
+
+struct pcap_md {
+ struct pcap_stat stat;
+ /*XXX*/
+ int use_bpf;
+ u_long TotPkts; /* can't oflow for 79 hrs on ether */
+ u_long TotAccepted; /* count accepted by filter */
+ u_long TotDrops; /* count of dropped packets */
+ long TotMissed; /* missed by i/f during this run */
+ long OrigMissed; /* missed by i/f before this run */
+#ifdef linux
+ int pad;
+ int skip;
+ char *device;
+#endif
+};
+
+struct pcap {
+ int fd;
+ int snapshot;
+ int linktype;
+ int tzoff; /* timezone offset */
+ int offset; /* offset for proper alignment */
+
+ struct pcap_sf sf;
+ struct pcap_md md;
+
+ /*
+ * Read buffer.
+ */
+ int bufsize;
+ u_char *buffer;
+ u_char *bp;
+ int cc;
+
+ /*
+ * Place holder for pcap_next().
+ */
+ u_char *pkt;
+
+
+ /*
+ * Placeholder for filter code if bpf not in kernel.
+ */
+ struct bpf_program fcode;
+
+ char errbuf[PCAP_ERRBUF_SIZE];
+};
+
+int yylex(void);
+
+#ifndef min
+#define min(a, b) ((a) > (b) ? (b) : (a))
+#endif
+
+/* XXX should these be in pcap.h? */
+int pcap_offline_read(pcap_t *, int, pcap_handler, u_char *);
+int pcap_read(pcap_t *, int cnt, pcap_handler, u_char *);
+
+/* Ultrix pads to make everything line up on a nice boundary */
+#if defined(ultrix) || defined(__alpha)
+#define PCAP_FDDIPAD 3
+#endif
+
+/* XXX */
+extern int pcap_fddipad;
+#endif
diff --git a/mdk-stage1/ppp/linux/Makefile.top b/mdk-stage1/ppp/linux/Makefile.top
new file mode 100644
index 000000000..fa34ce59f
--- /dev/null
+++ b/mdk-stage1/ppp/linux/Makefile.top
@@ -0,0 +1,55 @@
+# PPP top-level Makefile for Linux.
+
+
+BINDIR = $(DESTDIR)/usr/sbin
+MANDIR = $(DESTDIR)/usr/man
+ETCDIR = $(DESTDIR)/etc/ppp
+
+# uid 0 = root
+INSTALL= install
+
+all:
+ cd chat; $(MAKE) $(MFLAGS) all
+ cd pppd; $(MAKE) $(MFLAGS) all
+ cd pppstats; $(MAKE) $(MFLAGS) all
+ cd pppdump; $(MAKE) $(MFLAGS) all
+
+install: $(BINDIR) $(MANDIR)/man8 install-progs install-etcppp
+
+install-progs:
+ cd chat; $(MAKE) BINDIR=$(BINDIR) MANDIR=$(MANDIR) $(MFLAGS) install
+ cd pppd; $(MAKE) BINDIR=$(BINDIR) MANDIR=$(MANDIR) $(MFLAGS) install
+ cd pppstats; $(MAKE) BINDIR=$(BINDIR) MANDIR=$(MANDIR) $(MFLAGS) install
+ cd pppdump; $(MAKE) BINDIR=$(BINDIR) MANDIR=$(MANDIR) $(MFLAGS) install
+
+install-etcppp: $(ETCDIR) $(ETCDIR)/options $(ETCDIR)/pap-secrets \
+ $(ETCDIR)/chap-secrets
+
+$(ETCDIR)/options:
+ $(INSTALL) -c -m 644 etc.ppp/options $@
+$(ETCDIR)/pap-secrets:
+ $(INSTALL) -c -m 600 etc.ppp/pap-secrets $@
+$(ETCDIR)/chap-secrets:
+ $(INSTALL) -c -m 600 etc.ppp/chap-secrets $@
+
+$(BINDIR):
+ $(INSTALL) -d -m 755 $@
+$(MANDIR)/man8:
+ $(INSTALL) -d -m 755 $@
+$(ETCDIR):
+ $(INSTALL) -d -m 755 $@
+
+clean:
+ rm -f `find . -name '*.[oas]' -print`
+ rm -f `find . -name 'core' -print`
+ rm -f `find . -name '*~' -print`
+ cd chat; $(MAKE) clean
+ cd pppd; $(MAKE) clean
+ cd pppstats; $(MAKE) clean
+ cd pppdump; $(MAKE) clean
+
+dist-clean: clean
+ rm -f Makefile `find . -name Makefile -print`
+
+#kernel:
+# cd linux; ./kinstall.sh
diff --git a/mdk-stage1/ppp/modules/bsd-comp.c b/mdk-stage1/ppp/modules/bsd-comp.c
new file mode 100644
index 000000000..bbc8625db
--- /dev/null
+++ b/mdk-stage1/ppp/modules/bsd-comp.c
@@ -0,0 +1,1116 @@
+/* Because this code is derived from the 4.3BSD compress source:
+ *
+ *
+ * Copyright (c) 1985, 1986 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * James A. Woods, derived from original work by Spencer Thomas
+ * and Joseph Orost.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * This version is for use with STREAMS under SunOS 4.x,
+ * Digital UNIX, AIX 4.x, and SVR4 systems including Solaris 2.
+ *
+ * $Id: bsd-comp.c 195720 2001-06-11 11:44:34Z gc $
+ */
+
+#ifdef AIX4
+#include <net/net_globals.h>
+#endif
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/stream.h>
+#include <net/ppp_defs.h>
+#include "ppp_mod.h"
+
+#ifdef SVR4
+#include <sys/byteorder.h>
+#ifndef _BIG_ENDIAN
+#define BSD_LITTLE_ENDIAN
+#endif
+#endif
+
+#ifdef __osf__
+#undef FIRST
+#undef LAST
+#define BSD_LITTLE_ENDIAN
+#endif
+
+#define PACKETPTR mblk_t *
+#include <net/ppp-comp.h>
+
+#if DO_BSD_COMPRESS
+
+/*
+ * PPP "BSD compress" compression
+ * The differences between this compression and the classic BSD LZW
+ * source are obvious from the requirement that the classic code worked
+ * with files while this handles arbitrarily long streams that
+ * are broken into packets. They are:
+ *
+ * When the code size expands, a block of junk is not emitted by
+ * the compressor and not expected by the decompressor.
+ *
+ * New codes are not necessarily assigned every time an old
+ * code is output by the compressor. This is because a packet
+ * end forces a code to be emitted, but does not imply that a
+ * new sequence has been seen.
+ *
+ * The compression ratio is checked at the first end of a packet
+ * after the appropriate gap. Besides simplifying and speeding
+ * things up, this makes it more likely that the transmitter
+ * and receiver will agree when the dictionary is cleared when
+ * compression is not going well.
+ */
+
+/*
+ * A dictionary for doing BSD compress.
+ */
+struct bsd_db {
+ int totlen; /* length of this structure */
+ u_int hsize; /* size of the hash table */
+ u_char hshift; /* used in hash function */
+ u_char n_bits; /* current bits/code */
+ u_char maxbits;
+ u_char debug;
+ u_char unit;
+ u_short seqno; /* sequence number of next packet */
+ u_int hdrlen; /* header length to preallocate */
+ u_int mru;
+ u_int maxmaxcode; /* largest valid code */
+ u_int max_ent; /* largest code in use */
+ u_int in_count; /* uncompressed bytes, aged */
+ u_int bytes_out; /* compressed bytes, aged */
+ u_int ratio; /* recent compression ratio */
+ u_int checkpoint; /* when to next check the ratio */
+ u_int clear_count; /* times dictionary cleared */
+ u_int incomp_count; /* incompressible packets */
+ u_int incomp_bytes; /* incompressible bytes */
+ u_int uncomp_count; /* uncompressed packets */
+ u_int uncomp_bytes; /* uncompressed bytes */
+ u_int comp_count; /* compressed packets */
+ u_int comp_bytes; /* compressed bytes */
+ u_short *lens; /* array of lengths of codes */
+ struct bsd_dict {
+ union { /* hash value */
+ u_int32_t fcode;
+ struct {
+#ifdef BSD_LITTLE_ENDIAN
+ u_short prefix; /* preceding code */
+ u_char suffix; /* last character of new code */
+ u_char pad;
+#else
+ u_char pad;
+ u_char suffix; /* last character of new code */
+ u_short prefix; /* preceding code */
+#endif
+ } hs;
+ } f;
+ u_short codem1; /* output of hash table -1 */
+ u_short cptr; /* map code to hash table entry */
+ } dict[1];
+};
+
+#define BSD_OVHD 2 /* BSD compress overhead/packet */
+#define BSD_INIT_BITS BSD_MIN_BITS
+
+static void *bsd_comp_alloc __P((u_char *options, int opt_len));
+static void *bsd_decomp_alloc __P((u_char *options, int opt_len));
+static void bsd_free __P((void *state));
+static int bsd_comp_init __P((void *state, u_char *options, int opt_len,
+ int unit, int hdrlen, int debug));
+static int bsd_decomp_init __P((void *state, u_char *options, int opt_len,
+ int unit, int hdrlen, int mru, int debug));
+static int bsd_compress __P((void *state, mblk_t **mret,
+ mblk_t *mp, int slen, int maxolen));
+static void bsd_incomp __P((void *state, mblk_t *dmsg));
+static int bsd_decompress __P((void *state, mblk_t *cmp, mblk_t **dmpp));
+static void bsd_reset __P((void *state));
+static void bsd_comp_stats __P((void *state, struct compstat *stats));
+
+/*
+ * Procedures exported to ppp_comp.c.
+ */
+struct compressor ppp_bsd_compress = {
+ CI_BSD_COMPRESS, /* compress_proto */
+ bsd_comp_alloc, /* comp_alloc */
+ bsd_free, /* comp_free */
+ bsd_comp_init, /* comp_init */
+ bsd_reset, /* comp_reset */
+ bsd_compress, /* compress */
+ bsd_comp_stats, /* comp_stat */
+ bsd_decomp_alloc, /* decomp_alloc */
+ bsd_free, /* decomp_free */
+ bsd_decomp_init, /* decomp_init */
+ bsd_reset, /* decomp_reset */
+ bsd_decompress, /* decompress */
+ bsd_incomp, /* incomp */
+ bsd_comp_stats, /* decomp_stat */
+};
+
+/*
+ * the next two codes should not be changed lightly, as they must not
+ * lie within the contiguous general code space.
+ */
+#define CLEAR 256 /* table clear output code */
+#define FIRST 257 /* first free entry */
+#define LAST 255
+
+#define MAXCODE(b) ((1 << (b)) - 1)
+#define BADCODEM1 MAXCODE(BSD_MAX_BITS)
+
+#define BSD_HASH(prefix,suffix,hshift) ((((u_int32_t)(suffix)) << (hshift)) \
+ ^ (u_int32_t)(prefix))
+#define BSD_KEY(prefix,suffix) ((((u_int32_t)(suffix)) << 16) \
+ + (u_int32_t)(prefix))
+
+#define CHECK_GAP 10000 /* Ratio check interval */
+
+#define RATIO_SCALE_LOG 8
+#define RATIO_SCALE (1<<RATIO_SCALE_LOG)
+#define RATIO_MAX (0x7fffffff>>RATIO_SCALE_LOG)
+
+#define DECOMP_CHUNK 256
+
+/*
+ * clear the dictionary
+ */
+static void
+bsd_clear(db)
+ struct bsd_db *db;
+{
+ db->clear_count++;
+ db->max_ent = FIRST-1;
+ db->n_bits = BSD_INIT_BITS;
+ db->ratio = 0;
+ db->bytes_out = 0;
+ db->in_count = 0;
+ db->checkpoint = CHECK_GAP;
+}
+
+/*
+ * If the dictionary is full, then see if it is time to reset it.
+ *
+ * Compute the compression ratio using fixed-point arithmetic
+ * with 8 fractional bits.
+ *
+ * Since we have an infinite stream instead of a single file,
+ * watch only the local compression ratio.
+ *
+ * Since both peers must reset the dictionary at the same time even in
+ * the absence of CLEAR codes (while packets are incompressible), they
+ * must compute the same ratio.
+ */
+static int /* 1=output CLEAR */
+bsd_check(db)
+ struct bsd_db *db;
+{
+ u_int new_ratio;
+
+ if (db->in_count >= db->checkpoint) {
+ /* age the ratio by limiting the size of the counts */
+ if (db->in_count >= RATIO_MAX
+ || db->bytes_out >= RATIO_MAX) {
+ db->in_count -= db->in_count/4;
+ db->bytes_out -= db->bytes_out/4;
+ }
+
+ db->checkpoint = db->in_count + CHECK_GAP;
+
+ if (db->max_ent >= db->maxmaxcode) {
+ /* Reset the dictionary only if the ratio is worse,
+ * or if it looks as if it has been poisoned
+ * by incompressible data.
+ *
+ * This does not overflow, because
+ * db->in_count <= RATIO_MAX.
+ */
+ new_ratio = db->in_count << RATIO_SCALE_LOG;
+ if (db->bytes_out != 0)
+ new_ratio /= db->bytes_out;
+
+ if (new_ratio < db->ratio || new_ratio < 1 * RATIO_SCALE) {
+ bsd_clear(db);
+ return 1;
+ }
+ db->ratio = new_ratio;
+ }
+ }
+ return 0;
+}
+
+/*
+ * Return statistics.
+ */
+static void
+bsd_comp_stats(state, stats)
+ void *state;
+ struct compstat *stats;
+{
+ struct bsd_db *db = (struct bsd_db *) state;
+ u_int out;
+
+ stats->unc_bytes = db->uncomp_bytes;
+ stats->unc_packets = db->uncomp_count;
+ stats->comp_bytes = db->comp_bytes;
+ stats->comp_packets = db->comp_count;
+ stats->inc_bytes = db->incomp_bytes;
+ stats->inc_packets = db->incomp_count;
+ stats->ratio = db->in_count;
+ out = db->bytes_out;
+ if (stats->ratio <= 0x7fffff)
+ stats->ratio <<= 8;
+ else
+ out >>= 8;
+ if (out != 0)
+ stats->ratio /= out;
+}
+
+/*
+ * Reset state, as on a CCP ResetReq.
+ */
+static void
+bsd_reset(state)
+ void *state;
+{
+ struct bsd_db *db = (struct bsd_db *) state;
+
+ db->seqno = 0;
+ bsd_clear(db);
+ db->clear_count = 0;
+}
+
+/*
+ * Allocate space for a (de) compressor.
+ */
+static void *
+bsd_alloc(options, opt_len, decomp)
+ u_char *options;
+ int opt_len, decomp;
+{
+ int bits;
+ u_int newlen, hsize, hshift, maxmaxcode;
+ struct bsd_db *db;
+
+ if (opt_len != 3 || options[0] != CI_BSD_COMPRESS || options[1] != 3
+ || BSD_VERSION(options[2]) != BSD_CURRENT_VERSION)
+ return NULL;
+
+ bits = BSD_NBITS(options[2]);
+ switch (bits) {
+ case 9: /* needs 82152 for both directions */
+ case 10: /* needs 84144 */
+ case 11: /* needs 88240 */
+ case 12: /* needs 96432 */
+ hsize = 5003;
+ hshift = 4;
+ break;
+ case 13: /* needs 176784 */
+ hsize = 9001;
+ hshift = 5;
+ break;
+ case 14: /* needs 353744 */
+ hsize = 18013;
+ hshift = 6;
+ break;
+ case 15: /* needs 691440 */
+ hsize = 35023;
+ hshift = 7;
+ break;
+ case 16: /* needs 1366160--far too much, */
+ /* hsize = 69001; */ /* and 69001 is too big for cptr */
+ /* hshift = 8; */ /* in struct bsd_db */
+ /* break; */
+ default:
+ return NULL;
+ }
+
+ maxmaxcode = MAXCODE(bits);
+ newlen = sizeof(*db) + (hsize-1) * (sizeof(db->dict[0]));
+#ifdef __osf__
+ db = (struct bsd_db *) ALLOC_SLEEP(newlen);
+#else
+ db = (struct bsd_db *) ALLOC_NOSLEEP(newlen);
+#endif
+ if (!db)
+ return NULL;
+ bzero(db, sizeof(*db) - sizeof(db->dict));
+
+ if (!decomp) {
+ db->lens = NULL;
+ } else {
+#ifdef __osf__
+ db->lens = (u_short *) ALLOC_SLEEP((maxmaxcode+1) * sizeof(db->lens[0]));
+#else
+ db->lens = (u_short *) ALLOC_NOSLEEP((maxmaxcode+1) * sizeof(db->lens[0]));
+#endif
+ if (!db->lens) {
+ FREE(db, newlen);
+ return NULL;
+ }
+ }
+
+ db->totlen = newlen;
+ db->hsize = hsize;
+ db->hshift = hshift;
+ db->maxmaxcode = maxmaxcode;
+ db->maxbits = bits;
+
+ return (void *) db;
+}
+
+static void
+bsd_free(state)
+ void *state;
+{
+ struct bsd_db *db = (struct bsd_db *) state;
+
+ if (db->lens)
+ FREE(db->lens, (db->maxmaxcode+1) * sizeof(db->lens[0]));
+ FREE(db, db->totlen);
+}
+
+static void *
+bsd_comp_alloc(options, opt_len)
+ u_char *options;
+ int opt_len;
+{
+ return bsd_alloc(options, opt_len, 0);
+}
+
+static void *
+bsd_decomp_alloc(options, opt_len)
+ u_char *options;
+ int opt_len;
+{
+ return bsd_alloc(options, opt_len, 1);
+}
+
+/*
+ * Initialize the database.
+ */
+static int
+bsd_init(db, options, opt_len, unit, hdrlen, mru, debug, decomp)
+ struct bsd_db *db;
+ u_char *options;
+ int opt_len, unit, hdrlen, mru, debug, decomp;
+{
+ int i;
+
+ if (opt_len < CILEN_BSD_COMPRESS
+ || options[0] != CI_BSD_COMPRESS || options[1] != CILEN_BSD_COMPRESS
+ || BSD_VERSION(options[2]) != BSD_CURRENT_VERSION
+ || BSD_NBITS(options[2]) != db->maxbits
+ || decomp && db->lens == NULL)
+ return 0;
+
+ if (decomp) {
+ i = LAST+1;
+ while (i != 0)
+ db->lens[--i] = 1;
+ }
+ i = db->hsize;
+ while (i != 0) {
+ db->dict[--i].codem1 = BADCODEM1;
+ db->dict[i].cptr = 0;
+ }
+
+ db->unit = unit;
+ db->hdrlen = hdrlen;
+ db->mru = mru;
+ if (debug)
+ db->debug = 1;
+
+ bsd_reset(db);
+
+ return 1;
+}
+
+static int
+bsd_comp_init(state, options, opt_len, unit, hdrlen, debug)
+ void *state;
+ u_char *options;
+ int opt_len, unit, hdrlen, debug;
+{
+ return bsd_init((struct bsd_db *) state, options, opt_len,
+ unit, hdrlen, 0, debug, 0);
+}
+
+static int
+bsd_decomp_init(state, options, opt_len, unit, hdrlen, mru, debug)
+ void *state;
+ u_char *options;
+ int opt_len, unit, hdrlen, mru, debug;
+{
+ return bsd_init((struct bsd_db *) state, options, opt_len,
+ unit, hdrlen, mru, debug, 1);
+}
+
+
+/*
+ * compress a packet
+ * One change from the BSD compress command is that when the
+ * code size expands, we do not output a bunch of padding.
+ *
+ * N.B. at present, we ignore the hdrlen specified in the comp_init call.
+ */
+static int /* new slen */
+bsd_compress(state, mretp, mp, slen, maxolen)
+ void *state;
+ mblk_t **mretp; /* return compressed mbuf chain here */
+ mblk_t *mp; /* from here */
+ int slen; /* uncompressed length */
+ int maxolen; /* max compressed length */
+{
+ struct bsd_db *db = (struct bsd_db *) state;
+ int hshift = db->hshift;
+ u_int max_ent = db->max_ent;
+ u_int n_bits = db->n_bits;
+ u_int bitno = 32;
+ u_int32_t accm = 0, fcode;
+ struct bsd_dict *dictp;
+ u_char c;
+ int hval, disp, ent, ilen;
+ mblk_t *np, *mret;
+ u_char *rptr, *wptr;
+ u_char *cp_end;
+ int olen;
+ mblk_t *m, **mnp;
+
+#define PUTBYTE(v) { \
+ if (wptr) { \
+ *wptr++ = (v); \
+ if (wptr >= cp_end) { \
+ m->b_wptr = wptr; \
+ m = m->b_cont; \
+ if (m) { \
+ wptr = m->b_wptr; \
+ cp_end = m->b_datap->db_lim; \
+ } else \
+ wptr = NULL; \
+ } \
+ } \
+ ++olen; \
+}
+
+#define OUTPUT(ent) { \
+ bitno -= n_bits; \
+ accm |= ((ent) << bitno); \
+ do { \
+ PUTBYTE(accm >> 24); \
+ accm <<= 8; \
+ bitno += 8; \
+ } while (bitno <= 24); \
+}
+
+ /*
+ * First get the protocol and check that we're
+ * interested in this packet.
+ */
+ *mretp = NULL;
+ rptr = mp->b_rptr;
+ if (rptr + PPP_HDRLEN > mp->b_wptr) {
+ if (!pullupmsg(mp, PPP_HDRLEN))
+ return 0;
+ rptr = mp->b_rptr;
+ }
+ ent = PPP_PROTOCOL(rptr); /* get the protocol */
+ if (ent < 0x21 || ent > 0xf9)
+ return 0;
+
+ /* Don't generate compressed packets which are larger than
+ the uncompressed packet. */
+ if (maxolen > slen)
+ maxolen = slen;
+
+ /* Allocate enough message blocks to give maxolen total space. */
+ mnp = &mret;
+ for (olen = maxolen; olen > 0; ) {
+ m = allocb((olen < 4096? olen: 4096), BPRI_MED);
+ *mnp = m;
+ if (m == NULL) {
+ if (mret != NULL) {
+ freemsg(mret);
+ mnp = &mret;
+ }
+ break;
+ }
+ mnp = &m->b_cont;
+ olen -= m->b_datap->db_lim - m->b_wptr;
+ }
+ *mnp = NULL;
+
+ if ((m = mret) != NULL) {
+ wptr = m->b_wptr;
+ cp_end = m->b_datap->db_lim;
+ } else
+ wptr = cp_end = NULL;
+ olen = 0;
+
+ /*
+ * Copy the PPP header over, changing the protocol,
+ * and install the 2-byte sequence number.
+ */
+ if (wptr) {
+ wptr[0] = PPP_ADDRESS(rptr);
+ wptr[1] = PPP_CONTROL(rptr);
+ wptr[2] = 0; /* change the protocol */
+ wptr[3] = PPP_COMP;
+ wptr[4] = db->seqno >> 8;
+ wptr[5] = db->seqno;
+ wptr += PPP_HDRLEN + BSD_OVHD;
+ }
+ ++db->seqno;
+ rptr += PPP_HDRLEN;
+
+ slen = mp->b_wptr - rptr;
+ ilen = slen + 1;
+ np = mp->b_cont;
+ for (;;) {
+ if (slen <= 0) {
+ if (!np)
+ break;
+ rptr = np->b_rptr;
+ slen = np->b_wptr - rptr;
+ np = np->b_cont;
+ if (!slen)
+ continue; /* handle 0-length buffers */
+ ilen += slen;
+ }
+
+ slen--;
+ c = *rptr++;
+ fcode = BSD_KEY(ent, c);
+ hval = BSD_HASH(ent, c, hshift);
+ dictp = &db->dict[hval];
+
+ /* Validate and then check the entry. */
+ if (dictp->codem1 >= max_ent)
+ goto nomatch;
+ if (dictp->f.fcode == fcode) {
+ ent = dictp->codem1+1;
+ continue; /* found (prefix,suffix) */
+ }
+
+ /* continue probing until a match or invalid entry */
+ disp = (hval == 0) ? 1 : hval;
+ do {
+ hval += disp;
+ if (hval >= db->hsize)
+ hval -= db->hsize;
+ dictp = &db->dict[hval];
+ if (dictp->codem1 >= max_ent)
+ goto nomatch;
+ } while (dictp->f.fcode != fcode);
+ ent = dictp->codem1 + 1; /* finally found (prefix,suffix) */
+ continue;
+
+ nomatch:
+ OUTPUT(ent); /* output the prefix */
+
+ /* code -> hashtable */
+ if (max_ent < db->maxmaxcode) {
+ struct bsd_dict *dictp2;
+ /* expand code size if needed */
+ if (max_ent >= MAXCODE(n_bits))
+ db->n_bits = ++n_bits;
+
+ /* Invalidate old hash table entry using
+ * this code, and then take it over.
+ */
+ dictp2 = &db->dict[max_ent+1];
+ if (db->dict[dictp2->cptr].codem1 == max_ent)
+ db->dict[dictp2->cptr].codem1 = BADCODEM1;
+ dictp2->cptr = hval;
+ dictp->codem1 = max_ent;
+ dictp->f.fcode = fcode;
+
+ db->max_ent = ++max_ent;
+ }
+ ent = c;
+ }
+
+ OUTPUT(ent); /* output the last code */
+ db->bytes_out += olen;
+ db->in_count += ilen;
+ if (bitno < 32)
+ ++db->bytes_out; /* count complete bytes */
+
+ if (bsd_check(db))
+ OUTPUT(CLEAR); /* do not count the CLEAR */
+
+ /*
+ * Pad dribble bits of last code with ones.
+ * Do not emit a completely useless byte of ones.
+ */
+ if (bitno != 32)
+ PUTBYTE((accm | (0xff << (bitno-8))) >> 24);
+
+ /*
+ * Increase code size if we would have without the packet
+ * boundary and as the decompressor will.
+ */
+ if (max_ent >= MAXCODE(n_bits) && max_ent < db->maxmaxcode)
+ db->n_bits++;
+
+ db->uncomp_bytes += ilen;
+ ++db->uncomp_count;
+ if (olen + PPP_HDRLEN + BSD_OVHD > maxolen && mret != NULL) {
+ /* throw away the compressed stuff if it is longer than uncompressed */
+ freemsg(mret);
+ mret = NULL;
+ ++db->incomp_count;
+ db->incomp_bytes += ilen;
+ } else if (wptr != NULL) {
+ m->b_wptr = wptr;
+ if (m->b_cont) {
+ freemsg(m->b_cont);
+ m->b_cont = NULL;
+ }
+ ++db->comp_count;
+ db->comp_bytes += olen + BSD_OVHD;
+ }
+
+ *mretp = mret;
+ return olen + PPP_HDRLEN + BSD_OVHD;
+#undef OUTPUT
+#undef PUTBYTE
+}
+
+
+/*
+ * Update the "BSD Compress" dictionary on the receiver for
+ * incompressible data by pretending to compress the incoming data.
+ */
+static void
+bsd_incomp(state, dmsg)
+ void *state;
+ mblk_t *dmsg;
+{
+ struct bsd_db *db = (struct bsd_db *) state;
+ u_int hshift = db->hshift;
+ u_int max_ent = db->max_ent;
+ u_int n_bits = db->n_bits;
+ struct bsd_dict *dictp;
+ u_int32_t fcode;
+ u_char c;
+ long hval, disp;
+ int slen, ilen;
+ u_int bitno = 7;
+ u_char *rptr;
+ u_int ent;
+
+ rptr = dmsg->b_rptr;
+ if (rptr + PPP_HDRLEN > dmsg->b_wptr) {
+ if (!pullupmsg(dmsg, PPP_HDRLEN))
+ return;
+ rptr = dmsg->b_rptr;
+ }
+ ent = PPP_PROTOCOL(rptr); /* get the protocol */
+ if (ent < 0x21 || ent > 0xf9)
+ return;
+
+ db->seqno++;
+ ilen = 1; /* count the protocol as 1 byte */
+ rptr += PPP_HDRLEN;
+ for (;;) {
+ slen = dmsg->b_wptr - rptr;
+ if (slen <= 0) {
+ dmsg = dmsg->b_cont;
+ if (!dmsg)
+ break;
+ rptr = dmsg->b_rptr;
+ continue; /* skip zero-length buffers */
+ }
+ ilen += slen;
+
+ do {
+ c = *rptr++;
+ fcode = BSD_KEY(ent, c);
+ hval = BSD_HASH(ent, c, hshift);
+ dictp = &db->dict[hval];
+
+ /* validate and then check the entry */
+ if (dictp->codem1 >= max_ent)
+ goto nomatch;
+ if (dictp->f.fcode == fcode) {
+ ent = dictp->codem1+1;
+ continue; /* found (prefix,suffix) */
+ }
+
+ /* continue probing until a match or invalid entry */
+ disp = (hval == 0) ? 1 : hval;
+ do {
+ hval += disp;
+ if (hval >= db->hsize)
+ hval -= db->hsize;
+ dictp = &db->dict[hval];
+ if (dictp->codem1 >= max_ent)
+ goto nomatch;
+ } while (dictp->f.fcode != fcode);
+ ent = dictp->codem1+1;
+ continue; /* finally found (prefix,suffix) */
+
+ nomatch: /* output (count) the prefix */
+ bitno += n_bits;
+
+ /* code -> hashtable */
+ if (max_ent < db->maxmaxcode) {
+ struct bsd_dict *dictp2;
+ /* expand code size if needed */
+ if (max_ent >= MAXCODE(n_bits))
+ db->n_bits = ++n_bits;
+
+ /* Invalidate previous hash table entry
+ * assigned this code, and then take it over.
+ */
+ dictp2 = &db->dict[max_ent+1];
+ if (db->dict[dictp2->cptr].codem1 == max_ent)
+ db->dict[dictp2->cptr].codem1 = BADCODEM1;
+ dictp2->cptr = hval;
+ dictp->codem1 = max_ent;
+ dictp->f.fcode = fcode;
+
+ db->max_ent = ++max_ent;
+ db->lens[max_ent] = db->lens[ent]+1;
+ }
+ ent = c;
+ } while (--slen != 0);
+ }
+ bitno += n_bits; /* output (count) the last code */
+ db->bytes_out += bitno/8;
+ db->in_count += ilen;
+ (void)bsd_check(db);
+
+ ++db->incomp_count;
+ db->incomp_bytes += ilen;
+ ++db->uncomp_count;
+ db->uncomp_bytes += ilen;
+
+ /* Increase code size if we would have without the packet
+ * boundary and as the decompressor will.
+ */
+ if (max_ent >= MAXCODE(n_bits) && max_ent < db->maxmaxcode)
+ db->n_bits++;
+}
+
+
+/*
+ * Decompress "BSD Compress"
+ *
+ * Because of patent problems, we return DECOMP_ERROR for errors
+ * found by inspecting the input data and for system problems, but
+ * DECOMP_FATALERROR for any errors which could possibly be said to
+ * be being detected "after" decompression. For DECOMP_ERROR,
+ * we can issue a CCP reset-request; for DECOMP_FATALERROR, we may be
+ * infringing a patent of Motorola's if we do, so we take CCP down
+ * instead.
+ *
+ * Given that the frame has the correct sequence number and a good FCS,
+ * errors such as invalid codes in the input most likely indicate a
+ * bug, so we return DECOMP_FATALERROR for them in order to turn off
+ * compression, even though they are detected by inspecting the input.
+ */
+static int
+bsd_decompress(state, cmsg, dmpp)
+ void *state;
+ mblk_t *cmsg, **dmpp;
+{
+ struct bsd_db *db = (struct bsd_db *) state;
+ u_int max_ent = db->max_ent;
+ u_int32_t accm = 0;
+ u_int bitno = 32; /* 1st valid bit in accm */
+ u_int n_bits = db->n_bits;
+ u_int tgtbitno = 32-n_bits; /* bitno when we have a code */
+ struct bsd_dict *dictp;
+ int explen, i, seq, len;
+ u_int incode, oldcode, finchar;
+ u_char *p, *rptr, *wptr;
+ mblk_t *dmsg, *mret;
+ int adrs, ctrl, ilen;
+ int dlen, space, codelen, extra;
+
+ /*
+ * Get at least the BSD Compress header in the first buffer
+ */
+ rptr = cmsg->b_rptr;
+ if (rptr + PPP_HDRLEN + BSD_OVHD >= cmsg->b_wptr) {
+ if (!pullupmsg(cmsg, PPP_HDRLEN + BSD_OVHD + 1)) {
+ if (db->debug)
+ printf("bsd_decomp%d: failed to pullup\n", db->unit);
+ return DECOMP_ERROR;
+ }
+ rptr = cmsg->b_rptr;
+ }
+
+ /*
+ * Save the address/control from the PPP header
+ * and then get the sequence number.
+ */
+ adrs = PPP_ADDRESS(rptr);
+ ctrl = PPP_CONTROL(rptr);
+ rptr += PPP_HDRLEN;
+ seq = (rptr[0] << 8) + rptr[1];
+ rptr += BSD_OVHD;
+ ilen = len = cmsg->b_wptr - rptr;
+
+ /*
+ * Check the sequence number and give up if it is not what we expect.
+ */
+ if (seq != db->seqno++) {
+ if (db->debug)
+ printf("bsd_decomp%d: bad sequence # %d, expected %d\n",
+ db->unit, seq, db->seqno - 1);
+ return DECOMP_ERROR;
+ }
+
+ /*
+ * Allocate one message block to start with.
+ */
+ if ((dmsg = allocb(DECOMP_CHUNK + db->hdrlen, BPRI_MED)) == NULL)
+ return DECOMP_ERROR;
+ mret = dmsg;
+ dmsg->b_wptr += db->hdrlen;
+ dmsg->b_rptr = wptr = dmsg->b_wptr;
+
+ /* Fill in the ppp header, but not the last byte of the protocol
+ (that comes from the decompressed data). */
+ wptr[0] = adrs;
+ wptr[1] = ctrl;
+ wptr[2] = 0;
+ wptr += PPP_HDRLEN - 1;
+ space = dmsg->b_datap->db_lim - wptr;
+
+ oldcode = CLEAR;
+ explen = 0;
+ for (;;) {
+ if (len == 0) {
+ cmsg = cmsg->b_cont;
+ if (!cmsg) /* quit at end of message */
+ break;
+ rptr = cmsg->b_rptr;
+ len = cmsg->b_wptr - rptr;
+ ilen += len;
+ continue; /* handle 0-length buffers */
+ }
+
+ /*
+ * Accumulate bytes until we have a complete code.
+ * Then get the next code, relying on the 32-bit,
+ * unsigned accm to mask the result.
+ */
+ bitno -= 8;
+ accm |= *rptr++ << bitno;
+ --len;
+ if (tgtbitno < bitno)
+ continue;
+ incode = accm >> tgtbitno;
+ accm <<= n_bits;
+ bitno += n_bits;
+
+ if (incode == CLEAR) {
+ /*
+ * The dictionary must only be cleared at
+ * the end of a packet. But there could be an
+ * empty message block at the end.
+ */
+ if (len > 0 || cmsg->b_cont != 0) {
+ if (cmsg->b_cont)
+ len += msgdsize(cmsg->b_cont);
+ if (len > 0) {
+ freemsg(dmsg);
+ if (db->debug)
+ printf("bsd_decomp%d: bad CLEAR\n", db->unit);
+ return DECOMP_FATALERROR;
+ }
+ }
+ bsd_clear(db);
+ explen = ilen = 0;
+ break;
+ }
+
+ if (incode > max_ent + 2 || incode > db->maxmaxcode
+ || incode > max_ent && oldcode == CLEAR) {
+ freemsg(dmsg);
+ if (db->debug) {
+ printf("bsd_decomp%d: bad code 0x%x oldcode=0x%x ",
+ db->unit, incode, oldcode);
+ printf("max_ent=0x%x dlen=%d seqno=%d\n",
+ max_ent, dlen, db->seqno);
+ }
+ return DECOMP_FATALERROR; /* probably a bug */
+ }
+
+ /* Special case for KwKwK string. */
+ if (incode > max_ent) {
+ finchar = oldcode;
+ extra = 1;
+ } else {
+ finchar = incode;
+ extra = 0;
+ }
+
+ codelen = db->lens[finchar];
+ explen += codelen + extra;
+ if (explen > db->mru + 1) {
+ freemsg(dmsg);
+ if (db->debug)
+ printf("bsd_decomp%d: ran out of mru\n", db->unit);
+ return DECOMP_FATALERROR;
+ }
+
+ /*
+ * Decode this code and install it in the decompressed buffer.
+ */
+ space -= codelen + extra;
+ if (space < 0) {
+ /* Allocate another message block. */
+ dmsg->b_wptr = wptr;
+ dlen = codelen + extra;
+ if (dlen < DECOMP_CHUNK)
+ dlen = DECOMP_CHUNK;
+ if ((dmsg->b_cont = allocb(dlen, BPRI_MED)) == NULL) {
+ freemsg(dmsg);
+ return DECOMP_ERROR;
+ }
+ dmsg = dmsg->b_cont;
+ wptr = dmsg->b_wptr;
+ space = dmsg->b_datap->db_lim - wptr - codelen - extra;
+ }
+ p = (wptr += codelen);
+ while (finchar > LAST) {
+ dictp = &db->dict[db->dict[finchar].cptr];
+#ifdef DEBUG
+ --codelen;
+ if (codelen <= 0) {
+ freemsg(dmsg);
+ printf("bsd_decomp%d: fell off end of chain ", db->unit);
+ printf("0x%x at 0x%x by 0x%x, max_ent=0x%x\n",
+ incode, finchar, db->dict[finchar].cptr, max_ent);
+ return DECOMP_FATALERROR;
+ }
+ if (dictp->codem1 != finchar-1) {
+ freemsg(dmsg);
+ printf("bsd_decomp%d: bad code chain 0x%x finchar=0x%x ",
+ db->unit, incode, finchar);
+ printf("oldcode=0x%x cptr=0x%x codem1=0x%x\n", oldcode,
+ db->dict[finchar].cptr, dictp->codem1);
+ return DECOMP_FATALERROR;
+ }
+#endif
+ *--p = dictp->f.hs.suffix;
+ finchar = dictp->f.hs.prefix;
+ }
+ *--p = finchar;
+
+#ifdef DEBUG
+ if (--codelen != 0)
+ printf("bsd_decomp%d: short by %d after code 0x%x, max_ent=0x%x\n",
+ db->unit, codelen, incode, max_ent);
+#endif
+
+ if (extra) /* the KwKwK case again */
+ *wptr++ = finchar;
+
+ /*
+ * If not first code in a packet, and
+ * if not out of code space, then allocate a new code.
+ *
+ * Keep the hash table correct so it can be used
+ * with uncompressed packets.
+ */
+ if (oldcode != CLEAR && max_ent < db->maxmaxcode) {
+ struct bsd_dict *dictp2;
+ u_int32_t fcode;
+ int hval, disp;
+
+ fcode = BSD_KEY(oldcode,finchar);
+ hval = BSD_HASH(oldcode,finchar,db->hshift);
+ dictp = &db->dict[hval];
+
+ /* look for a free hash table entry */
+ if (dictp->codem1 < max_ent) {
+ disp = (hval == 0) ? 1 : hval;
+ do {
+ hval += disp;
+ if (hval >= db->hsize)
+ hval -= db->hsize;
+ dictp = &db->dict[hval];
+ } while (dictp->codem1 < max_ent);
+ }
+
+ /*
+ * Invalidate previous hash table entry
+ * assigned this code, and then take it over
+ */
+ dictp2 = &db->dict[max_ent+1];
+ if (db->dict[dictp2->cptr].codem1 == max_ent) {
+ db->dict[dictp2->cptr].codem1 = BADCODEM1;
+ }
+ dictp2->cptr = hval;
+ dictp->codem1 = max_ent;
+ dictp->f.fcode = fcode;
+
+ db->max_ent = ++max_ent;
+ db->lens[max_ent] = db->lens[oldcode]+1;
+
+ /* Expand code size if needed. */
+ if (max_ent >= MAXCODE(n_bits) && max_ent < db->maxmaxcode) {
+ db->n_bits = ++n_bits;
+ tgtbitno = 32-n_bits;
+ }
+ }
+ oldcode = incode;
+ }
+ dmsg->b_wptr = wptr;
+
+ /*
+ * Keep the checkpoint right so that incompressible packets
+ * clear the dictionary at the right times.
+ */
+ db->bytes_out += ilen;
+ db->in_count += explen;
+ if (bsd_check(db) && db->debug) {
+ printf("bsd_decomp%d: peer should have cleared dictionary\n",
+ db->unit);
+ }
+
+ ++db->comp_count;
+ db->comp_bytes += ilen + BSD_OVHD;
+ ++db->uncomp_count;
+ db->uncomp_bytes += explen;
+
+ *dmpp = mret;
+ return DECOMP_OK;
+}
+#endif /* DO_BSD_COMPRESS */
diff --git a/mdk-stage1/ppp/modules/deflate.c b/mdk-stage1/ppp/modules/deflate.c
new file mode 100644
index 000000000..592344f9b
--- /dev/null
+++ b/mdk-stage1/ppp/modules/deflate.c
@@ -0,0 +1,760 @@
+/*
+ * ppp_deflate.c - interface the zlib procedures for Deflate compression
+ * and decompression (as used by gzip) to the PPP code.
+ * This version is for use with STREAMS under SunOS 4.x, Solaris 2,
+ * SVR4, OSF/1 and AIX 4.x.
+ *
+ * Copyright (c) 1994 The Australian National University.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation is hereby granted, provided that the above copyright
+ * notice appears in all copies. This software is provided without any
+ * warranty, express or implied. The Australian National University
+ * makes no representations about the suitability of this software for
+ * any purpose.
+ *
+ * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
+ * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
+ * THE AUSTRALIAN NATIONAL UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
+ * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
+ * OR MODIFICATIONS.
+ *
+ * $Id: deflate.c 195720 2001-06-11 11:44:34Z gc $
+ */
+
+#ifdef AIX4
+#include <net/net_globals.h>
+#endif
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/stream.h>
+#include <net/ppp_defs.h>
+#include "ppp_mod.h"
+
+#define PACKETPTR mblk_t *
+#include <net/ppp-comp.h>
+
+#ifdef __osf__
+#include "zlib.h"
+#else
+#include "../common/zlib.h"
+#endif
+
+#if DO_DEFLATE
+
+#define DEFLATE_DEBUG 1
+
+/*
+ * State for a Deflate (de)compressor.
+ */
+struct deflate_state {
+ int seqno;
+ int w_size;
+ int unit;
+ int hdrlen;
+ int mru;
+ int debug;
+ z_stream strm;
+ struct compstat stats;
+};
+
+#define DEFLATE_OVHD 2 /* Deflate overhead/packet */
+
+static void *z_alloc __P((void *, u_int items, u_int size));
+static void *z_alloc_init __P((void *, u_int items, u_int size));
+static void z_free __P((void *, void *ptr));
+static void *z_comp_alloc __P((u_char *options, int opt_len));
+static void *z_decomp_alloc __P((u_char *options, int opt_len));
+static void z_comp_free __P((void *state));
+static void z_decomp_free __P((void *state));
+static int z_comp_init __P((void *state, u_char *options, int opt_len,
+ int unit, int hdrlen, int debug));
+static int z_decomp_init __P((void *state, u_char *options, int opt_len,
+ int unit, int hdrlen, int mru, int debug));
+static int z_compress __P((void *state, mblk_t **mret,
+ mblk_t *mp, int slen, int maxolen));
+static void z_incomp __P((void *state, mblk_t *dmsg));
+static int z_decompress __P((void *state, mblk_t *cmp,
+ mblk_t **dmpp));
+static void z_comp_reset __P((void *state));
+static void z_decomp_reset __P((void *state));
+static void z_comp_stats __P((void *state, struct compstat *stats));
+
+/*
+ * Procedures exported to ppp_comp.c.
+ */
+struct compressor ppp_deflate = {
+ CI_DEFLATE, /* compress_proto */
+ z_comp_alloc, /* comp_alloc */
+ z_comp_free, /* comp_free */
+ z_comp_init, /* comp_init */
+ z_comp_reset, /* comp_reset */
+ z_compress, /* compress */
+ z_comp_stats, /* comp_stat */
+ z_decomp_alloc, /* decomp_alloc */
+ z_decomp_free, /* decomp_free */
+ z_decomp_init, /* decomp_init */
+ z_decomp_reset, /* decomp_reset */
+ z_decompress, /* decompress */
+ z_incomp, /* incomp */
+ z_comp_stats, /* decomp_stat */
+};
+
+struct compressor ppp_deflate_draft = {
+ CI_DEFLATE_DRAFT, /* compress_proto */
+ z_comp_alloc, /* comp_alloc */
+ z_comp_free, /* comp_free */
+ z_comp_init, /* comp_init */
+ z_comp_reset, /* comp_reset */
+ z_compress, /* compress */
+ z_comp_stats, /* comp_stat */
+ z_decomp_alloc, /* decomp_alloc */
+ z_decomp_free, /* decomp_free */
+ z_decomp_init, /* decomp_init */
+ z_decomp_reset, /* decomp_reset */
+ z_decompress, /* decompress */
+ z_incomp, /* incomp */
+ z_comp_stats, /* decomp_stat */
+};
+
+#define DECOMP_CHUNK 512
+
+/*
+ * Space allocation and freeing routines for use by zlib routines.
+ */
+struct zchunk {
+ u_int size;
+ u_int guard;
+};
+
+#define GUARD_MAGIC 0x77a6011a
+
+static void *
+z_alloc_init(notused, items, size)
+ void *notused;
+ u_int items, size;
+{
+ struct zchunk *z;
+
+ size = items * size + sizeof(struct zchunk);
+#ifdef __osf__
+ z = (struct zchunk *) ALLOC_SLEEP(size);
+#else
+ z = (struct zchunk *) ALLOC_NOSLEEP(size);
+#endif
+ z->size = size;
+ z->guard = GUARD_MAGIC;
+ return (void *) (z + 1);
+}
+
+static void *
+z_alloc(notused, items, size)
+ void *notused;
+ u_int items, size;
+{
+ struct zchunk *z;
+
+ size = items * size + sizeof(struct zchunk);
+ z = (struct zchunk *) ALLOC_NOSLEEP(size);
+ z->size = size;
+ z->guard = GUARD_MAGIC;
+ return (void *) (z + 1);
+}
+
+static void
+z_free(notused, ptr)
+ void *notused;
+ void *ptr;
+{
+ struct zchunk *z = ((struct zchunk *) ptr) - 1;
+
+ if (z->guard != GUARD_MAGIC) {
+ printf("ppp: z_free of corrupted chunk at %x (%x, %x)\n",
+ z, z->size, z->guard);
+ return;
+ }
+ FREE(z, z->size);
+}
+
+/*
+ * Allocate space for a compressor.
+ */
+static void *
+z_comp_alloc(options, opt_len)
+ u_char *options;
+ int opt_len;
+{
+ struct deflate_state *state;
+ int w_size;
+
+ if (opt_len != CILEN_DEFLATE
+ || (options[0] != CI_DEFLATE && options[0] != CI_DEFLATE_DRAFT)
+ || options[1] != CILEN_DEFLATE
+ || DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL
+ || options[3] != DEFLATE_CHK_SEQUENCE)
+ return NULL;
+ w_size = DEFLATE_SIZE(options[2]);
+ /*
+ * N.B. the 9 below should be DEFLATE_MIN_SIZE (8), but using
+ * 8 will cause kernel crashes because of a bug in zlib.
+ */
+ if (w_size < 9 || w_size > DEFLATE_MAX_SIZE)
+ return NULL;
+
+
+#ifdef __osf__
+ state = (struct deflate_state *) ALLOC_SLEEP(sizeof(*state));
+#else
+ state = (struct deflate_state *) ALLOC_NOSLEEP(sizeof(*state));
+#endif
+
+ if (state == NULL)
+ return NULL;
+
+ state->strm.next_in = NULL;
+ state->strm.zalloc = (alloc_func) z_alloc_init;
+ state->strm.zfree = (free_func) z_free;
+ if (deflateInit2(&state->strm, Z_DEFAULT_COMPRESSION, DEFLATE_METHOD_VAL,
+ -w_size, 8, Z_DEFAULT_STRATEGY) != Z_OK) {
+ FREE(state, sizeof(*state));
+ return NULL;
+ }
+
+ state->strm.zalloc = (alloc_func) z_alloc;
+ state->w_size = w_size;
+ bzero(&state->stats, sizeof(state->stats));
+ return (void *) state;
+}
+
+static void
+z_comp_free(arg)
+ void *arg;
+{
+ struct deflate_state *state = (struct deflate_state *) arg;
+
+ deflateEnd(&state->strm);
+ FREE(state, sizeof(*state));
+}
+
+static int
+z_comp_init(arg, options, opt_len, unit, hdrlen, debug)
+ void *arg;
+ u_char *options;
+ int opt_len, unit, hdrlen, debug;
+{
+ struct deflate_state *state = (struct deflate_state *) arg;
+
+ if (opt_len < CILEN_DEFLATE
+ || (options[0] != CI_DEFLATE && options[0] != CI_DEFLATE_DRAFT)
+ || options[1] != CILEN_DEFLATE
+ || DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL
+ || DEFLATE_SIZE(options[2]) != state->w_size
+ || options[3] != DEFLATE_CHK_SEQUENCE)
+ return 0;
+
+ state->seqno = 0;
+ state->unit = unit;
+ state->hdrlen = hdrlen;
+ state->debug = debug;
+
+ deflateReset(&state->strm);
+
+ return 1;
+}
+
+static void
+z_comp_reset(arg)
+ void *arg;
+{
+ struct deflate_state *state = (struct deflate_state *) arg;
+
+ state->seqno = 0;
+ deflateReset(&state->strm);
+}
+
+static int
+z_compress(arg, mret, mp, orig_len, maxolen)
+ void *arg;
+ mblk_t **mret; /* compressed packet (out) */
+ mblk_t *mp; /* uncompressed packet (in) */
+ int orig_len, maxolen;
+{
+ struct deflate_state *state = (struct deflate_state *) arg;
+ u_char *rptr, *wptr;
+ int proto, olen, wspace, r, flush;
+ mblk_t *m;
+
+ /*
+ * Check that the protocol is in the range we handle.
+ */
+ *mret = NULL;
+ rptr = mp->b_rptr;
+ if (rptr + PPP_HDRLEN > mp->b_wptr) {
+ if (!pullupmsg(mp, PPP_HDRLEN))
+ return 0;
+ rptr = mp->b_rptr;
+ }
+ proto = PPP_PROTOCOL(rptr);
+ if (proto > 0x3fff || proto == 0xfd || proto == 0xfb)
+ return orig_len;
+
+ /* Allocate one mblk initially. */
+ if (maxolen > orig_len)
+ maxolen = orig_len;
+ if (maxolen <= PPP_HDRLEN + 2) {
+ wspace = 0;
+ m = NULL;
+ } else {
+ wspace = maxolen + state->hdrlen;
+ if (wspace > 4096)
+ wspace = 4096;
+ m = allocb(wspace, BPRI_MED);
+ }
+ if (m != NULL) {
+ *mret = m;
+ if (state->hdrlen + PPP_HDRLEN + 2 < wspace) {
+ m->b_rptr += state->hdrlen;
+ m->b_wptr = m->b_rptr;
+ wspace -= state->hdrlen;
+ }
+ wptr = m->b_wptr;
+
+ /*
+ * Copy over the PPP header and store the 2-byte sequence number.
+ */
+ wptr[0] = PPP_ADDRESS(rptr);
+ wptr[1] = PPP_CONTROL(rptr);
+ wptr[2] = PPP_COMP >> 8;
+ wptr[3] = PPP_COMP;
+ wptr += PPP_HDRLEN;
+ wptr[0] = state->seqno >> 8;
+ wptr[1] = state->seqno;
+ wptr += 2;
+ state->strm.next_out = wptr;
+ state->strm.avail_out = wspace - (PPP_HDRLEN + 2);
+ } else {
+ state->strm.next_out = NULL;
+ state->strm.avail_out = 1000000;
+ }
+ ++state->seqno;
+
+ rptr += (proto > 0xff)? 2: 3; /* skip 1st proto byte if 0 */
+ state->strm.next_in = rptr;
+ state->strm.avail_in = mp->b_wptr - rptr;
+ mp = mp->b_cont;
+ flush = (mp == NULL)? Z_PACKET_FLUSH: Z_NO_FLUSH;
+ olen = 0;
+ for (;;) {
+ r = deflate(&state->strm, flush);
+ if (r != Z_OK) {
+ printf("z_compress: deflate returned %d (%s)\n",
+ r, (state->strm.msg? state->strm.msg: ""));
+ break;
+ }
+ if (flush != Z_NO_FLUSH && state->strm.avail_out != 0)
+ break; /* all done */
+ if (state->strm.avail_in == 0 && mp != NULL) {
+ state->strm.next_in = mp->b_rptr;
+ state->strm.avail_in = mp->b_wptr - mp->b_rptr;
+ mp = mp->b_cont;
+ if (mp == NULL)
+ flush = Z_PACKET_FLUSH;
+ }
+ if (state->strm.avail_out == 0) {
+ if (m != NULL) {
+ m->b_wptr += wspace;
+ olen += wspace;
+ wspace = maxolen - olen;
+ if (wspace <= 0) {
+ wspace = 0;
+ m->b_cont = NULL;
+ } else {
+ if (wspace < 32)
+ wspace = 32;
+ else if (wspace > 4096)
+ wspace = 4096;
+ m->b_cont = allocb(wspace, BPRI_MED);
+ }
+ m = m->b_cont;
+ if (m != NULL) {
+ state->strm.next_out = m->b_wptr;
+ state->strm.avail_out = wspace;
+ }
+ }
+ if (m == NULL) {
+ state->strm.next_out = NULL;
+ state->strm.avail_out = 1000000;
+ }
+ }
+ }
+ if (m != NULL) {
+ m->b_wptr += wspace - state->strm.avail_out;
+ olen += wspace - state->strm.avail_out;
+ }
+
+ /*
+ * See if we managed to reduce the size of the packet.
+ */
+ if (olen < orig_len && m != NULL) {
+ state->stats.comp_bytes += olen;
+ state->stats.comp_packets++;
+ } else {
+ if (*mret != NULL) {
+ freemsg(*mret);
+ *mret = NULL;
+ }
+ state->stats.inc_bytes += orig_len;
+ state->stats.inc_packets++;
+ olen = orig_len;
+ }
+ state->stats.unc_bytes += orig_len;
+ state->stats.unc_packets++;
+
+ return olen;
+}
+
+static void
+z_comp_stats(arg, stats)
+ void *arg;
+ struct compstat *stats;
+{
+ struct deflate_state *state = (struct deflate_state *) arg;
+ u_int out;
+
+ *stats = state->stats;
+ stats->ratio = stats->unc_bytes;
+ out = stats->comp_bytes + stats->unc_bytes;
+ if (stats->ratio <= 0x7ffffff)
+ stats->ratio <<= 8;
+ else
+ out >>= 8;
+ if (out != 0)
+ stats->ratio /= out;
+}
+
+/*
+ * Allocate space for a decompressor.
+ */
+static void *
+z_decomp_alloc(options, opt_len)
+ u_char *options;
+ int opt_len;
+{
+ struct deflate_state *state;
+ int w_size;
+
+ if (opt_len != CILEN_DEFLATE
+ || (options[0] != CI_DEFLATE && options[0] != CI_DEFLATE_DRAFT)
+ || options[1] != CILEN_DEFLATE
+ || DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL
+ || options[3] != DEFLATE_CHK_SEQUENCE)
+ return NULL;
+ w_size = DEFLATE_SIZE(options[2]);
+ /*
+ * N.B. the 9 below should be DEFLATE_MIN_SIZE (8), but using
+ * 8 will cause kernel crashes because of a bug in zlib.
+ */
+ if (w_size < 9 || w_size > DEFLATE_MAX_SIZE)
+ return NULL;
+
+#ifdef __osf__
+ state = (struct deflate_state *) ALLOC_SLEEP(sizeof(*state));
+#else
+ state = (struct deflate_state *) ALLOC_NOSLEEP(sizeof(*state));
+#endif
+ if (state == NULL)
+ return NULL;
+
+ state->strm.next_out = NULL;
+ state->strm.zalloc = (alloc_func) z_alloc_init;
+ state->strm.zfree = (free_func) z_free;
+ if (inflateInit2(&state->strm, -w_size) != Z_OK) {
+ FREE(state, sizeof(*state));
+ return NULL;
+ }
+
+ state->strm.zalloc = (alloc_func) z_alloc;
+ state->w_size = w_size;
+ bzero(&state->stats, sizeof(state->stats));
+ return (void *) state;
+}
+
+static void
+z_decomp_free(arg)
+ void *arg;
+{
+ struct deflate_state *state = (struct deflate_state *) arg;
+
+ inflateEnd(&state->strm);
+ FREE(state, sizeof(*state));
+}
+
+static int
+z_decomp_init(arg, options, opt_len, unit, hdrlen, mru, debug)
+ void *arg;
+ u_char *options;
+ int opt_len, unit, hdrlen, mru, debug;
+{
+ struct deflate_state *state = (struct deflate_state *) arg;
+
+ if (opt_len < CILEN_DEFLATE
+ || (options[0] != CI_DEFLATE && options[0] != CI_DEFLATE_DRAFT)
+ || options[1] != CILEN_DEFLATE
+ || DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL
+ || DEFLATE_SIZE(options[2]) != state->w_size
+ || options[3] != DEFLATE_CHK_SEQUENCE)
+ return 0;
+
+ state->seqno = 0;
+ state->unit = unit;
+ state->hdrlen = hdrlen;
+ state->debug = debug;
+ state->mru = mru;
+
+ inflateReset(&state->strm);
+
+ return 1;
+}
+
+static void
+z_decomp_reset(arg)
+ void *arg;
+{
+ struct deflate_state *state = (struct deflate_state *) arg;
+
+ state->seqno = 0;
+ inflateReset(&state->strm);
+}
+
+/*
+ * Decompress a Deflate-compressed packet.
+ *
+ * Because of patent problems, we return DECOMP_ERROR for errors
+ * found by inspecting the input data and for system problems, but
+ * DECOMP_FATALERROR for any errors which could possibly be said to
+ * be being detected "after" decompression. For DECOMP_ERROR,
+ * we can issue a CCP reset-request; for DECOMP_FATALERROR, we may be
+ * infringing a patent of Motorola's if we do, so we take CCP down
+ * instead.
+ *
+ * Given that the frame has the correct sequence number and a good FCS,
+ * errors such as invalid codes in the input most likely indicate a
+ * bug, so we return DECOMP_FATALERROR for them in order to turn off
+ * compression, even though they are detected by inspecting the input.
+ */
+static int
+z_decompress(arg, mi, mop)
+ void *arg;
+ mblk_t *mi, **mop;
+{
+ struct deflate_state *state = (struct deflate_state *) arg;
+ mblk_t *mo, *mo_head;
+ u_char *rptr, *wptr;
+ int rlen, olen, ospace;
+ int seq, i, flush, r, decode_proto;
+ u_char hdr[PPP_HDRLEN + DEFLATE_OVHD];
+
+ *mop = NULL;
+ rptr = mi->b_rptr;
+ for (i = 0; i < PPP_HDRLEN + DEFLATE_OVHD; ++i) {
+ while (rptr >= mi->b_wptr) {
+ mi = mi->b_cont;
+ if (mi == NULL)
+ return DECOMP_ERROR;
+ rptr = mi->b_rptr;
+ }
+ hdr[i] = *rptr++;
+ }
+
+ /* Check the sequence number. */
+ seq = (hdr[PPP_HDRLEN] << 8) + hdr[PPP_HDRLEN+1];
+ if (seq != state->seqno) {
+#if !DEFLATE_DEBUG
+ if (state->debug)
+#endif
+ printf("z_decompress%d: bad seq # %d, expected %d\n",
+ state->unit, seq, state->seqno);
+ return DECOMP_ERROR;
+ }
+ ++state->seqno;
+
+ /* Allocate an output message block. */
+ mo = allocb(DECOMP_CHUNK + state->hdrlen, BPRI_MED);
+ if (mo == NULL)
+ return DECOMP_ERROR;
+ mo_head = mo;
+ mo->b_cont = NULL;
+ mo->b_rptr += state->hdrlen;
+ mo->b_wptr = wptr = mo->b_rptr;
+ ospace = DECOMP_CHUNK;
+ olen = 0;
+
+ /*
+ * Fill in the first part of the PPP header. The protocol field
+ * comes from the decompressed data.
+ */
+ wptr[0] = PPP_ADDRESS(hdr);
+ wptr[1] = PPP_CONTROL(hdr);
+ wptr[2] = 0;
+
+ /*
+ * Set up to call inflate. We set avail_out to 1 initially so we can
+ * look at the first byte of the output and decide whether we have
+ * a 1-byte or 2-byte protocol field.
+ */
+ state->strm.next_in = rptr;
+ state->strm.avail_in = mi->b_wptr - rptr;
+ mi = mi->b_cont;
+ flush = (mi == NULL)? Z_PACKET_FLUSH: Z_NO_FLUSH;
+ rlen = state->strm.avail_in + PPP_HDRLEN + DEFLATE_OVHD;
+ state->strm.next_out = wptr + 3;
+ state->strm.avail_out = 1;
+ decode_proto = 1;
+
+ /*
+ * Call inflate, supplying more input or output as needed.
+ */
+ for (;;) {
+ r = inflate(&state->strm, flush);
+ if (r != Z_OK) {
+#if !DEFLATE_DEBUG
+ if (state->debug)
+#endif
+ printf("z_decompress%d: inflate returned %d (%s)\n",
+ state->unit, r, (state->strm.msg? state->strm.msg: ""));
+ freemsg(mo_head);
+ return DECOMP_FATALERROR;
+ }
+ if (flush != Z_NO_FLUSH && state->strm.avail_out != 0)
+ break; /* all done */
+ if (state->strm.avail_in == 0 && mi != NULL) {
+ state->strm.next_in = mi->b_rptr;
+ state->strm.avail_in = mi->b_wptr - mi->b_rptr;
+ rlen += state->strm.avail_in;
+ mi = mi->b_cont;
+ if (mi == NULL)
+ flush = Z_PACKET_FLUSH;
+ }
+ if (state->strm.avail_out == 0) {
+ if (decode_proto) {
+ state->strm.avail_out = ospace - PPP_HDRLEN;
+ if ((wptr[3] & 1) == 0) {
+ /* 2-byte protocol field */
+ wptr[2] = wptr[3];
+ --state->strm.next_out;
+ ++state->strm.avail_out;
+ }
+ decode_proto = 0;
+ } else {
+ mo->b_wptr += ospace;
+ olen += ospace;
+ mo->b_cont = allocb(DECOMP_CHUNK, BPRI_MED);
+ mo = mo->b_cont;
+ if (mo == NULL) {
+ freemsg(mo_head);
+ return DECOMP_ERROR;
+ }
+ state->strm.next_out = mo->b_rptr;
+ state->strm.avail_out = ospace = DECOMP_CHUNK;
+ }
+ }
+ }
+ if (decode_proto) {
+ freemsg(mo_head);
+ return DECOMP_ERROR;
+ }
+ mo->b_wptr += ospace - state->strm.avail_out;
+ olen += ospace - state->strm.avail_out;
+
+#if DEFLATE_DEBUG
+ if (olen > state->mru + PPP_HDRLEN)
+ printf("ppp_deflate%d: exceeded mru (%d > %d)\n",
+ state->unit, olen, state->mru + PPP_HDRLEN);
+#endif
+
+ state->stats.unc_bytes += olen;
+ state->stats.unc_packets++;
+ state->stats.comp_bytes += rlen;
+ state->stats.comp_packets++;
+
+ *mop = mo_head;
+ return DECOMP_OK;
+}
+
+/*
+ * Incompressible data has arrived - add it to the history.
+ */
+static void
+z_incomp(arg, mi)
+ void *arg;
+ mblk_t *mi;
+{
+ struct deflate_state *state = (struct deflate_state *) arg;
+ u_char *rptr;
+ int rlen, proto, r;
+
+ /*
+ * Check that the protocol is one we handle.
+ */
+ rptr = mi->b_rptr;
+ if (rptr + PPP_HDRLEN > mi->b_wptr) {
+ if (!pullupmsg(mi, PPP_HDRLEN))
+ return;
+ rptr = mi->b_rptr;
+ }
+ proto = PPP_PROTOCOL(rptr);
+ if (proto > 0x3fff || proto == 0xfd || proto == 0xfb)
+ return;
+
+ ++state->seqno;
+
+ /*
+ * Iterate through the message blocks, adding the characters in them
+ * to the decompressor's history. For the first block, we start
+ * at the either the 1st or 2nd byte of the protocol field,
+ * depending on whether the protocol value is compressible.
+ */
+ rlen = mi->b_wptr - mi->b_rptr;
+ state->strm.next_in = rptr + 3;
+ state->strm.avail_in = rlen - 3;
+ if (proto > 0xff) {
+ --state->strm.next_in;
+ ++state->strm.avail_in;
+ }
+ for (;;) {
+ r = inflateIncomp(&state->strm);
+ if (r != Z_OK) {
+ /* gak! */
+#if !DEFLATE_DEBUG
+ if (state->debug)
+#endif
+ printf("z_incomp%d: inflateIncomp returned %d (%s)\n",
+ state->unit, r, (state->strm.msg? state->strm.msg: ""));
+ return;
+ }
+ mi = mi->b_cont;
+ if (mi == NULL)
+ break;
+ state->strm.next_in = mi->b_rptr;
+ state->strm.avail_in = mi->b_wptr - mi->b_rptr;
+ rlen += state->strm.avail_in;
+ }
+
+ /*
+ * Update stats.
+ */
+ state->stats.inc_bytes += rlen;
+ state->stats.inc_packets++;
+ state->stats.unc_bytes += rlen;
+ state->stats.unc_packets++;
+}
+
+#endif /* DO_DEFLATE */
diff --git a/mdk-stage1/ppp/modules/if_ppp.c b/mdk-stage1/ppp/modules/if_ppp.c
new file mode 100644
index 000000000..9792708d1
--- /dev/null
+++ b/mdk-stage1/ppp/modules/if_ppp.c
@@ -0,0 +1,865 @@
+/*
+ * if_ppp.c - a network interface connected to a STREAMS module.
+ *
+ * Copyright (c) 1994 The Australian National University.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation is hereby granted, provided that the above copyright
+ * notice appears in all copies. This software is provided without any
+ * warranty, express or implied. The Australian National University
+ * makes no representations about the suitability of this software for
+ * any purpose.
+ *
+ * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
+ * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
+ * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
+ * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
+ * OR MODIFICATIONS.
+ *
+ * $Id: if_ppp.c 195720 2001-06-11 11:44:34Z gc $
+ */
+
+/*
+ * This file is used under SunOS 4 and Digital UNIX.
+ *
+ * This file provides the glue between PPP and IP.
+ */
+
+#define INET 1
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/errno.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <net/netisr.h>
+#include <net/ppp_defs.h>
+#include <net/pppio.h>
+#include <netinet/in.h>
+#include <netinet/in_var.h>
+#ifdef __osf__
+#include <sys/ioctl.h>
+#include <net/if_types.h>
+#else
+#include <sys/sockio.h>
+#endif
+#include "ppp_mod.h"
+
+#include <sys/stream.h>
+
+#ifdef SNIT_SUPPORT
+#include <sys/time.h>
+#include <net/nit_if.h>
+#include <netinet/if_ether.h>
+#endif
+
+#ifdef __osf__
+#define SIOCSIFMTU SIOCSIPMTU
+#define SIOCGIFMTU SIOCRIPMTU
+#define IFA_ADDR(ifa) (*(ifa)->ifa_addr)
+#else
+#define IFA_ADDR(ifa) ((ifa)->ifa_addr)
+#endif
+
+#define ifr_mtu ifr_metric
+
+static int if_ppp_open __P((queue_t *, int, int, int));
+static int if_ppp_close __P((queue_t *, int));
+static int if_ppp_wput __P((queue_t *, mblk_t *));
+static int if_ppp_rput __P((queue_t *, mblk_t *));
+
+#define PPP_IF_ID 0x8021
+static struct module_info minfo = {
+ PPP_IF_ID, "if_ppp", 0, INFPSZ, 4096, 128
+};
+
+static struct qinit rinit = {
+ if_ppp_rput, NULL, if_ppp_open, if_ppp_close, NULL, &minfo, NULL
+};
+
+static struct qinit winit = {
+ if_ppp_wput, NULL, NULL, NULL, NULL, &minfo, NULL
+};
+
+struct streamtab if_pppinfo = {
+ &rinit, &winit, NULL, NULL
+};
+
+typedef struct if_ppp_state {
+ int unit;
+ queue_t *q;
+ int flags;
+} if_ppp_t;
+
+/* Values for flags */
+#define DBGLOG 1
+
+static int if_ppp_count; /* Number of currently-active streams */
+
+static int ppp_nalloc; /* Number of elements of ifs and states */
+static struct ifnet **ifs; /* Array of pointers to interface structs */
+static if_ppp_t **states; /* Array of pointers to state structs */
+
+static int if_ppp_output __P((struct ifnet *, struct mbuf *,
+ struct sockaddr *));
+static int if_ppp_ioctl __P((struct ifnet *, u_int, caddr_t));
+static struct mbuf *make_mbufs __P((mblk_t *, int));
+static mblk_t *make_message __P((struct mbuf *, int));
+
+#ifdef SNIT_SUPPORT
+/* Fake ether header for SNIT */
+static struct ether_header snit_ehdr = {{0}, {0}, ETHERTYPE_IP};
+#endif
+
+#ifndef __osf__
+static void ppp_if_detach __P((struct ifnet *));
+
+/*
+ * Detach all the interfaces before unloading.
+ * Not sure this works.
+ */
+int
+if_ppp_unload()
+{
+ int i;
+
+ if (if_ppp_count > 0)
+ return EBUSY;
+ for (i = 0; i < ppp_nalloc; ++i)
+ if (ifs[i] != 0)
+ ppp_if_detach(ifs[i]);
+ if (ifs) {
+ FREE(ifs, ppp_nalloc * sizeof (struct ifnet *));
+ FREE(states, ppp_nalloc * sizeof (struct if_ppp_t *));
+ }
+ ppp_nalloc = 0;
+ return 0;
+}
+#endif /* __osf__ */
+
+/*
+ * STREAMS module entry points.
+ */
+static int
+if_ppp_open(q, dev, flag, sflag)
+ queue_t *q;
+ int dev;
+ int flag, sflag;
+{
+ if_ppp_t *sp;
+
+ if (q->q_ptr == 0) {
+ sp = (if_ppp_t *) ALLOC_SLEEP(sizeof (if_ppp_t));
+ if (sp == 0)
+ return OPENFAIL;
+ bzero(sp, sizeof (if_ppp_t));
+ q->q_ptr = (caddr_t) sp;
+ WR(q)->q_ptr = (caddr_t) sp;
+ sp->unit = -1; /* no interface unit attached at present */
+ sp->q = WR(q);
+ sp->flags = 0;
+ ++if_ppp_count;
+ }
+ return 0;
+}
+
+static int
+if_ppp_close(q, flag)
+ queue_t *q;
+ int flag;
+{
+ if_ppp_t *sp;
+ struct ifnet *ifp;
+
+ sp = (if_ppp_t *) q->q_ptr;
+ if (sp != 0) {
+ if (sp->flags & DBGLOG)
+ printf("if_ppp closed, q=%x sp=%x\n", q, sp);
+ if (sp->unit >= 0) {
+ if (sp->unit < ppp_nalloc) {
+ states[sp->unit] = 0;
+ ifp = ifs[sp->unit];
+ if (ifp != 0)
+ ifp->if_flags &= ~(IFF_UP | IFF_RUNNING);
+#ifdef DEBUG
+ } else {
+ printf("if_ppp: unit %d nonexistent!\n", sp->unit);
+#endif
+ }
+ }
+ FREE(sp, sizeof (if_ppp_t));
+ --if_ppp_count;
+ }
+ return 0;
+}
+
+static int
+if_ppp_wput(q, mp)
+ queue_t *q;
+ mblk_t *mp;
+{
+ if_ppp_t *sp;
+ struct iocblk *iop;
+ int error, unit;
+ struct ifnet *ifp;
+
+ sp = (if_ppp_t *) q->q_ptr;
+ switch (mp->b_datap->db_type) {
+ case M_DATA:
+ /*
+ * Now why would we be getting data coming in here??
+ */
+ if (sp->flags & DBGLOG)
+ printf("if_ppp: got M_DATA len=%d\n", msgdsize(mp));
+ freemsg(mp);
+ break;
+
+ case M_IOCTL:
+ iop = (struct iocblk *) mp->b_rptr;
+ error = EINVAL;
+
+ if (sp->flags & DBGLOG)
+ printf("if_ppp: got ioctl cmd=%x count=%d\n",
+ iop->ioc_cmd, iop->ioc_count);
+
+ switch (iop->ioc_cmd) {
+ case PPPIO_NEWPPA: /* well almost */
+ if (iop->ioc_count != sizeof(int) || sp->unit >= 0)
+ break;
+ if ((error = NOTSUSER()) != 0)
+ break;
+ unit = *(int *)mp->b_cont->b_rptr;
+
+ /* Check that this unit isn't already in use */
+ if (unit < ppp_nalloc && states[unit] != 0) {
+ error = EADDRINUSE;
+ break;
+ }
+
+ /* Extend ifs and states arrays if necessary. */
+ error = ENOSR;
+ if (unit >= ppp_nalloc) {
+ int newn;
+ struct ifnet **newifs;
+ if_ppp_t **newstates;
+
+ newn = unit + 4;
+ if (sp->flags & DBGLOG)
+ printf("if_ppp: extending ifs to %d\n", newn);
+ newifs = (struct ifnet **)
+ ALLOC_NOSLEEP(newn * sizeof (struct ifnet *));
+ if (newifs == 0)
+ break;
+ bzero(newifs, newn * sizeof (struct ifnet *));
+ newstates = (if_ppp_t **)
+ ALLOC_NOSLEEP(newn * sizeof (struct if_ppp_t *));
+ if (newstates == 0) {
+ FREE(newifs, newn * sizeof (struct ifnet *));
+ break;
+ }
+ bzero(newstates, newn * sizeof (struct if_ppp_t *));
+ bcopy(ifs, newifs, ppp_nalloc * sizeof(struct ifnet *));
+ bcopy(states, newstates, ppp_nalloc * sizeof(if_ppp_t *));
+ if (ifs) {
+ FREE(ifs, ppp_nalloc * sizeof(struct ifnet *));
+ FREE(states, ppp_nalloc * sizeof(if_ppp_t *));
+ }
+ ifs = newifs;
+ states = newstates;
+ ppp_nalloc = newn;
+ }
+
+ /* Allocate a new ifnet struct if necessary. */
+ ifp = ifs[unit];
+ if (ifp == 0) {
+ ifp = (struct ifnet *) ALLOC_NOSLEEP(sizeof (struct ifnet));
+ if (ifp == 0)
+ break;
+ bzero(ifp, sizeof (struct ifnet));
+ ifs[unit] = ifp;
+ ifp->if_name = "ppp";
+ ifp->if_unit = unit;
+ ifp->if_mtu = PPP_MTU;
+ ifp->if_flags = IFF_POINTOPOINT | IFF_RUNNING;
+#ifndef __osf__
+#ifdef IFF_MULTICAST
+ ifp->if_flags |= IFF_MULTICAST;
+#endif
+#endif /* __osf__ */
+ ifp->if_output = if_ppp_output;
+#ifdef __osf__
+ ifp->if_version = "Point-to-Point Protocol, version 2.3.11";
+ ifp->if_mediamtu = PPP_MTU;
+ ifp->if_type = IFT_PPP;
+ ifp->if_hdrlen = PPP_HDRLEN;
+ ifp->if_addrlen = 0;
+ ifp->if_flags |= IFF_NOARP | IFF_SIMPLEX | IFF_NOTRAILERS;
+#ifdef IFF_VAR_MTU
+ ifp->if_flags |= IFF_VAR_MTU;
+#endif
+#ifdef NETMASTERCPU
+ ifp->if_affinity = NETMASTERCPU;
+#endif
+#endif
+ ifp->if_ioctl = if_ppp_ioctl;
+ ifp->if_snd.ifq_maxlen = IFQ_MAXLEN;
+ if_attach(ifp);
+ if (sp->flags & DBGLOG)
+ printf("if_ppp: created unit %d\n", unit);
+ } else {
+ ifp->if_mtu = PPP_MTU;
+ ifp->if_flags |= IFF_RUNNING;
+ }
+
+ states[unit] = sp;
+ sp->unit = unit;
+
+ error = 0;
+ iop->ioc_count = 0;
+ if (sp->flags & DBGLOG)
+ printf("if_ppp: attached unit %d, sp=%x q=%x\n", unit,
+ sp, sp->q);
+ break;
+
+ case PPPIO_DEBUG:
+ error = -1;
+ if (iop->ioc_count == sizeof(int)) {
+ if (*(int *)mp->b_cont->b_rptr == PPPDBG_LOG + PPPDBG_IF) {
+ printf("if_ppp: debug log enabled, q=%x sp=%x\n", q, sp);
+ sp->flags |= DBGLOG;
+ error = 0;
+ iop->ioc_count = 0;
+ }
+ }
+ break;
+
+ default:
+ error = -1;
+ break;
+ }
+
+ if (sp->flags & DBGLOG)
+ printf("if_ppp: ioctl result %d\n", error);
+ if (error < 0)
+ putnext(q, mp);
+ else if (error == 0) {
+ mp->b_datap->db_type = M_IOCACK;
+ qreply(q, mp);
+ } else {
+ mp->b_datap->db_type = M_IOCNAK;
+ iop->ioc_count = 0;
+ iop->ioc_error = error;
+ qreply(q, mp);
+ }
+ break;
+
+ default:
+ putnext(q, mp);
+ }
+ return 0;
+}
+
+static int
+if_ppp_rput(q, mp)
+ queue_t *q;
+ mblk_t *mp;
+{
+ if_ppp_t *sp;
+ int proto, s;
+ struct mbuf *mb;
+ struct ifqueue *inq;
+ struct ifnet *ifp;
+ int len;
+
+ sp = (if_ppp_t *) q->q_ptr;
+ switch (mp->b_datap->db_type) {
+ case M_DATA:
+ /*
+ * Convert the message into an mbuf chain
+ * and inject it into the network code.
+ */
+ if (sp->flags & DBGLOG)
+ printf("if_ppp: rput pkt len %d data %x %x %x %x %x %x %x %x\n",
+ msgdsize(mp), mp->b_rptr[0], mp->b_rptr[1], mp->b_rptr[2],
+ mp->b_rptr[3], mp->b_rptr[4], mp->b_rptr[5], mp->b_rptr[6],
+ mp->b_rptr[7]);
+
+ if (sp->unit < 0) {
+ freemsg(mp);
+ break;
+ }
+ if (sp->unit >= ppp_nalloc || (ifp = ifs[sp->unit]) == 0) {
+#ifdef DEBUG
+ printf("if_ppp: no unit %d!\n", sp->unit);
+#endif
+ freemsg(mp);
+ break;
+ }
+
+ if ((ifp->if_flags & IFF_UP) == 0) {
+ freemsg(mp);
+ break;
+ }
+ ++ifp->if_ipackets;
+
+ proto = PPP_PROTOCOL(mp->b_rptr);
+ adjmsg(mp, PPP_HDRLEN);
+ len = msgdsize(mp);
+ mb = make_mbufs(mp, sizeof(struct ifnet *));
+ freemsg(mp);
+ if (mb == NULL) {
+ if (sp->flags & DBGLOG)
+ printf("if_ppp%d: make_mbufs failed\n", ifp->if_unit);
+ ++ifp->if_ierrors;
+ break;
+ }
+
+#ifdef SNIT_SUPPORT
+ if (proto == PPP_IP && (ifp->if_flags & IFF_PROMISC)) {
+ struct nit_if nif;
+
+ nif.nif_header = (caddr_t) &snit_ehdr;
+ nif.nif_hdrlen = sizeof(snit_ehdr);
+ nif.nif_bodylen = len;
+ nif.nif_promisc = 0;
+ snit_intr(ifp, mb, &nif);
+ }
+#endif
+
+/*
+ * For Digital UNIX, there's space set aside in the header mbuf
+ * for the interface info.
+ *
+ * For Sun it's smuggled around via a pointer at the front of the mbuf.
+ */
+#ifdef __osf__
+ mb->m_pkthdr.rcvif = ifp;
+ mb->m_pkthdr.len = len;
+#else
+ mb->m_off -= sizeof(struct ifnet *);
+ mb->m_len += sizeof(struct ifnet *);
+ *mtod(mb, struct ifnet **) = ifp;
+#endif
+
+ inq = 0;
+ switch (proto) {
+ case PPP_IP:
+ inq = &ipintrq;
+ schednetisr(NETISR_IP);
+ }
+
+ if (inq != 0) {
+ s = splhigh();
+ if (IF_QFULL(inq)) {
+ IF_DROP(inq);
+ ++ifp->if_ierrors;
+ if (sp->flags & DBGLOG)
+ printf("if_ppp: inq full, proto=%x\n", proto);
+ m_freem(mb);
+ } else {
+ IF_ENQUEUE(inq, mb);
+ }
+ splx(s);
+ } else {
+ if (sp->flags & DBGLOG)
+ printf("if_ppp%d: proto=%x?\n", ifp->if_unit, proto);
+ ++ifp->if_ierrors;
+ m_freem(mb);
+ }
+ break;
+
+ default:
+ putnext(q, mp);
+ }
+ return 0;
+}
+
+/*
+ * Network code wants to output a packet.
+ * Turn it into a STREAMS message and send it down.
+ */
+static int
+if_ppp_output(ifp, m0, dst)
+ struct ifnet *ifp;
+ struct mbuf *m0;
+ struct sockaddr *dst;
+{
+ mblk_t *mp;
+ int proto, s;
+ if_ppp_t *sp;
+ u_char *p;
+
+ if ((ifp->if_flags & IFF_UP) == 0) {
+ m_freem(m0);
+ return ENETDOWN;
+ }
+
+ if ((unsigned)ifp->if_unit >= ppp_nalloc) {
+#ifdef DEBUG
+ printf("if_ppp_output: unit %d?\n", ifp->if_unit);
+#endif
+ m_freem(m0);
+ return EINVAL;
+ }
+ sp = states[ifp->if_unit];
+ if (sp == 0) {
+#ifdef DEBUG
+ printf("if_ppp_output: no queue?\n");
+#endif
+ m_freem(m0);
+ return ENETDOWN;
+ }
+
+ if (sp->flags & DBGLOG) {
+ p = mtod(m0, u_char *);
+ printf("if_ppp_output%d: af=%d data=%x %x %x %x %x %x %x %x q=%x\n",
+ ifp->if_unit, dst->sa_family, p[0], p[1], p[2], p[3], p[4],
+ p[5], p[6], p[7], sp->q);
+ }
+
+ switch (dst->sa_family) {
+ case AF_INET:
+ proto = PPP_IP;
+#ifdef SNIT_SUPPORT
+ if (ifp->if_flags & IFF_PROMISC) {
+ struct nit_if nif;
+ struct mbuf *m;
+ int len;
+
+ for (len = 0, m = m0; m != NULL; m = m->m_next)
+ len += m->m_len;
+ nif.nif_header = (caddr_t) &snit_ehdr;
+ nif.nif_hdrlen = sizeof(snit_ehdr);
+ nif.nif_bodylen = len;
+ nif.nif_promisc = 0;
+ snit_intr(ifp, m0, &nif);
+ }
+#endif
+ break;
+
+ default:
+ m_freem(m0);
+ return EAFNOSUPPORT;
+ }
+
+ ++ifp->if_opackets;
+ mp = make_message(m0, PPP_HDRLEN);
+ m_freem(m0);
+ if (mp == 0) {
+ ++ifp->if_oerrors;
+ return ENOBUFS;
+ }
+ mp->b_rptr -= PPP_HDRLEN;
+ mp->b_rptr[0] = PPP_ALLSTATIONS;
+ mp->b_rptr[1] = PPP_UI;
+ mp->b_rptr[2] = proto >> 8;
+ mp->b_rptr[3] = proto;
+
+ s = splstr();
+ if (sp->flags & DBGLOG)
+ printf("if_ppp: putnext(%x, %x), r=%x w=%x p=%x\n",
+ sp->q, mp, mp->b_rptr, mp->b_wptr, proto);
+ putnext(sp->q, mp);
+ splx(s);
+
+ return 0;
+}
+
+/*
+ * Socket ioctl routine for ppp interfaces.
+ */
+static int
+if_ppp_ioctl(ifp, cmd, data)
+ struct ifnet *ifp;
+ u_int cmd;
+ caddr_t data;
+{
+ int s, error;
+ struct ifreq *ifr = (struct ifreq *) data;
+ struct ifaddr *ifa = (struct ifaddr *) data;
+ u_short mtu;
+
+ error = 0;
+ s = splimp();
+ switch (cmd) {
+ case SIOCSIFFLAGS:
+ if ((ifp->if_flags & IFF_RUNNING) == 0)
+ ifp->if_flags &= ~IFF_UP;
+ break;
+
+ case SIOCSIFADDR:
+ if (IFA_ADDR(ifa).sa_family != AF_INET)
+ error = EAFNOSUPPORT;
+ break;
+
+ case SIOCSIFDSTADDR:
+ if (IFA_ADDR(ifa).sa_family != AF_INET)
+ error = EAFNOSUPPORT;
+ break;
+
+ case SIOCSIFMTU:
+ if ((error = NOTSUSER()) != 0)
+ break;
+#ifdef __osf__
+ /* this hack is necessary because ifioctl checks ifr_data
+ * in 4.0 and 5.0, but ifr_data and ifr_metric overlay each
+ * other in the definition of struct ifreq so pppd can't set both.
+ */
+ bcopy(ifr->ifr_data, &mtu, sizeof (u_short));
+ ifr->ifr_mtu = mtu;
+#endif
+
+ if (ifr->ifr_mtu < PPP_MINMTU || ifr->ifr_mtu > PPP_MAXMTU) {
+ error = EINVAL;
+ break;
+ }
+ ifp->if_mtu = ifr->ifr_mtu;
+ break;
+
+ case SIOCGIFMTU:
+ ifr->ifr_mtu = ifp->if_mtu;
+ break;
+
+ case SIOCADDMULTI:
+ case SIOCDELMULTI:
+ switch(ifr->ifr_addr.sa_family) {
+ case AF_INET:
+ break;
+ default:
+ error = EAFNOSUPPORT;
+ break;
+ }
+ break;
+
+ default:
+ error = EINVAL;
+ }
+ splx(s);
+ return (error);
+}
+
+/*
+ * Turn a STREAMS message into an mbuf chain.
+ */
+static struct mbuf *
+make_mbufs(mp, off)
+ mblk_t *mp;
+ int off;
+{
+ struct mbuf *head, **prevp, *m;
+ int len, space, n;
+ unsigned char *cp, *dp;
+
+ len = msgdsize(mp);
+ if (len == 0)
+ return 0;
+ prevp = &head;
+ space = 0;
+ cp = mp->b_rptr;
+#ifdef __osf__
+ MGETHDR(m, M_DONTWAIT, MT_DATA);
+ m->m_len = 0;
+ space = MHLEN;
+ *prevp = m;
+ prevp = &m->m_next;
+ dp = mtod(m, unsigned char *);
+ len -= space;
+ off = 0;
+#endif
+ for (;;) {
+ while (cp >= mp->b_wptr) {
+ mp = mp->b_cont;
+ if (mp == 0) {
+ *prevp = 0;
+ return head;
+ }
+ cp = mp->b_rptr;
+ }
+ n = mp->b_wptr - cp;
+ if (space == 0) {
+ MGET(m, M_DONTWAIT, MT_DATA);
+ *prevp = m;
+ if (m == 0) {
+ if (head != 0)
+ m_freem(head);
+ return 0;
+ }
+ if (len + off > 2 * MLEN) {
+#ifdef __osf__
+ MCLGET(m, M_DONTWAIT);
+#else
+ MCLGET(m);
+#endif
+ }
+#ifdef __osf__
+ space = ((m->m_flags & M_EXT) ? MCLBYTES : MLEN);
+#else
+ space = (m->m_off > MMAXOFF? MCLBYTES: MLEN) - off;
+ m->m_off += off;
+#endif
+ m->m_len = 0;
+ len -= space;
+ dp = mtod(m, unsigned char *);
+ off = 0;
+ prevp = &m->m_next;
+ }
+ if (n > space)
+ n = space;
+ bcopy(cp, dp, n);
+ cp += n;
+ dp += n;
+ space -= n;
+ m->m_len += n;
+ }
+}
+
+/*
+ * Turn an mbuf chain into a STREAMS message.
+ */
+#define ALLOCB_MAX 4096
+
+static mblk_t *
+make_message(m, off)
+ struct mbuf *m;
+ int off;
+{
+ mblk_t *head, **prevp, *mp;
+ int len, space, n, nb;
+ unsigned char *cp, *dp;
+ struct mbuf *nm;
+
+ len = 0;
+ for (nm = m; nm != 0; nm = nm->m_next)
+ len += nm->m_len;
+ prevp = &head;
+ space = 0;
+ cp = mtod(m, unsigned char *);
+ nb = m->m_len;
+ for (;;) {
+ while (nb <= 0) {
+ m = m->m_next;
+ if (m == 0) {
+ *prevp = 0;
+ return head;
+ }
+ cp = mtod(m, unsigned char *);
+ nb = m->m_len;
+ }
+ if (space == 0) {
+ space = len + off;
+ if (space > ALLOCB_MAX)
+ space = ALLOCB_MAX;
+ mp = allocb(space, BPRI_LO);
+ *prevp = mp;
+ if (mp == 0) {
+ if (head != 0)
+ freemsg(head);
+ return 0;
+ }
+ dp = mp->b_rptr += off;
+ space -= off;
+ len -= space;
+ off = 0;
+ prevp = &mp->b_cont;
+ }
+ n = nb < space? nb: space;
+ bcopy(cp, dp, n);
+ cp += n;
+ dp += n;
+ nb -= n;
+ space -= n;
+ mp->b_wptr = dp;
+ }
+}
+
+/*
+ * Digital UNIX doesn't allow for removing ifnet structures
+ * from the list. But then we're not using this as a loadable
+ * module anyway, so that's OK.
+ *
+ * Under SunOS, this should allow the module to be unloaded.
+ * Unfortunately, it doesn't seem to detach all the references,
+ * so your system may well crash after you unload this module :-(
+ */
+#ifndef __osf__
+
+/*
+ * Remove an interface from the system.
+ * This routine contains magic.
+ */
+#include <net/route.h>
+#include <netinet/in_pcb.h>
+#include <netinet/ip_var.h>
+#include <netinet/tcp.h>
+#include <netinet/tcp_timer.h>
+#include <netinet/tcp_var.h>
+#include <netinet/udp.h>
+#include <netinet/udp_var.h>
+
+static void
+ppp_if_detach(ifp)
+ struct ifnet *ifp;
+{
+ int s;
+ struct inpcb *pcb;
+ struct ifaddr *ifa;
+ struct in_ifaddr **inap;
+ struct ifnet **ifpp;
+
+ s = splhigh();
+
+ /*
+ * Clear the interface from any routes currently cached in
+ * TCP or UDP protocol control blocks.
+ */
+ for (pcb = tcb.inp_next; pcb != &tcb; pcb = pcb->inp_next)
+ if (pcb->inp_route.ro_rt && pcb->inp_route.ro_rt->rt_ifp == ifp)
+ in_losing(pcb);
+ for (pcb = udb.inp_next; pcb != &udb; pcb = pcb->inp_next)
+ if (pcb->inp_route.ro_rt && pcb->inp_route.ro_rt->rt_ifp == ifp)
+ in_losing(pcb);
+
+ /*
+ * Delete routes through all addresses of the interface.
+ */
+ for (ifa = ifp->if_addrlist; ifa != 0; ifa = ifa->ifa_next) {
+ rtinit(ifa, ifa, SIOCDELRT, RTF_HOST);
+ rtinit(ifa, ifa, SIOCDELRT, 0);
+ }
+
+ /*
+ * Unlink the interface's address(es) from the in_ifaddr list.
+ */
+ for (inap = &in_ifaddr; *inap != 0; ) {
+ if ((*inap)->ia_ifa.ifa_ifp == ifp)
+ *inap = (*inap)->ia_next;
+ else
+ inap = &(*inap)->ia_next;
+ }
+
+ /*
+ * Delete the interface from the ifnet list.
+ */
+ for (ifpp = &ifnet; (*ifpp) != 0; ) {
+ if (*ifpp == ifp)
+ break;
+ ifpp = &(*ifpp)->if_next;
+ }
+ if (*ifpp == 0)
+ printf("couldn't find interface ppp%d in ifnet list\n", ifp->if_unit);
+ else
+ *ifpp = ifp->if_next;
+
+ splx(s);
+}
+
+#endif /* __osf__ */
diff --git a/mdk-stage1/ppp/modules/ppp.c b/mdk-stage1/ppp/modules/ppp.c
new file mode 100644
index 000000000..f6d8c93df
--- /dev/null
+++ b/mdk-stage1/ppp/modules/ppp.c
@@ -0,0 +1,2486 @@
+/*
+ * ppp.c - STREAMS multiplexing pseudo-device driver for PPP.
+ *
+ * Copyright (c) 1994 The Australian National University.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation is hereby granted, provided that the above copyright
+ * notice appears in all copies. This software is provided without any
+ * warranty, express or implied. The Australian National University
+ * makes no representations about the suitability of this software for
+ * any purpose.
+ *
+ * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
+ * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
+ * THE AUSTRALIAN NATIONAL UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
+ * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
+ * OR MODIFICATIONS.
+ *
+ * $Id: ppp.c 195720 2001-06-11 11:44:34Z gc $
+ */
+
+/*
+ * This file is used under Solaris 2, SVR4, SunOS 4, and Digital UNIX.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/stream.h>
+#include <sys/stropts.h>
+#include <sys/errno.h>
+#ifdef __osf__
+#include <sys/ioctl.h>
+#include <sys/cmn_err.h>
+#define queclass(mp) ((mp)->b_band & QPCTL)
+#else
+#include <sys/ioccom.h>
+#endif
+#include <sys/time.h>
+#ifdef SVR4
+#include <sys/cmn_err.h>
+#include <sys/conf.h>
+#include <sys/dlpi.h>
+#include <sys/ddi.h>
+#ifdef SOL2
+#include <sys/ksynch.h>
+#include <sys/kstat.h>
+#include <sys/sunddi.h>
+#include <sys/ethernet.h>
+#else
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#endif /* SOL2 */
+#else /* not SVR4 */
+#include <sys/user.h>
+#endif /* SVR4 */
+#include <net/ppp_defs.h>
+#include <net/pppio.h>
+#include "ppp_mod.h"
+
+/*
+ * Modifications marked with #ifdef PRIOQ are for priority queueing of
+ * interactive traffic, and are due to Marko Zec <zec@japa.tel.fer.hr>.
+ */
+#ifdef PRIOQ
+#endif /* PRIOQ */
+
+#include <netinet/in.h> /* leave this outside of PRIOQ for htons */
+
+#ifdef __STDC__
+#define __P(x) x
+#else
+#define __P(x) ()
+#endif
+
+/*
+ * The IP module may use this SAP value for IP packets.
+ */
+#ifndef ETHERTYPE_IP
+#define ETHERTYPE_IP 0x800
+#endif
+
+#if !defined(ETHERTYPE_IPV6)
+#define ETHERTYPE_IPV6 0x86dd
+#endif /* !defined(ETHERTYPE_IPV6) */
+
+#if !defined(ETHERTYPE_ALLSAP) && defined(SOL2)
+#define ETHERTYPE_ALLSAP 0
+#endif /* !defined(ETHERTYPE_ALLSAP) && defined(SOL2) */
+
+#if !defined(PPP_ALLSAP) && defined(SOL2)
+#define PPP_ALLSAP PPP_ALLSTATIONS
+#endif /* !defined(PPP_ALLSAP) && defined(SOL2) */
+
+extern time_t time;
+
+#ifdef SOL2
+/*
+ * We use this reader-writer lock to ensure that the lower streams
+ * stay connected to the upper streams while the lower-side put and
+ * service procedures are running. Essentially it is an existence
+ * lock for the upper stream associated with each lower stream.
+ */
+krwlock_t ppp_lower_lock;
+#define LOCK_LOWER_W rw_enter(&ppp_lower_lock, RW_WRITER)
+#define LOCK_LOWER_R rw_enter(&ppp_lower_lock, RW_READER)
+#define TRYLOCK_LOWER_R rw_tryenter(&ppp_lower_lock, RW_READER)
+#define UNLOCK_LOWER rw_exit(&ppp_lower_lock)
+
+#define MT_ENTER(x) mutex_enter(x)
+#define MT_EXIT(x) mutex_exit(x)
+
+/*
+ * Notes on multithreaded implementation for Solaris 2:
+ *
+ * We use an inner perimeter around each queue pair and an outer
+ * perimeter around the whole driver. The inner perimeter is
+ * entered exclusively for all entry points (open, close, put,
+ * service). The outer perimeter is entered exclusively for open
+ * and close and shared for put and service. This is all done for
+ * us by the streams framework.
+ *
+ * I used to think that the perimeters were entered for the lower
+ * streams' put and service routines as well as for the upper streams'.
+ * Because of problems experienced by people, and after reading the
+ * documentation more closely, I now don't think that is true. So we
+ * now use ppp_lower_lock to give us an existence guarantee on the
+ * upper stream controlling each lower stream.
+ *
+ * Shared entry to the outer perimeter protects the existence of all
+ * the upper streams and their upperstr_t structures, and guarantees
+ * that the following fields of any upperstr_t won't change:
+ * nextmn, next, nextppa. It guarantees that the lowerq field of an
+ * upperstr_t won't go from non-zero to zero, that the global `ppas'
+ * won't change and that the no lower stream will get unlinked.
+ *
+ * Shared (reader) access to ppa_lower_lock guarantees that no lower
+ * stream will be unlinked and that the lowerq field of all upperstr_t
+ * structures won't change.
+ */
+
+#else /* SOL2 */
+#define LOCK_LOWER_W 0
+#define LOCK_LOWER_R 0
+#define TRYLOCK_LOWER_R 1
+#define UNLOCK_LOWER 0
+#define MT_ENTER(x) 0
+#define MT_EXIT(x) 0
+
+#endif /* SOL2 */
+
+/*
+ * Private information; one per upper stream.
+ */
+typedef struct upperstr {
+ minor_t mn; /* minor device number */
+ struct upperstr *nextmn; /* next minor device */
+ queue_t *q; /* read q associated with this upper stream */
+ int flags; /* flag bits, see below */
+ int state; /* current DLPI state */
+ int sap; /* service access point */
+ int req_sap; /* which SAP the DLPI client requested */
+ struct upperstr *ppa; /* control stream for our ppa */
+ struct upperstr *next; /* next stream for this ppa */
+ uint ioc_id; /* last ioctl ID for this stream */
+ enum NPmode npmode; /* what to do with packets on this SAP */
+ unsigned char rblocked; /* flow control has blocked upper read strm */
+ /* N.B. rblocked is only changed by control stream's put/srv procs */
+ /*
+ * There is exactly one control stream for each PPA.
+ * The following fields are only used for control streams.
+ */
+ int ppa_id;
+ queue_t *lowerq; /* write queue attached below this PPA */
+ struct upperstr *nextppa; /* next control stream */
+ int mru;
+ int mtu;
+ struct pppstat stats; /* statistics */
+ time_t last_sent; /* time last NP packet sent */
+ time_t last_recv; /* time last NP packet rcvd */
+#ifdef SOL2
+ kmutex_t stats_lock; /* lock for stats updates */
+ kstat_t *kstats; /* stats for netstat */
+#endif /* SOL2 */
+#ifdef LACHTCP
+ int ifflags;
+ char ifname[IFNAMSIZ];
+ struct ifstats ifstats;
+#endif /* LACHTCP */
+} upperstr_t;
+
+/* Values for flags */
+#define US_PRIV 1 /* stream was opened by superuser */
+#define US_CONTROL 2 /* stream is a control stream */
+#define US_BLOCKED 4 /* flow ctrl has blocked lower write stream */
+#define US_LASTMOD 8 /* no PPP modules below us */
+#define US_DBGLOG 0x10 /* log various occurrences */
+#define US_RBLOCKED 0x20 /* flow ctrl has blocked upper read stream */
+
+#if defined(SOL2)
+#if DL_CURRENT_VERSION >= 2
+#define US_PROMISC 0x40 /* stream is promiscuous */
+#endif /* DL_CURRENT_VERSION >= 2 */
+#define US_RAWDATA 0x80 /* raw M_DATA, no DLPI header */
+#endif /* defined(SOL2) */
+
+#ifdef PRIOQ
+static u_char max_band=0;
+static u_char def_band=0;
+
+#define IPPORT_DEFAULT 65535
+
+/*
+ * Port priority table
+ * Highest priority ports are listed first, lowest are listed last.
+ * ICMP & packets using unlisted ports will be treated as "default".
+ * If IPPORT_DEFAULT is not listed here, "default" packets will be
+ * assigned lowest priority.
+ * Each line should be terminated with "0".
+ * Line containing only "0" marks the end of the list.
+ */
+
+static u_short prioq_table[]= {
+ 113, 53, 0,
+ 22, 23, 513, 517, 518, 0,
+ 514, 21, 79, 111, 0,
+ 25, 109, 110, 0,
+ IPPORT_DEFAULT, 0,
+ 20, 70, 80, 8001, 8008, 8080, 0, /* 8001,8008,8080 - common proxy ports */
+0 };
+
+#endif /* PRIOQ */
+
+
+static upperstr_t *minor_devs = NULL;
+static upperstr_t *ppas = NULL;
+
+#ifdef SVR4
+static int pppopen __P((queue_t *, dev_t *, int, int, cred_t *));
+static int pppclose __P((queue_t *, int, cred_t *));
+#else
+static int pppopen __P((queue_t *, int, int, int));
+static int pppclose __P((queue_t *, int));
+#endif /* SVR4 */
+static int pppurput __P((queue_t *, mblk_t *));
+static int pppuwput __P((queue_t *, mblk_t *));
+static int pppursrv __P((queue_t *));
+static int pppuwsrv __P((queue_t *));
+static int ppplrput __P((queue_t *, mblk_t *));
+static int ppplwput __P((queue_t *, mblk_t *));
+static int ppplrsrv __P((queue_t *));
+static int ppplwsrv __P((queue_t *));
+#ifndef NO_DLPI
+static void dlpi_request __P((queue_t *, mblk_t *, upperstr_t *));
+static void dlpi_error __P((queue_t *, upperstr_t *, int, int, int));
+static void dlpi_ok __P((queue_t *, int));
+#endif
+static int send_data __P((mblk_t *, upperstr_t *));
+static void new_ppa __P((queue_t *, mblk_t *));
+static void attach_ppa __P((queue_t *, mblk_t *));
+static void detach_ppa __P((queue_t *, mblk_t *));
+static void detach_lower __P((queue_t *, mblk_t *));
+static void debug_dump __P((queue_t *, mblk_t *));
+static upperstr_t *find_dest __P((upperstr_t *, int));
+#if defined(SOL2)
+static upperstr_t *find_promisc __P((upperstr_t *, int));
+static mblk_t *prepend_ether __P((upperstr_t *, mblk_t *, int));
+static mblk_t *prepend_udind __P((upperstr_t *, mblk_t *, int));
+static void promisc_sendup __P((upperstr_t *, mblk_t *, int, int));
+#endif /* defined(SOL2) */
+static int putctl2 __P((queue_t *, int, int, int));
+static int putctl4 __P((queue_t *, int, int, int));
+static int pass_packet __P((upperstr_t *ppa, mblk_t *mp, int outbound));
+#ifdef FILTER_PACKETS
+static int ip_hard_filter __P((upperstr_t *ppa, mblk_t *mp, int outbound));
+#endif /* FILTER_PACKETS */
+
+#define PPP_ID 0xb1a6
+static struct module_info ppp_info = {
+#ifdef PRIOQ
+ PPP_ID, "ppp", 0, 512, 512, 384
+#else
+ PPP_ID, "ppp", 0, 512, 512, 128
+#endif /* PRIOQ */
+};
+
+static struct qinit pppurint = {
+ pppurput, pppursrv, pppopen, pppclose, NULL, &ppp_info, NULL
+};
+
+static struct qinit pppuwint = {
+ pppuwput, pppuwsrv, NULL, NULL, NULL, &ppp_info, NULL
+};
+
+static struct qinit ppplrint = {
+ ppplrput, ppplrsrv, NULL, NULL, NULL, &ppp_info, NULL
+};
+
+static struct qinit ppplwint = {
+ ppplwput, ppplwsrv, NULL, NULL, NULL, &ppp_info, NULL
+};
+
+#ifdef LACHTCP
+extern struct ifstats *ifstats;
+int pppdevflag = 0;
+#endif
+
+struct streamtab pppinfo = {
+ &pppurint, &pppuwint,
+ &ppplrint, &ppplwint
+};
+
+int ppp_count;
+
+/*
+ * How we maintain statistics.
+ */
+#ifdef SOL2
+#define INCR_IPACKETS(ppa) \
+ if (ppa->kstats != 0) { \
+ KSTAT_NAMED_PTR(ppa->kstats)[0].value.ul++; \
+ }
+#define INCR_IERRORS(ppa) \
+ if (ppa->kstats != 0) { \
+ KSTAT_NAMED_PTR(ppa->kstats)[1].value.ul++; \
+ }
+#define INCR_OPACKETS(ppa) \
+ if (ppa->kstats != 0) { \
+ KSTAT_NAMED_PTR(ppa->kstats)[2].value.ul++; \
+ }
+#define INCR_OERRORS(ppa) \
+ if (ppa->kstats != 0) { \
+ KSTAT_NAMED_PTR(ppa->kstats)[3].value.ul++; \
+ }
+#endif
+
+#ifdef LACHTCP
+#define INCR_IPACKETS(ppa) ppa->ifstats.ifs_ipackets++;
+#define INCR_IERRORS(ppa) ppa->ifstats.ifs_ierrors++;
+#define INCR_OPACKETS(ppa) ppa->ifstats.ifs_opackets++;
+#define INCR_OERRORS(ppa) ppa->ifstats.ifs_oerrors++;
+#endif
+
+/*
+ * STREAMS driver entry points.
+ */
+static int
+#ifdef SVR4
+pppopen(q, devp, oflag, sflag, credp)
+ queue_t *q;
+ dev_t *devp;
+ int oflag, sflag;
+ cred_t *credp;
+#else
+pppopen(q, dev, oflag, sflag)
+ queue_t *q;
+ int dev; /* really dev_t */
+ int oflag, sflag;
+#endif
+{
+ upperstr_t *up;
+ upperstr_t **prevp;
+ minor_t mn;
+#ifdef PRIOQ
+ u_short *ptr;
+ u_char new_band;
+#endif /* PRIOQ */
+
+ if (q->q_ptr)
+ DRV_OPEN_OK(dev); /* device is already open */
+
+#ifdef PRIOQ
+ /* Calculate max_bband & def_band from definitions in prioq.h
+ This colud be done at some more approtiate time (less often)
+ but this way it works well so I'll just leave it here */
+
+ max_band = 1;
+ def_band = 0;
+ ptr = prioq_table;
+ while (*ptr) {
+ new_band = 1;
+ while (*ptr)
+ if (*ptr++ == IPPORT_DEFAULT) {
+ new_band = 0;
+ def_band = max_band;
+ }
+ max_band += new_band;
+ ptr++;
+ }
+ if (def_band)
+ def_band = max_band - def_band;
+ --max_band;
+#endif /* PRIOQ */
+
+ if (sflag == CLONEOPEN) {
+ mn = 0;
+ for (prevp = &minor_devs; (up = *prevp) != 0; prevp = &up->nextmn) {
+ if (up->mn != mn)
+ break;
+ ++mn;
+ }
+ } else {
+#ifdef SVR4
+ mn = getminor(*devp);
+#else
+ mn = minor(dev);
+#endif
+ for (prevp = &minor_devs; (up = *prevp) != 0; prevp = &up->nextmn) {
+ if (up->mn >= mn)
+ break;
+ }
+ if (up->mn == mn) {
+ /* this can't happen */
+ q->q_ptr = WR(q)->q_ptr = (caddr_t) up;
+ DRV_OPEN_OK(dev);
+ }
+ }
+
+ /*
+ * Construct a new minor node.
+ */
+ up = (upperstr_t *) ALLOC_SLEEP(sizeof(upperstr_t));
+ bzero((caddr_t) up, sizeof(upperstr_t));
+ if (up == 0) {
+ DPRINT("pppopen: out of kernel memory\n");
+ OPEN_ERROR(ENXIO);
+ }
+ up->nextmn = *prevp;
+ *prevp = up;
+ up->mn = mn;
+#ifdef SVR4
+ *devp = makedevice(getmajor(*devp), mn);
+#endif
+ up->q = q;
+ if (NOTSUSER() == 0)
+ up->flags |= US_PRIV;
+#ifndef NO_DLPI
+ up->state = DL_UNATTACHED;
+#endif
+#ifdef LACHTCP
+ up->ifflags = IFF_UP | IFF_POINTOPOINT;
+#endif
+ up->sap = -1;
+ up->last_sent = up->last_recv = time;
+ up->npmode = NPMODE_DROP;
+ q->q_ptr = (caddr_t) up;
+ WR(q)->q_ptr = (caddr_t) up;
+ noenable(WR(q));
+#ifdef SOL2
+ mutex_init(&up->stats_lock, NULL, MUTEX_DRIVER, NULL);
+#endif
+ ++ppp_count;
+
+ qprocson(q);
+ DRV_OPEN_OK(makedev(major(dev), mn));
+}
+
+static int
+#ifdef SVR4
+pppclose(q, flag, credp)
+ queue_t *q;
+ int flag;
+ cred_t *credp;
+#else
+pppclose(q, flag)
+ queue_t *q;
+ int flag;
+#endif
+{
+ upperstr_t *up, **upp;
+ upperstr_t *as, *asnext;
+ upperstr_t **prevp;
+
+ qprocsoff(q);
+
+ up = (upperstr_t *) q->q_ptr;
+ if (up == 0) {
+ DPRINT("pppclose: q_ptr = 0\n");
+ return 0;
+ }
+ if (up->flags & US_DBGLOG)
+ DPRINT2("ppp/%d: close, flags=%x\n", up->mn, up->flags);
+ if (up->flags & US_CONTROL) {
+#ifdef LACHTCP
+ struct ifstats *ifp, *pifp;
+#endif
+ if (up->lowerq != 0) {
+ /* Gack! the lower stream should have be unlinked earlier! */
+ DPRINT1("ppp%d: lower stream still connected on close?\n",
+ up->mn);
+ LOCK_LOWER_W;
+ up->lowerq->q_ptr = 0;
+ RD(up->lowerq)->q_ptr = 0;
+ up->lowerq = 0;
+ UNLOCK_LOWER;
+ }
+
+ /*
+ * This stream represents a PPA:
+ * For all streams attached to the PPA, clear their
+ * references to this PPA.
+ * Then remove this PPA from the list of PPAs.
+ */
+ for (as = up->next; as != 0; as = asnext) {
+ asnext = as->next;
+ as->next = 0;
+ as->ppa = 0;
+ if (as->flags & US_BLOCKED) {
+ as->flags &= ~US_BLOCKED;
+ flushq(WR(as->q), FLUSHDATA);
+ }
+ }
+ for (upp = &ppas; *upp != 0; upp = &(*upp)->nextppa)
+ if (*upp == up) {
+ *upp = up->nextppa;
+ break;
+ }
+#ifdef LACHTCP
+ /* Remove the statistics from the active list. */
+ for (ifp = ifstats, pifp = 0; ifp; ifp = ifp->ifs_next) {
+ if (ifp == &up->ifstats) {
+ if (pifp)
+ pifp->ifs_next = ifp->ifs_next;
+ else
+ ifstats = ifp->ifs_next;
+ break;
+ }
+ pifp = ifp;
+ }
+#endif
+ } else {
+ /*
+ * If this stream is attached to a PPA,
+ * remove it from the PPA's list.
+ */
+ if ((as = up->ppa) != 0) {
+ for (; as->next != 0; as = as->next)
+ if (as->next == up) {
+ as->next = up->next;
+ break;
+ }
+ }
+ }
+
+#ifdef SOL2
+ if (up->kstats)
+ kstat_delete(up->kstats);
+ mutex_destroy(&up->stats_lock);
+#endif
+
+ q->q_ptr = NULL;
+ WR(q)->q_ptr = NULL;
+
+ for (prevp = &minor_devs; *prevp != 0; prevp = &(*prevp)->nextmn) {
+ if (*prevp == up) {
+ *prevp = up->nextmn;
+ break;
+ }
+ }
+ FREE(up, sizeof(upperstr_t));
+ --ppp_count;
+
+ return 0;
+}
+
+/*
+ * A message from on high. We do one of three things:
+ * - qreply()
+ * - put the message on the lower write stream
+ * - queue it for our service routine
+ */
+static int
+pppuwput(q, mp)
+ queue_t *q;
+ mblk_t *mp;
+{
+ upperstr_t *us, *ppa, *nps;
+ struct iocblk *iop;
+ struct linkblk *lb;
+#ifdef LACHTCP
+ struct ifreq *ifr;
+ int i;
+#endif
+ queue_t *lq;
+ int error, n, sap;
+ mblk_t *mq;
+ struct ppp_idle *pip;
+#ifdef PRIOQ
+ queue_t *tlq;
+#endif /* PRIOQ */
+#ifdef NO_DLPI
+ upperstr_t *os;
+#endif
+
+ us = (upperstr_t *) q->q_ptr;
+ if (us == 0) {
+ DPRINT("pppuwput: q_ptr = 0!\n");
+ return 0;
+ }
+ if (mp == 0) {
+ DPRINT1("pppuwput/%d: mp = 0!\n", us->mn);
+ return 0;
+ }
+ if (mp->b_datap == 0) {
+ DPRINT1("pppuwput/%d: mp->b_datap = 0!\n", us->mn);
+ return 0;
+ }
+ switch (mp->b_datap->db_type) {
+#ifndef NO_DLPI
+ case M_PCPROTO:
+ case M_PROTO:
+ dlpi_request(q, mp, us);
+ break;
+#endif /* NO_DLPI */
+
+ case M_DATA:
+ if (us->flags & US_DBGLOG)
+ DPRINT3("ppp/%d: uwput M_DATA len=%d flags=%x\n",
+ us->mn, msgdsize(mp), us->flags);
+ if (us->ppa == 0 || msgdsize(mp) > us->ppa->mtu + PPP_HDRLEN
+#ifndef NO_DLPI
+ || (us->flags & US_CONTROL) == 0
+#endif /* NO_DLPI */
+ ) {
+ DPRINT1("pppuwput: junk data len=%d\n", msgdsize(mp));
+ freemsg(mp);
+ break;
+ }
+#ifdef NO_DLPI
+ if ((us->flags & US_CONTROL) == 0 && !pass_packet(us, mp, 1))
+ break;
+#endif
+ if (!send_data(mp, us))
+ putq(q, mp);
+ break;
+
+ case M_IOCTL:
+ iop = (struct iocblk *) mp->b_rptr;
+ error = EINVAL;
+ if (us->flags & US_DBGLOG)
+ DPRINT3("ppp/%d: ioctl %x count=%d\n",
+ us->mn, iop->ioc_cmd, iop->ioc_count);
+ switch (iop->ioc_cmd) {
+#if defined(SOL2)
+ case DLIOCRAW: /* raw M_DATA mode */
+ us->flags |= US_RAWDATA;
+ error = 0;
+ break;
+#endif /* defined(SOL2) */
+ case I_LINK:
+ if ((us->flags & US_CONTROL) == 0 || us->lowerq != 0)
+ break;
+ if (mp->b_cont == 0) {
+ DPRINT1("pppuwput/%d: ioctl I_LINK b_cont = 0!\n", us->mn);
+ break;
+ }
+ lb = (struct linkblk *) mp->b_cont->b_rptr;
+ lq = lb->l_qbot;
+ if (lq == 0) {
+ DPRINT1("pppuwput/%d: ioctl I_LINK l_qbot = 0!\n", us->mn);
+ break;
+ }
+ LOCK_LOWER_W;
+ us->lowerq = lq;
+ lq->q_ptr = (caddr_t) q;
+ RD(lq)->q_ptr = (caddr_t) us->q;
+ UNLOCK_LOWER;
+ iop->ioc_count = 0;
+ error = 0;
+ us->flags &= ~US_LASTMOD;
+ /* Unblock upper streams which now feed this lower stream. */
+ qenable(q);
+ /* Send useful information down to the modules which
+ are now linked below us. */
+ putctl2(lq, M_CTL, PPPCTL_UNIT, us->ppa_id);
+ putctl4(lq, M_CTL, PPPCTL_MRU, us->mru);
+ putctl4(lq, M_CTL, PPPCTL_MTU, us->mtu);
+#ifdef PRIOQ
+ /* Lower tty driver's queue hiwat/lowat from default 4096/128
+ to 256/128 since we don't want queueing of data on
+ output to physical device */
+
+ freezestr(lq);
+ for (tlq = lq; tlq->q_next != NULL; tlq = tlq->q_next)
+ ;
+ strqset(tlq, QHIWAT, 0, 256);
+ strqset(tlq, QLOWAT, 0, 128);
+ unfreezestr(lq);
+#endif /* PRIOQ */
+ break;
+
+ case I_UNLINK:
+ if (mp->b_cont == 0) {
+ DPRINT1("pppuwput/%d: ioctl I_UNLINK b_cont = 0!\n", us->mn);
+ break;
+ }
+ lb = (struct linkblk *) mp->b_cont->b_rptr;
+#if DEBUG
+ if (us->lowerq != lb->l_qbot) {
+ DPRINT2("ppp unlink: lowerq=%x qbot=%x\n",
+ us->lowerq, lb->l_qbot);
+ break;
+ }
+#endif
+ iop->ioc_count = 0;
+ qwriter(q, mp, detach_lower, PERIM_OUTER);
+ error = -1;
+ break;
+
+ case PPPIO_NEWPPA:
+ if (us->flags & US_CONTROL)
+ break;
+ if ((us->flags & US_PRIV) == 0) {
+ error = EPERM;
+ break;
+ }
+ /* Arrange to return an int */
+ if ((mq = mp->b_cont) == 0
+ || mq->b_datap->db_lim - mq->b_rptr < sizeof(int)) {
+ mq = allocb(sizeof(int), BPRI_HI);
+ if (mq == 0) {
+ error = ENOSR;
+ break;
+ }
+ if (mp->b_cont != 0)
+ freemsg(mp->b_cont);
+ mp->b_cont = mq;
+ mq->b_cont = 0;
+ }
+ iop->ioc_count = sizeof(int);
+ mq->b_wptr = mq->b_rptr + sizeof(int);
+ qwriter(q, mp, new_ppa, PERIM_OUTER);
+ error = -1;
+ break;
+
+ case PPPIO_ATTACH:
+ /* like dlpi_attach, for programs which can't write to
+ the stream (like pppstats) */
+ if (iop->ioc_count != sizeof(int) || us->ppa != 0)
+ break;
+ if (mp->b_cont == 0) {
+ DPRINT1("pppuwput/%d: ioctl PPPIO_ATTACH b_cont = 0!\n", us->mn);
+ break;
+ }
+ n = *(int *)mp->b_cont->b_rptr;
+ for (ppa = ppas; ppa != 0; ppa = ppa->nextppa)
+ if (ppa->ppa_id == n)
+ break;
+ if (ppa == 0)
+ break;
+ us->ppa = ppa;
+ iop->ioc_count = 0;
+ qwriter(q, mp, attach_ppa, PERIM_OUTER);
+ error = -1;
+ break;
+
+#ifdef NO_DLPI
+ case PPPIO_BIND:
+ /* Attach to a given SAP. */
+ if (iop->ioc_count != sizeof(int) || us->ppa == 0)
+ break;
+ if (mp->b_cont == 0) {
+ DPRINT1("pppuwput/%d: ioctl PPPIO_BIND b_cont = 0!\n", us->mn);
+ break;
+ }
+ n = *(int *)mp->b_cont->b_rptr;
+ /* n must be a valid PPP network protocol number. */
+ if (n < 0x21 || n > 0x3fff || (n & 0x101) != 1)
+ break;
+ /* check that no other stream is bound to this sap already. */
+ for (os = us->ppa; os != 0; os = os->next)
+ if (os->sap == n)
+ break;
+ if (os != 0)
+ break;
+ us->sap = n;
+ iop->ioc_count = 0;
+ error = 0;
+ break;
+#endif /* NO_DLPI */
+
+ case PPPIO_MRU:
+ if (iop->ioc_count != sizeof(int) || (us->flags & US_CONTROL) == 0)
+ break;
+ if (mp->b_cont == 0) {
+ DPRINT1("pppuwput/%d: ioctl PPPIO_MRU b_cont = 0!\n", us->mn);
+ break;
+ }
+ n = *(int *)mp->b_cont->b_rptr;
+ if (n <= 0 || n > PPP_MAXMRU)
+ break;
+ if (n < PPP_MRU)
+ n = PPP_MRU;
+ us->mru = n;
+ if (us->lowerq)
+ putctl4(us->lowerq, M_CTL, PPPCTL_MRU, n);
+ error = 0;
+ iop->ioc_count = 0;
+ break;
+
+ case PPPIO_MTU:
+ if (iop->ioc_count != sizeof(int) || (us->flags & US_CONTROL) == 0)
+ break;
+ if (mp->b_cont == 0) {
+ DPRINT1("pppuwput/%d: ioctl PPPIO_MTU b_cont = 0!\n", us->mn);
+ break;
+ }
+ n = *(int *)mp->b_cont->b_rptr;
+ if (n <= 0 || n > PPP_MAXMTU)
+ break;
+ us->mtu = n;
+#ifdef LACHTCP
+ /* The MTU reported in netstat, not used as IP max packet size! */
+ us->ifstats.ifs_mtu = n;
+#endif
+ if (us->lowerq)
+ putctl4(us->lowerq, M_CTL, PPPCTL_MTU, n);
+ error = 0;
+ iop->ioc_count = 0;
+ break;
+
+ case PPPIO_LASTMOD:
+ us->flags |= US_LASTMOD;
+ error = 0;
+ break;
+
+ case PPPIO_DEBUG:
+ if (iop->ioc_count != sizeof(int))
+ break;
+ if (mp->b_cont == 0) {
+ DPRINT1("pppuwput/%d: ioctl PPPIO_DEBUG b_cont = 0!\n", us->mn);
+ break;
+ }
+ n = *(int *)mp->b_cont->b_rptr;
+ if (n == PPPDBG_DUMP + PPPDBG_DRIVER) {
+ qwriter(q, NULL, debug_dump, PERIM_OUTER);
+ iop->ioc_count = 0;
+ error = -1;
+ } else if (n == PPPDBG_LOG + PPPDBG_DRIVER) {
+ DPRINT1("ppp/%d: debug log enabled\n", us->mn);
+ us->flags |= US_DBGLOG;
+ iop->ioc_count = 0;
+ error = 0;
+ } else {
+ if (us->ppa == 0 || us->ppa->lowerq == 0)
+ break;
+ putnext(us->ppa->lowerq, mp);
+ error = -1;
+ }
+ break;
+
+ case PPPIO_NPMODE:
+ if (iop->ioc_count != 2 * sizeof(int))
+ break;
+ if ((us->flags & US_CONTROL) == 0)
+ break;
+ if (mp->b_cont == 0) {
+ DPRINT1("pppuwput/%d: ioctl PPPIO_NPMODE b_cont = 0!\n", us->mn);
+ break;
+ }
+ sap = ((int *)mp->b_cont->b_rptr)[0];
+ for (nps = us->next; nps != 0; nps = nps->next) {
+ if (us->flags & US_DBGLOG)
+ DPRINT2("us = 0x%x, us->next->sap = 0x%x\n", nps, nps->sap);
+ if (nps->sap == sap)
+ break;
+ }
+ if (nps == 0) {
+ if (us->flags & US_DBGLOG)
+ DPRINT2("ppp/%d: no stream for sap %x\n", us->mn, sap);
+ break;
+ }
+ /* XXX possibly should use qwriter here */
+ nps->npmode = (enum NPmode) ((int *)mp->b_cont->b_rptr)[1];
+ if (nps->npmode != NPMODE_QUEUE && (nps->flags & US_BLOCKED) != 0)
+ qenable(WR(nps->q));
+ iop->ioc_count = 0;
+ error = 0;
+ break;
+
+ case PPPIO_GIDLE:
+ if ((ppa = us->ppa) == 0)
+ break;
+ mq = allocb(sizeof(struct ppp_idle), BPRI_HI);
+ if (mq == 0) {
+ error = ENOSR;
+ break;
+ }
+ if (mp->b_cont != 0)
+ freemsg(mp->b_cont);
+ mp->b_cont = mq;
+ mq->b_cont = 0;
+ pip = (struct ppp_idle *) mq->b_wptr;
+ pip->xmit_idle = time - ppa->last_sent;
+ pip->recv_idle = time - ppa->last_recv;
+ mq->b_wptr += sizeof(struct ppp_idle);
+ iop->ioc_count = sizeof(struct ppp_idle);
+ error = 0;
+ break;
+
+#ifdef LACHTCP
+ case SIOCSIFNAME:
+ /* Sent from IP down to us. Attach the ifstats structure. */
+ if (iop->ioc_count != sizeof(struct ifreq) || us->ppa == 0)
+ break;
+ ifr = (struct ifreq *)mp->b_cont->b_rptr;
+ /* Find the unit number in the interface name. */
+ for (i = 0; i < IFNAMSIZ; i++) {
+ if (ifr->ifr_name[i] == 0 ||
+ (ifr->ifr_name[i] >= '0' &&
+ ifr->ifr_name[i] <= '9'))
+ break;
+ else
+ us->ifname[i] = ifr->ifr_name[i];
+ }
+ us->ifname[i] = 0;
+
+ /* Convert the unit number to binary. */
+ for (n = 0; i < IFNAMSIZ; i++) {
+ if (ifr->ifr_name[i] == 0) {
+ break;
+ }
+ else {
+ n = n * 10 + ifr->ifr_name[i] - '0';
+ }
+ }
+
+ /* Verify the ppa. */
+ if (us->ppa->ppa_id != n)
+ break;
+ ppa = us->ppa;
+
+ /* Set up the netstat block. */
+ strncpy (ppa->ifname, us->ifname, IFNAMSIZ);
+
+ ppa->ifstats.ifs_name = ppa->ifname;
+ ppa->ifstats.ifs_unit = n;
+ ppa->ifstats.ifs_active = us->state != DL_UNBOUND;
+ ppa->ifstats.ifs_mtu = ppa->mtu;
+
+ /* Link in statistics used by netstat. */
+ ppa->ifstats.ifs_next = ifstats;
+ ifstats = &ppa->ifstats;
+
+ iop->ioc_count = 0;
+ error = 0;
+ break;
+
+ case SIOCGIFFLAGS:
+ if (!(us->flags & US_CONTROL)) {
+ if (us->ppa)
+ us = us->ppa;
+ else
+ break;
+ }
+ ((struct iocblk_in *)iop)->ioc_ifflags = us->ifflags;
+ error = 0;
+ break;
+
+ case SIOCSIFFLAGS:
+ if (!(us->flags & US_CONTROL)) {
+ if (us->ppa)
+ us = us->ppa;
+ else
+ break;
+ }
+ us->ifflags = ((struct iocblk_in *)iop)->ioc_ifflags;
+ error = 0;
+ break;
+
+ case SIOCSIFADDR:
+ if (!(us->flags & US_CONTROL)) {
+ if (us->ppa)
+ us = us->ppa;
+ else
+ break;
+ }
+ us->ifflags |= IFF_RUNNING;
+ ((struct iocblk_in *)iop)->ioc_ifflags |= IFF_RUNNING;
+ error = 0;
+ break;
+
+ case SIOCSIFMTU:
+ /*
+ * Vanilla SVR4 systems don't handle SIOCSIFMTU, rather
+ * they take the MTU from the DL_INFO_ACK we sent in response
+ * to their DL_INFO_REQ. Fortunately, they will update the
+ * MTU if we send an unsolicited DL_INFO_ACK up.
+ */
+ if ((mq = allocb(sizeof(dl_info_req_t), BPRI_HI)) == 0)
+ break; /* should do bufcall */
+ ((union DL_primitives *)mq->b_rptr)->dl_primitive = DL_INFO_REQ;
+ mq->b_wptr = mq->b_rptr + sizeof(dl_info_req_t);
+ dlpi_request(q, mq, us);
+ error = 0;
+ break;
+
+ case SIOCGIFNETMASK:
+ case SIOCSIFNETMASK:
+ case SIOCGIFADDR:
+ case SIOCGIFDSTADDR:
+ case SIOCSIFDSTADDR:
+ case SIOCGIFMETRIC:
+ error = 0;
+ break;
+#endif /* LACHTCP */
+
+ default:
+ if (us->ppa == 0 || us->ppa->lowerq == 0)
+ break;
+ us->ioc_id = iop->ioc_id;
+ error = -1;
+ switch (iop->ioc_cmd) {
+ case PPPIO_GETSTAT:
+ case PPPIO_GETCSTAT:
+ if (us->flags & US_LASTMOD) {
+ error = EINVAL;
+ break;
+ }
+ putnext(us->ppa->lowerq, mp);
+ break;
+ default:
+ if (us->flags & US_PRIV)
+ putnext(us->ppa->lowerq, mp);
+ else {
+ DPRINT1("ppp ioctl %x rejected\n", iop->ioc_cmd);
+ error = EPERM;
+ }
+ break;
+ }
+ break;
+ }
+
+ if (error > 0) {
+ iop->ioc_error = error;
+ mp->b_datap->db_type = M_IOCNAK;
+ qreply(q, mp);
+ } else if (error == 0) {
+ mp->b_datap->db_type = M_IOCACK;
+ qreply(q, mp);
+ }
+ break;
+
+ case M_FLUSH:
+ if (us->flags & US_DBGLOG)
+ DPRINT2("ppp/%d: flush %x\n", us->mn, *mp->b_rptr);
+ if (*mp->b_rptr & FLUSHW)
+ flushq(q, FLUSHDATA);
+ if (*mp->b_rptr & FLUSHR) {
+ *mp->b_rptr &= ~FLUSHW;
+ qreply(q, mp);
+ } else
+ freemsg(mp);
+ break;
+
+ default:
+ freemsg(mp);
+ break;
+ }
+ return 0;
+}
+
+#ifndef NO_DLPI
+static void
+dlpi_request(q, mp, us)
+ queue_t *q;
+ mblk_t *mp;
+ upperstr_t *us;
+{
+ union DL_primitives *d = (union DL_primitives *) mp->b_rptr;
+ int size = mp->b_wptr - mp->b_rptr;
+ mblk_t *reply, *np;
+ upperstr_t *ppa, *os;
+ int sap, len;
+ dl_info_ack_t *info;
+ dl_bind_ack_t *ackp;
+#if DL_CURRENT_VERSION >= 2
+ dl_phys_addr_ack_t *paddrack;
+ static struct ether_addr eaddr = {0};
+#endif
+
+ if (us->flags & US_DBGLOG)
+ DPRINT3("ppp/%d: dlpi prim %x len=%d\n", us->mn,
+ d->dl_primitive, size);
+ switch (d->dl_primitive) {
+ case DL_INFO_REQ:
+ if (size < sizeof(dl_info_req_t))
+ goto badprim;
+ if ((reply = allocb(sizeof(dl_info_ack_t), BPRI_HI)) == 0)
+ break; /* should do bufcall */
+ reply->b_datap->db_type = M_PCPROTO;
+ info = (dl_info_ack_t *) reply->b_wptr;
+ reply->b_wptr += sizeof(dl_info_ack_t);
+ bzero((caddr_t) info, sizeof(dl_info_ack_t));
+ info->dl_primitive = DL_INFO_ACK;
+ info->dl_max_sdu = us->ppa? us->ppa->mtu: PPP_MAXMTU;
+ info->dl_min_sdu = 1;
+ info->dl_addr_length = sizeof(uint);
+ info->dl_mac_type = DL_ETHER; /* a bigger lie */
+ info->dl_current_state = us->state;
+ info->dl_service_mode = DL_CLDLS;
+ info->dl_provider_style = DL_STYLE2;
+#if DL_CURRENT_VERSION >= 2
+ info->dl_sap_length = sizeof(uint);
+ info->dl_version = DL_CURRENT_VERSION;
+#endif
+ qreply(q, reply);
+ break;
+
+ case DL_ATTACH_REQ:
+ if (size < sizeof(dl_attach_req_t))
+ goto badprim;
+ if (us->state != DL_UNATTACHED || us->ppa != 0) {
+ dlpi_error(q, us, DL_ATTACH_REQ, DL_OUTSTATE, 0);
+ break;
+ }
+ for (ppa = ppas; ppa != 0; ppa = ppa->nextppa)
+ if (ppa->ppa_id == d->attach_req.dl_ppa)
+ break;
+ if (ppa == 0) {
+ dlpi_error(q, us, DL_ATTACH_REQ, DL_BADPPA, 0);
+ break;
+ }
+ us->ppa = ppa;
+ qwriter(q, mp, attach_ppa, PERIM_OUTER);
+ return;
+
+ case DL_DETACH_REQ:
+ if (size < sizeof(dl_detach_req_t))
+ goto badprim;
+ if (us->state != DL_UNBOUND || us->ppa == 0) {
+ dlpi_error(q, us, DL_DETACH_REQ, DL_OUTSTATE, 0);
+ break;
+ }
+ qwriter(q, mp, detach_ppa, PERIM_OUTER);
+ return;
+
+ case DL_BIND_REQ:
+ if (size < sizeof(dl_bind_req_t))
+ goto badprim;
+ if (us->state != DL_UNBOUND || us->ppa == 0) {
+ dlpi_error(q, us, DL_BIND_REQ, DL_OUTSTATE, 0);
+ break;
+ }
+#if 0
+ /* apparently this test fails (unnecessarily?) on some systems */
+ if (d->bind_req.dl_service_mode != DL_CLDLS) {
+ dlpi_error(q, us, DL_BIND_REQ, DL_UNSUPPORTED, 0);
+ break;
+ }
+#endif
+
+ /* saps must be valid PPP network protocol numbers,
+ except that we accept ETHERTYPE_IP in place of PPP_IP. */
+ sap = d->bind_req.dl_sap;
+ us->req_sap = sap;
+
+#if defined(SOL2)
+ if (us->flags & US_DBGLOG)
+ DPRINT2("DL_BIND_REQ: ip gives sap = 0x%x, us = 0x%x", sap, us);
+
+ if (sap == ETHERTYPE_IP) /* normal IFF_IPV4 */
+ sap = PPP_IP;
+ else if (sap == ETHERTYPE_IPV6) /* when IFF_IPV6 is set */
+ sap = PPP_IPV6;
+ else if (sap == ETHERTYPE_ALLSAP) /* snoop gives sap of 0 */
+ sap = PPP_ALLSAP;
+ else {
+ DPRINT2("DL_BIND_REQ: unrecognized sap = 0x%x, us = 0x%x", sap, us);
+ dlpi_error(q, us, DL_BIND_REQ, DL_BADADDR, 0);
+ break;
+ }
+#else
+ if (sap == ETHERTYPE_IP)
+ sap = PPP_IP;
+ if (sap < 0x21 || sap > 0x3fff || (sap & 0x101) != 1) {
+ dlpi_error(q, us, DL_BIND_REQ, DL_BADADDR, 0);
+ break;
+ }
+#endif /* defined(SOL2) */
+
+ /* check that no other stream is bound to this sap already. */
+ for (os = us->ppa; os != 0; os = os->next)
+ if (os->sap == sap)
+ break;
+ if (os != 0) {
+ dlpi_error(q, us, DL_BIND_REQ, DL_NOADDR, 0);
+ break;
+ }
+
+ us->sap = sap;
+ us->state = DL_IDLE;
+
+ if ((reply = allocb(sizeof(dl_bind_ack_t) + sizeof(uint),
+ BPRI_HI)) == 0)
+ break; /* should do bufcall */
+ ackp = (dl_bind_ack_t *) reply->b_wptr;
+ reply->b_wptr += sizeof(dl_bind_ack_t) + sizeof(uint);
+ reply->b_datap->db_type = M_PCPROTO;
+ bzero((caddr_t) ackp, sizeof(dl_bind_ack_t));
+ ackp->dl_primitive = DL_BIND_ACK;
+ ackp->dl_sap = sap;
+ ackp->dl_addr_length = sizeof(uint);
+ ackp->dl_addr_offset = sizeof(dl_bind_ack_t);
+ *(uint *)(ackp+1) = sap;
+ qreply(q, reply);
+ break;
+
+ case DL_UNBIND_REQ:
+ if (size < sizeof(dl_unbind_req_t))
+ goto badprim;
+ if (us->state != DL_IDLE) {
+ dlpi_error(q, us, DL_UNBIND_REQ, DL_OUTSTATE, 0);
+ break;
+ }
+ us->sap = -1;
+ us->state = DL_UNBOUND;
+#ifdef LACHTCP
+ us->ppa->ifstats.ifs_active = 0;
+#endif
+ dlpi_ok(q, DL_UNBIND_REQ);
+ break;
+
+ case DL_UNITDATA_REQ:
+ if (size < sizeof(dl_unitdata_req_t))
+ goto badprim;
+ if (us->state != DL_IDLE) {
+ dlpi_error(q, us, DL_UNITDATA_REQ, DL_OUTSTATE, 0);
+ break;
+ }
+ if ((ppa = us->ppa) == 0) {
+ cmn_err(CE_CONT, "ppp: in state dl_idle but ppa == 0?\n");
+ break;
+ }
+ len = mp->b_cont == 0? 0: msgdsize(mp->b_cont);
+ if (len > ppa->mtu) {
+ DPRINT2("dlpi data too large (%d > %d)\n", len, ppa->mtu);
+ break;
+ }
+
+#if defined(SOL2)
+ /*
+ * Should there be any promiscuous stream(s), send the data
+ * up for each promiscuous stream that we recognize.
+ */
+ if (mp->b_cont)
+ promisc_sendup(ppa, mp->b_cont, us->sap, 0);
+#endif /* defined(SOL2) */
+
+ mp->b_band = 0;
+#ifdef PRIOQ
+ /* Extract s_port & d_port from IP-packet, the code is a bit
+ dirty here, but so am I, too... */
+ if (mp->b_datap->db_type == M_PROTO && us->sap == PPP_IP
+ && mp->b_cont != 0) {
+ u_char *bb, *tlh;
+ int iphlen, len;
+ u_short *ptr;
+ u_char band_unset, cur_band, syn;
+ u_short s_port, d_port;
+
+ bb = mp->b_cont->b_rptr; /* bb points to IP-header*/
+ len = mp->b_cont->b_wptr - mp->b_cont->b_rptr;
+ syn = 0;
+ s_port = IPPORT_DEFAULT;
+ d_port = IPPORT_DEFAULT;
+ if (len >= 20) { /* 20 = minimum length of IP header */
+ iphlen = (bb[0] & 0x0f) * 4;
+ tlh = bb + iphlen;
+ len -= iphlen;
+ switch (bb[9]) {
+ case IPPROTO_TCP:
+ if (len >= 20) { /* min length of TCP header */
+ s_port = (tlh[0] << 8) + tlh[1];
+ d_port = (tlh[2] << 8) + tlh[3];
+ syn = tlh[13] & 0x02;
+ }
+ break;
+ case IPPROTO_UDP:
+ if (len >= 8) { /* min length of UDP header */
+ s_port = (tlh[0] << 8) + tlh[1];
+ d_port = (tlh[2] << 8) + tlh[3];
+ }
+ break;
+ }
+ }
+
+ /*
+ * Now calculate b_band for this packet from the
+ * port-priority table.
+ */
+ ptr = prioq_table;
+ cur_band = max_band;
+ band_unset = 1;
+ while (*ptr) {
+ while (*ptr && band_unset)
+ if (s_port == *ptr || d_port == *ptr++) {
+ mp->b_band = cur_band;
+ band_unset = 0;
+ break;
+ }
+ ptr++;
+ cur_band--;
+ }
+ if (band_unset)
+ mp->b_band = def_band;
+ /* It may be usable to urge SYN packets a bit */
+ if (syn)
+ mp->b_band++;
+ }
+#endif /* PRIOQ */
+ /* this assumes PPP_HDRLEN <= sizeof(dl_unitdata_req_t) */
+ if (mp->b_datap->db_ref > 1) {
+ np = allocb(PPP_HDRLEN, BPRI_HI);
+ if (np == 0)
+ break; /* gak! */
+ np->b_cont = mp->b_cont;
+ mp->b_cont = 0;
+ freeb(mp);
+ mp = np;
+ } else
+ mp->b_datap->db_type = M_DATA;
+ /* XXX should use dl_dest_addr_offset/length here,
+ but we would have to translate ETHERTYPE_IP -> PPP_IP */
+ mp->b_wptr = mp->b_rptr + PPP_HDRLEN;
+ mp->b_rptr[0] = PPP_ALLSTATIONS;
+ mp->b_rptr[1] = PPP_UI;
+ mp->b_rptr[2] = us->sap >> 8;
+ mp->b_rptr[3] = us->sap;
+ if (pass_packet(us, mp, 1)) {
+ if (!send_data(mp, us))
+ putq(q, mp);
+ }
+ return;
+
+#if DL_CURRENT_VERSION >= 2
+ case DL_PHYS_ADDR_REQ:
+ if (size < sizeof(dl_phys_addr_req_t))
+ goto badprim;
+
+ /*
+ * Don't check state because ifconfig sends this one down too
+ */
+
+ if ((reply = allocb(sizeof(dl_phys_addr_ack_t)+ETHERADDRL,
+ BPRI_HI)) == 0)
+ break; /* should do bufcall */
+ reply->b_datap->db_type = M_PCPROTO;
+ paddrack = (dl_phys_addr_ack_t *) reply->b_wptr;
+ reply->b_wptr += sizeof(dl_phys_addr_ack_t);
+ bzero((caddr_t) paddrack, sizeof(dl_phys_addr_ack_t)+ETHERADDRL);
+ paddrack->dl_primitive = DL_PHYS_ADDR_ACK;
+ paddrack->dl_addr_length = ETHERADDRL;
+ paddrack->dl_addr_offset = sizeof(dl_phys_addr_ack_t);
+ bcopy(&eaddr, reply->b_wptr, ETHERADDRL);
+ reply->b_wptr += ETHERADDRL;
+ qreply(q, reply);
+ break;
+
+#if defined(SOL2)
+ case DL_PROMISCON_REQ:
+ if (size < sizeof(dl_promiscon_req_t))
+ goto badprim;
+ us->flags |= US_PROMISC;
+ dlpi_ok(q, DL_PROMISCON_REQ);
+ break;
+
+ case DL_PROMISCOFF_REQ:
+ if (size < sizeof(dl_promiscoff_req_t))
+ goto badprim;
+ us->flags &= ~US_PROMISC;
+ dlpi_ok(q, DL_PROMISCOFF_REQ);
+ break;
+#else
+ case DL_PROMISCON_REQ: /* fall thru */
+ case DL_PROMISCOFF_REQ: /* fall thru */
+#endif /* defined(SOL2) */
+#endif /* DL_CURRENT_VERSION >= 2 */
+
+#if DL_CURRENT_VERSION >= 2
+ case DL_SET_PHYS_ADDR_REQ:
+ case DL_SUBS_BIND_REQ:
+ case DL_SUBS_UNBIND_REQ:
+ case DL_ENABMULTI_REQ:
+ case DL_DISABMULTI_REQ:
+ case DL_XID_REQ:
+ case DL_TEST_REQ:
+ case DL_REPLY_UPDATE_REQ:
+ case DL_REPLY_REQ:
+ case DL_DATA_ACK_REQ:
+#endif
+ case DL_CONNECT_REQ:
+ case DL_TOKEN_REQ:
+ dlpi_error(q, us, d->dl_primitive, DL_NOTSUPPORTED, 0);
+ break;
+
+ case DL_CONNECT_RES:
+ case DL_DISCONNECT_REQ:
+ case DL_RESET_REQ:
+ case DL_RESET_RES:
+ dlpi_error(q, us, d->dl_primitive, DL_OUTSTATE, 0);
+ break;
+
+ case DL_UDQOS_REQ:
+ dlpi_error(q, us, d->dl_primitive, DL_BADQOSTYPE, 0);
+ break;
+
+#if DL_CURRENT_VERSION >= 2
+ case DL_TEST_RES:
+ case DL_XID_RES:
+ break;
+#endif
+
+ default:
+ cmn_err(CE_CONT, "ppp: unknown dlpi prim 0x%x\n", d->dl_primitive);
+ /* fall through */
+ badprim:
+ dlpi_error(q, us, d->dl_primitive, DL_BADPRIM, 0);
+ break;
+ }
+ freemsg(mp);
+}
+
+static void
+dlpi_error(q, us, prim, err, uerr)
+ queue_t *q;
+ upperstr_t *us;
+ int prim, err, uerr;
+{
+ mblk_t *reply;
+ dl_error_ack_t *errp;
+
+ if (us->flags & US_DBGLOG)
+ DPRINT3("ppp/%d: dlpi error, prim=%x, err=%x\n", us->mn, prim, err);
+ reply = allocb(sizeof(dl_error_ack_t), BPRI_HI);
+ if (reply == 0)
+ return; /* XXX should do bufcall */
+ reply->b_datap->db_type = M_PCPROTO;
+ errp = (dl_error_ack_t *) reply->b_wptr;
+ reply->b_wptr += sizeof(dl_error_ack_t);
+ errp->dl_primitive = DL_ERROR_ACK;
+ errp->dl_error_primitive = prim;
+ errp->dl_errno = err;
+ errp->dl_unix_errno = uerr;
+ qreply(q, reply);
+}
+
+static void
+dlpi_ok(q, prim)
+ queue_t *q;
+ int prim;
+{
+ mblk_t *reply;
+ dl_ok_ack_t *okp;
+
+ reply = allocb(sizeof(dl_ok_ack_t), BPRI_HI);
+ if (reply == 0)
+ return; /* XXX should do bufcall */
+ reply->b_datap->db_type = M_PCPROTO;
+ okp = (dl_ok_ack_t *) reply->b_wptr;
+ reply->b_wptr += sizeof(dl_ok_ack_t);
+ okp->dl_primitive = DL_OK_ACK;
+ okp->dl_correct_primitive = prim;
+ qreply(q, reply);
+}
+#endif /* NO_DLPI */
+
+static int
+pass_packet(us, mp, outbound)
+ upperstr_t *us;
+ mblk_t *mp;
+ int outbound;
+{
+ int pass;
+ upperstr_t *ppa;
+
+ if ((ppa = us->ppa) == 0) {
+ freemsg(mp);
+ return 0;
+ }
+
+#ifdef FILTER_PACKETS
+ pass = ip_hard_filter(us, mp, outbound);
+#else
+ /*
+ * Here is where we might, in future, decide whether to pass
+ * or drop the packet, and whether it counts as link activity.
+ */
+ pass = 1;
+#endif /* FILTER_PACKETS */
+
+ if (pass < 0) {
+ /* pass only if link already up, and don't update time */
+ if (ppa->lowerq == 0) {
+ freemsg(mp);
+ return 0;
+ }
+ pass = 1;
+ } else if (pass) {
+ if (outbound)
+ ppa->last_sent = time;
+ else
+ ppa->last_recv = time;
+ }
+
+ return pass;
+}
+
+/*
+ * We have some data to send down to the lower stream (or up the
+ * control stream, if we don't have a lower stream attached).
+ * Returns 1 if the message was dealt with, 0 if it wasn't able
+ * to be sent on and should therefore be queued up.
+ */
+static int
+send_data(mp, us)
+ mblk_t *mp;
+ upperstr_t *us;
+{
+ upperstr_t *ppa;
+
+ if ((us->flags & US_BLOCKED) || us->npmode == NPMODE_QUEUE)
+ return 0;
+ ppa = us->ppa;
+ if (ppa == 0 || us->npmode == NPMODE_DROP || us->npmode == NPMODE_ERROR) {
+ if (us->flags & US_DBGLOG)
+ DPRINT2("ppp/%d: dropping pkt (npmode=%d)\n", us->mn, us->npmode);
+ freemsg(mp);
+ return 1;
+ }
+ if (ppa->lowerq == 0) {
+ /* try to send it up the control stream */
+ if (bcanputnext(ppa->q, mp->b_band)) {
+ /*
+ * The message seems to get corrupted for some reason if
+ * we just send the message up as it is, so we send a copy.
+ */
+ mblk_t *np = copymsg(mp);
+ freemsg(mp);
+ if (np != 0)
+ putnext(ppa->q, np);
+ return 1;
+ }
+ } else {
+ if (bcanputnext(ppa->lowerq, mp->b_band)) {
+ MT_ENTER(&ppa->stats_lock);
+ ppa->stats.ppp_opackets++;
+ ppa->stats.ppp_obytes += msgdsize(mp);
+#ifdef INCR_OPACKETS
+ INCR_OPACKETS(ppa);
+#endif
+ MT_EXIT(&ppa->stats_lock);
+ /*
+ * The lower queue is only ever detached while holding an
+ * exclusive lock on the whole driver. So we can be confident
+ * that the lower queue is still there.
+ */
+ putnext(ppa->lowerq, mp);
+ return 1;
+ }
+ }
+ us->flags |= US_BLOCKED;
+ return 0;
+}
+
+/*
+ * Allocate a new PPA id and link this stream into the list of PPAs.
+ * This procedure is called with an exclusive lock on all queues in
+ * this driver.
+ */
+static void
+new_ppa(q, mp)
+ queue_t *q;
+ mblk_t *mp;
+{
+ upperstr_t *us, *up, **usp;
+ int ppa_id;
+
+ us = (upperstr_t *) q->q_ptr;
+ if (us == 0) {
+ DPRINT("new_ppa: q_ptr = 0!\n");
+ return;
+ }
+
+ usp = &ppas;
+ ppa_id = 0;
+ while ((up = *usp) != 0 && ppa_id == up->ppa_id) {
+ ++ppa_id;
+ usp = &up->nextppa;
+ }
+ us->ppa_id = ppa_id;
+ us->ppa = us;
+ us->next = 0;
+ us->nextppa = *usp;
+ *usp = us;
+ us->flags |= US_CONTROL;
+ us->npmode = NPMODE_PASS;
+
+ us->mtu = PPP_MTU;
+ us->mru = PPP_MRU;
+
+#ifdef SOL2
+ /*
+ * Create a kstats record for our statistics, so netstat -i works.
+ */
+ if (us->kstats == 0) {
+ char unit[32];
+
+ sprintf(unit, "ppp%d", us->ppa->ppa_id);
+ us->kstats = kstat_create("ppp", us->ppa->ppa_id, unit,
+ "net", KSTAT_TYPE_NAMED, 4, 0);
+ if (us->kstats != 0) {
+ kstat_named_t *kn = KSTAT_NAMED_PTR(us->kstats);
+
+ strcpy(kn[0].name, "ipackets");
+ kn[0].data_type = KSTAT_DATA_ULONG;
+ strcpy(kn[1].name, "ierrors");
+ kn[1].data_type = KSTAT_DATA_ULONG;
+ strcpy(kn[2].name, "opackets");
+ kn[2].data_type = KSTAT_DATA_ULONG;
+ strcpy(kn[3].name, "oerrors");
+ kn[3].data_type = KSTAT_DATA_ULONG;
+ kstat_install(us->kstats);
+ }
+ }
+#endif /* SOL2 */
+
+ *(int *)mp->b_cont->b_rptr = ppa_id;
+ mp->b_datap->db_type = M_IOCACK;
+ qreply(q, mp);
+}
+
+static void
+attach_ppa(q, mp)
+ queue_t *q;
+ mblk_t *mp;
+{
+ upperstr_t *us, *t;
+
+ us = (upperstr_t *) q->q_ptr;
+ if (us == 0) {
+ DPRINT("attach_ppa: q_ptr = 0!\n");
+ return;
+ }
+
+#ifndef NO_DLPI
+ us->state = DL_UNBOUND;
+#endif
+ for (t = us->ppa; t->next != 0; t = t->next)
+ ;
+ t->next = us;
+ us->next = 0;
+ if (mp->b_datap->db_type == M_IOCTL) {
+ mp->b_datap->db_type = M_IOCACK;
+ qreply(q, mp);
+ } else {
+#ifndef NO_DLPI
+ dlpi_ok(q, DL_ATTACH_REQ);
+#endif
+ }
+}
+
+static void
+detach_ppa(q, mp)
+ queue_t *q;
+ mblk_t *mp;
+{
+ upperstr_t *us, *t;
+
+ us = (upperstr_t *) q->q_ptr;
+ if (us == 0) {
+ DPRINT("detach_ppa: q_ptr = 0!\n");
+ return;
+ }
+
+ for (t = us->ppa; t->next != 0; t = t->next)
+ if (t->next == us) {
+ t->next = us->next;
+ break;
+ }
+ us->next = 0;
+ us->ppa = 0;
+#ifndef NO_DLPI
+ us->state = DL_UNATTACHED;
+ dlpi_ok(q, DL_DETACH_REQ);
+#endif
+}
+
+/*
+ * We call this with qwriter in order to give the upper queue procedures
+ * the guarantee that the lower queue is not going to go away while
+ * they are executing.
+ */
+static void
+detach_lower(q, mp)
+ queue_t *q;
+ mblk_t *mp;
+{
+ upperstr_t *us;
+
+ us = (upperstr_t *) q->q_ptr;
+ if (us == 0) {
+ DPRINT("detach_lower: q_ptr = 0!\n");
+ return;
+ }
+
+ LOCK_LOWER_W;
+ us->lowerq->q_ptr = 0;
+ RD(us->lowerq)->q_ptr = 0;
+ us->lowerq = 0;
+ UNLOCK_LOWER;
+
+ /* Unblock streams which now feed back up the control stream. */
+ qenable(us->q);
+
+ mp->b_datap->db_type = M_IOCACK;
+ qreply(q, mp);
+}
+
+static int
+pppuwsrv(q)
+ queue_t *q;
+{
+ upperstr_t *us, *as;
+ mblk_t *mp;
+
+ us = (upperstr_t *) q->q_ptr;
+ if (us == 0) {
+ DPRINT("pppuwsrv: q_ptr = 0!\n");
+ return 0;
+ }
+
+ /*
+ * If this is a control stream, then this service procedure
+ * probably got enabled because of flow control in the lower
+ * stream being enabled (or because of the lower stream going
+ * away). Therefore we enable the service procedure of all
+ * attached upper streams.
+ */
+ if (us->flags & US_CONTROL) {
+ for (as = us->next; as != 0; as = as->next)
+ qenable(WR(as->q));
+ }
+
+ /* Try to send on any data queued here. */
+ us->flags &= ~US_BLOCKED;
+ while ((mp = getq(q)) != 0) {
+ if (!send_data(mp, us)) {
+ putbq(q, mp);
+ break;
+ }
+ }
+
+ return 0;
+}
+
+/* should never get called... */
+static int
+ppplwput(q, mp)
+ queue_t *q;
+ mblk_t *mp;
+{
+ putnext(q, mp);
+ return 0;
+}
+
+static int
+ppplwsrv(q)
+ queue_t *q;
+{
+ queue_t *uq;
+
+ /*
+ * Flow control has back-enabled this stream:
+ * enable the upper write service procedure for
+ * the upper control stream for this lower stream.
+ */
+ LOCK_LOWER_R;
+ uq = (queue_t *) q->q_ptr;
+ if (uq != 0)
+ qenable(uq);
+ UNLOCK_LOWER;
+ return 0;
+}
+
+/*
+ * This should only get called for control streams.
+ */
+static int
+pppurput(q, mp)
+ queue_t *q;
+ mblk_t *mp;
+{
+ upperstr_t *ppa, *us;
+ int proto, len;
+ struct iocblk *iop;
+
+ ppa = (upperstr_t *) q->q_ptr;
+ if (ppa == 0) {
+ DPRINT("pppurput: q_ptr = 0!\n");
+ return 0;
+ }
+
+ switch (mp->b_datap->db_type) {
+ case M_CTL:
+ MT_ENTER(&ppa->stats_lock);
+ switch (*mp->b_rptr) {
+ case PPPCTL_IERROR:
+#ifdef INCR_IERRORS
+ INCR_IERRORS(ppa);
+#endif
+ ppa->stats.ppp_ierrors++;
+ break;
+ case PPPCTL_OERROR:
+#ifdef INCR_OERRORS
+ INCR_OERRORS(ppa);
+#endif
+ ppa->stats.ppp_oerrors++;
+ break;
+ }
+ MT_EXIT(&ppa->stats_lock);
+ freemsg(mp);
+ break;
+
+ case M_IOCACK:
+ case M_IOCNAK:
+ /*
+ * Attempt to match up the response with the stream
+ * that the request came from.
+ */
+ iop = (struct iocblk *) mp->b_rptr;
+ for (us = ppa; us != 0; us = us->next)
+ if (us->ioc_id == iop->ioc_id)
+ break;
+ if (us == 0)
+ freemsg(mp);
+ else
+ putnext(us->q, mp);
+ break;
+
+ case M_HANGUP:
+ /*
+ * The serial device has hung up. We don't want to send
+ * the M_HANGUP message up to pppd because that will stop
+ * us from using the control stream any more. Instead we
+ * send a zero-length message as an end-of-file indication.
+ */
+ freemsg(mp);
+ mp = allocb(1, BPRI_HI);
+ if (mp == 0) {
+ DPRINT1("ppp/%d: couldn't allocate eof message!\n", ppa->mn);
+ break;
+ }
+ putnext(ppa->q, mp);
+ break;
+
+ default:
+ if (mp->b_datap->db_type == M_DATA) {
+ len = msgdsize(mp);
+ if (mp->b_wptr - mp->b_rptr < PPP_HDRLEN) {
+ PULLUP(mp, PPP_HDRLEN);
+ if (mp == 0) {
+ DPRINT1("ppp_urput: msgpullup failed (len=%d)\n", len);
+ break;
+ }
+ }
+ MT_ENTER(&ppa->stats_lock);
+ ppa->stats.ppp_ipackets++;
+ ppa->stats.ppp_ibytes += len;
+#ifdef INCR_IPACKETS
+ INCR_IPACKETS(ppa);
+#endif
+ MT_EXIT(&ppa->stats_lock);
+
+ proto = PPP_PROTOCOL(mp->b_rptr);
+
+#if defined(SOL2)
+ /*
+ * Should there be any promiscuous stream(s), send the data
+ * up for each promiscuous stream that we recognize.
+ */
+ promisc_sendup(ppa, mp, proto, 1);
+#endif /* defined(SOL2) */
+
+ if (proto < 0x8000 && (us = find_dest(ppa, proto)) != 0) {
+ /*
+ * A data packet for some network protocol.
+ * Queue it on the upper stream for that protocol.
+ * XXX could we just putnext it? (would require thought)
+ * The rblocked flag is there to ensure that we keep
+ * messages in order for each network protocol.
+ */
+ if (!pass_packet(us, mp, 0))
+ break;
+ if (!us->rblocked && !canput(us->q))
+ us->rblocked = 1;
+ if (!us->rblocked)
+ putq(us->q, mp);
+ else
+ putq(q, mp);
+ break;
+ }
+ }
+ /*
+ * A control frame, a frame for an unknown protocol,
+ * or some other message type.
+ * Send it up to pppd via the control stream.
+ */
+ if (queclass(mp) == QPCTL || canputnext(ppa->q))
+ putnext(ppa->q, mp);
+ else
+ putq(q, mp);
+ break;
+ }
+
+ return 0;
+}
+
+static int
+pppursrv(q)
+ queue_t *q;
+{
+ upperstr_t *us, *as;
+ mblk_t *mp, *hdr;
+#ifndef NO_DLPI
+ dl_unitdata_ind_t *ud;
+#endif
+ int proto;
+
+ us = (upperstr_t *) q->q_ptr;
+ if (us == 0) {
+ DPRINT("pppursrv: q_ptr = 0!\n");
+ return 0;
+ }
+
+ if (us->flags & US_CONTROL) {
+ /*
+ * A control stream.
+ * If there is no lower queue attached, run the write service
+ * routines of other upper streams attached to this PPA.
+ */
+ if (us->lowerq == 0) {
+ as = us;
+ do {
+ if (as->flags & US_BLOCKED)
+ qenable(WR(as->q));
+ as = as->next;
+ } while (as != 0);
+ }
+
+ /*
+ * Messages get queued on this stream's read queue if they
+ * can't be queued on the read queue of the attached stream
+ * that they are destined for. This is for flow control -
+ * when this queue fills up, the lower read put procedure will
+ * queue messages there and the flow control will propagate
+ * down from there.
+ */
+ while ((mp = getq(q)) != 0) {
+ proto = PPP_PROTOCOL(mp->b_rptr);
+ if (proto < 0x8000 && (as = find_dest(us, proto)) != 0) {
+ if (!canput(as->q))
+ break;
+ putq(as->q, mp);
+ } else {
+ if (!canputnext(q))
+ break;
+ putnext(q, mp);
+ }
+ }
+ if (mp) {
+ putbq(q, mp);
+ } else {
+ /* can now put stuff directly on network protocol streams again */
+ for (as = us->next; as != 0; as = as->next)
+ as->rblocked = 0;
+ }
+
+ /*
+ * If this stream has a lower stream attached,
+ * enable the read queue's service routine.
+ * XXX we should really only do this if the queue length
+ * has dropped below the low-water mark.
+ */
+ if (us->lowerq != 0)
+ qenable(RD(us->lowerq));
+
+ } else {
+ /*
+ * A network protocol stream. Put a DLPI header on each
+ * packet and send it on.
+ * (Actually, it seems that the IP module will happily
+ * accept M_DATA messages without the DL_UNITDATA_IND header.)
+ */
+ while ((mp = getq(q)) != 0) {
+ if (!canputnext(q)) {
+ putbq(q, mp);
+ break;
+ }
+#ifndef NO_DLPI
+ proto = PPP_PROTOCOL(mp->b_rptr);
+ mp->b_rptr += PPP_HDRLEN;
+ hdr = allocb(sizeof(dl_unitdata_ind_t) + 2 * sizeof(uint),
+ BPRI_MED);
+ if (hdr == 0) {
+ /* XXX should put it back and use bufcall */
+ freemsg(mp);
+ continue;
+ }
+ hdr->b_datap->db_type = M_PROTO;
+ ud = (dl_unitdata_ind_t *) hdr->b_wptr;
+ hdr->b_wptr += sizeof(dl_unitdata_ind_t) + 2 * sizeof(uint);
+ hdr->b_cont = mp;
+ ud->dl_primitive = DL_UNITDATA_IND;
+ ud->dl_dest_addr_length = sizeof(uint);
+ ud->dl_dest_addr_offset = sizeof(dl_unitdata_ind_t);
+ ud->dl_src_addr_length = sizeof(uint);
+ ud->dl_src_addr_offset = ud->dl_dest_addr_offset + sizeof(uint);
+#if DL_CURRENT_VERSION >= 2
+ ud->dl_group_address = 0;
+#endif
+ /* Send the DLPI client the data with the SAP they requested,
+ (e.g. ETHERTYPE_IP) rather than the PPP protocol number
+ (e.g. PPP_IP) */
+ ((uint *)(ud + 1))[0] = us->req_sap; /* dest SAP */
+ ((uint *)(ud + 1))[1] = us->req_sap; /* src SAP */
+ putnext(q, hdr);
+#else /* NO_DLPI */
+ putnext(q, mp);
+#endif /* NO_DLPI */
+ }
+ /*
+ * Now that we have consumed some packets from this queue,
+ * enable the control stream's read service routine so that we
+ * can process any packets for us that might have got queued
+ * there for flow control reasons.
+ */
+ if (us->ppa)
+ qenable(us->ppa->q);
+ }
+
+ return 0;
+}
+
+static upperstr_t *
+find_dest(ppa, proto)
+ upperstr_t *ppa;
+ int proto;
+{
+ upperstr_t *us;
+
+ for (us = ppa->next; us != 0; us = us->next)
+ if (proto == us->sap)
+ break;
+ return us;
+}
+
+#if defined (SOL2)
+/*
+ * Test upstream promiscuous conditions. As of now, only pass IPv4 and
+ * Ipv6 packets upstream (let PPP packets be decoded elsewhere).
+ */
+static upperstr_t *
+find_promisc(us, proto)
+ upperstr_t *us;
+ int proto;
+{
+
+ if ((proto != PPP_IP) && (proto != PPP_IPV6))
+ return (upperstr_t *)0;
+
+ for ( ; us; us = us->next) {
+ if ((us->flags & US_PROMISC) && (us->state == DL_IDLE))
+ return us;
+ }
+
+ return (upperstr_t *)0;
+}
+
+/*
+ * Prepend an empty Ethernet header to msg for snoop, et al.
+ */
+static mblk_t *
+prepend_ether(us, mp, proto)
+ upperstr_t *us;
+ mblk_t *mp;
+ int proto;
+{
+ mblk_t *eh;
+ int type;
+
+ if ((eh = allocb(sizeof(struct ether_header), BPRI_HI)) == 0) {
+ freemsg(mp);
+ return (mblk_t *)0;
+ }
+
+ if (proto == PPP_IP)
+ type = ETHERTYPE_IP;
+ else if (proto == PPP_IPV6)
+ type = ETHERTYPE_IPV6;
+ else
+ type = proto; /* What else? Let decoder decide */
+
+ eh->b_wptr += sizeof(struct ether_header);
+ bzero((caddr_t)eh->b_rptr, sizeof(struct ether_header));
+ ((struct ether_header *)eh->b_rptr)->ether_type = htons((short)type);
+ eh->b_cont = mp;
+ return (eh);
+}
+
+/*
+ * Prepend DL_UNITDATA_IND mblk to msg
+ */
+static mblk_t *
+prepend_udind(us, mp, proto)
+ upperstr_t *us;
+ mblk_t *mp;
+ int proto;
+{
+ dl_unitdata_ind_t *dlu;
+ mblk_t *dh;
+ size_t size;
+
+ size = sizeof(dl_unitdata_ind_t);
+ if ((dh = allocb(size, BPRI_MED)) == 0) {
+ freemsg(mp);
+ return (mblk_t *)0;
+ }
+
+ dh->b_datap->db_type = M_PROTO;
+ dh->b_wptr = dh->b_datap->db_lim;
+ dh->b_rptr = dh->b_wptr - size;
+
+ dlu = (dl_unitdata_ind_t *)dh->b_rptr;
+ dlu->dl_primitive = DL_UNITDATA_IND;
+ dlu->dl_dest_addr_length = 0;
+ dlu->dl_dest_addr_offset = sizeof(dl_unitdata_ind_t);
+ dlu->dl_src_addr_length = 0;
+ dlu->dl_src_addr_offset = sizeof(dl_unitdata_ind_t);
+ dlu->dl_group_address = 0;
+
+ dh->b_cont = mp;
+ return (dh);
+}
+
+/*
+ * For any recognized promiscuous streams, send data upstream
+ */
+static void
+promisc_sendup(ppa, mp, proto, skip)
+ upperstr_t *ppa;
+ mblk_t *mp;
+ int proto, skip;
+{
+ mblk_t *dup_mp, *dup_dup_mp;
+ upperstr_t *prus, *nprus;
+
+ if ((prus = find_promisc(ppa, proto)) != 0) {
+ if (dup_mp = dupmsg(mp)) {
+
+ if (skip)
+ dup_mp->b_rptr += PPP_HDRLEN;
+
+ for ( ; nprus = find_promisc(prus->next, proto);
+ prus = nprus) {
+
+ if (dup_dup_mp = dupmsg(dup_mp)) {
+ if (canputnext(prus->q)) {
+ if (prus->flags & US_RAWDATA) {
+ dup_dup_mp = prepend_ether(prus, dup_dup_mp, proto);
+ putnext(prus->q, dup_dup_mp);
+ } else {
+ dup_dup_mp = prepend_udind(prus, dup_dup_mp, proto);
+ putnext(prus->q, dup_dup_mp);
+ }
+ } else {
+ DPRINT("ppp_urput: data to promisc q dropped\n");
+ freemsg(dup_dup_mp);
+ }
+ }
+ }
+
+ if (canputnext(prus->q)) {
+ if (prus->flags & US_RAWDATA) {
+ dup_mp = prepend_ether(prus, dup_mp, proto);
+ putnext(prus->q, dup_mp);
+ } else {
+ dup_mp = prepend_udind(prus, dup_mp, proto);
+ putnext(prus->q, dup_mp);
+ }
+ } else {
+ DPRINT("ppp_urput: data to promisc q dropped\n");
+ freemsg(dup_mp);
+ }
+ }
+ }
+}
+#endif /* defined(SOL2) */
+
+/*
+ * We simply put the message on to the associated upper control stream
+ * (either here or in ppplrsrv). That way we enter the perimeters
+ * before looking through the list of attached streams to decide which
+ * stream it should go up.
+ */
+static int
+ppplrput(q, mp)
+ queue_t *q;
+ mblk_t *mp;
+{
+ queue_t *uq;
+ struct iocblk *iop;
+
+ switch (mp->b_datap->db_type) {
+ case M_IOCTL:
+ iop = (struct iocblk *) mp->b_rptr;
+ iop->ioc_error = EINVAL;
+ mp->b_datap->db_type = M_IOCNAK;
+ qreply(q, mp);
+ return 0;
+ case M_FLUSH:
+ if (*mp->b_rptr & FLUSHR)
+ flushq(q, FLUSHDATA);
+ if (*mp->b_rptr & FLUSHW) {
+ *mp->b_rptr &= ~FLUSHR;
+ qreply(q, mp);
+ } else
+ freemsg(mp);
+ return 0;
+ }
+
+ /*
+ * If we can't get the lower lock straight away, queue this one
+ * rather than blocking, to avoid the possibility of deadlock.
+ */
+ if (!TRYLOCK_LOWER_R) {
+ putq(q, mp);
+ return 0;
+ }
+
+ /*
+ * Check that we're still connected to the driver.
+ */
+ uq = (queue_t *) q->q_ptr;
+ if (uq == 0) {
+ UNLOCK_LOWER;
+ DPRINT1("ppplrput: q = %x, uq = 0??\n", q);
+ freemsg(mp);
+ return 0;
+ }
+
+ /*
+ * Try to forward the message to the put routine for the upper
+ * control stream for this lower stream.
+ * If there are already messages queued here, queue this one so
+ * they don't get out of order.
+ */
+ if (queclass(mp) == QPCTL || (qsize(q) == 0 && canput(uq)))
+ put(uq, mp);
+ else
+ putq(q, mp);
+
+ UNLOCK_LOWER;
+ return 0;
+}
+
+static int
+ppplrsrv(q)
+ queue_t *q;
+{
+ mblk_t *mp;
+ queue_t *uq;
+
+ /*
+ * Packets get queued here for flow control reasons
+ * or if the lrput routine couldn't get the lower lock
+ * without blocking.
+ */
+ LOCK_LOWER_R;
+ uq = (queue_t *) q->q_ptr;
+ if (uq == 0) {
+ UNLOCK_LOWER;
+ flushq(q, FLUSHALL);
+ DPRINT1("ppplrsrv: q = %x, uq = 0??\n", q);
+ return 0;
+ }
+ while ((mp = getq(q)) != 0) {
+ if (queclass(mp) == QPCTL || canput(uq))
+ put(uq, mp);
+ else {
+ putbq(q, mp);
+ break;
+ }
+ }
+ UNLOCK_LOWER;
+ return 0;
+}
+
+static int
+putctl2(q, type, code, val)
+ queue_t *q;
+ int type, code, val;
+{
+ mblk_t *mp;
+
+ mp = allocb(2, BPRI_HI);
+ if (mp == 0)
+ return 0;
+ mp->b_datap->db_type = type;
+ mp->b_wptr[0] = code;
+ mp->b_wptr[1] = val;
+ mp->b_wptr += 2;
+ putnext(q, mp);
+ return 1;
+}
+
+static int
+putctl4(q, type, code, val)
+ queue_t *q;
+ int type, code, val;
+{
+ mblk_t *mp;
+
+ mp = allocb(4, BPRI_HI);
+ if (mp == 0)
+ return 0;
+ mp->b_datap->db_type = type;
+ mp->b_wptr[0] = code;
+ ((short *)mp->b_wptr)[1] = val;
+ mp->b_wptr += 4;
+ putnext(q, mp);
+ return 1;
+}
+
+static void
+debug_dump(q, mp)
+ queue_t *q;
+ mblk_t *mp;
+{
+ upperstr_t *us;
+ queue_t *uq, *lq;
+
+ DPRINT("ppp upper streams:\n");
+ for (us = minor_devs; us != 0; us = us->nextmn) {
+ uq = us->q;
+ DPRINT3(" %d: q=%x rlev=%d",
+ us->mn, uq, (uq? qsize(uq): 0));
+ DPRINT3(" wlev=%d flags=0x%b", (uq? qsize(WR(uq)): 0),
+ us->flags, "\020\1priv\2control\3blocked\4last");
+ DPRINT3(" state=%x sap=%x req_sap=%x", us->state, us->sap,
+ us->req_sap);
+ if (us->ppa == 0)
+ DPRINT(" ppa=?\n");
+ else
+ DPRINT1(" ppa=%d\n", us->ppa->ppa_id);
+ if (us->flags & US_CONTROL) {
+ lq = us->lowerq;
+ DPRINT3(" control for %d lq=%x rlev=%d",
+ us->ppa_id, lq, (lq? qsize(RD(lq)): 0));
+ DPRINT3(" wlev=%d mru=%d mtu=%d\n",
+ (lq? qsize(lq): 0), us->mru, us->mtu);
+ }
+ }
+ mp->b_datap->db_type = M_IOCACK;
+ qreply(q, mp);
+}
+
+#ifdef FILTER_PACKETS
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/udp.h>
+#include <netinet/tcp.h>
+
+#define MAX_IPHDR 128 /* max TCP/IP header size */
+
+
+/* The following table contains a hard-coded list of protocol/port pairs.
+ * Any matching packets are either discarded unconditionally, or,
+ * if ok_if_link_up is non-zero when a connection does not currently exist
+ * (i.e., they go through if the connection is present, but never initiate
+ * a dial-out).
+ * This idea came from a post by dm@garage.uun.org (David Mazieres)
+ */
+static struct pktfilt_tab {
+ int proto;
+ u_short port;
+ u_short ok_if_link_up;
+} pktfilt_tab[] = {
+ { IPPROTO_UDP, 520, 1 }, /* RIP, ok to pass if link is up */
+ { IPPROTO_UDP, 123, 1 }, /* NTP, don't keep up the link for it */
+ { -1, 0, 0 } /* terminator entry has port == -1 */
+};
+
+
+static int
+ip_hard_filter(us, mp, outbound)
+ upperstr_t *us;
+ mblk_t *mp;
+ int outbound;
+{
+ struct ip *ip;
+ struct pktfilt_tab *pft;
+ mblk_t *temp_mp;
+ int proto;
+ int len, hlen;
+
+
+ /* Note, the PPP header has already been pulled up in all cases */
+ proto = PPP_PROTOCOL(mp->b_rptr);
+ if (us->flags & US_DBGLOG)
+ DPRINT3("ppp/%d: filter, proto=0x%x, out=%d\n", us->mn, proto, outbound);
+
+ switch (proto)
+ {
+ case PPP_IP:
+ if ((mp->b_wptr - mp->b_rptr) == PPP_HDRLEN && mp->b_cont != 0) {
+ temp_mp = mp->b_cont;
+ len = msgdsize(temp_mp);
+ hlen = (len < MAX_IPHDR) ? len : MAX_IPHDR;
+ PULLUP(temp_mp, hlen);
+ if (temp_mp == 0) {
+ DPRINT2("ppp/%d: filter, pullup next failed, len=%d\n",
+ us->mn, hlen);
+ mp->b_cont = 0; /* PULLUP() freed the rest */
+ freemsg(mp);
+ return 0;
+ }
+ ip = (struct ip *)mp->b_cont->b_rptr;
+ }
+ else {
+ len = msgdsize(mp);
+ hlen = (len < (PPP_HDRLEN+MAX_IPHDR)) ? len : (PPP_HDRLEN+MAX_IPHDR);
+ PULLUP(mp, hlen);
+ if (mp == 0) {
+ DPRINT2("ppp/%d: filter, pullup failed, len=%d\n",
+ us->mn, hlen);
+ return 0;
+ }
+ ip = (struct ip *)(mp->b_rptr + PPP_HDRLEN);
+ }
+
+ /* For IP traffic, certain packets (e.g., RIP) may be either
+ * 1. ignored - dropped completely
+ * 2. will not initiate a connection, but
+ * will be passed if a connection is currently up.
+ */
+ for (pft=pktfilt_tab; pft->proto != -1; pft++) {
+ if (ip->ip_p == pft->proto) {
+ switch(pft->proto) {
+ case IPPROTO_UDP:
+ if (((struct udphdr *) &((int *)ip)[ip->ip_hl])->uh_dport
+ == htons(pft->port)) goto endfor;
+ break;
+ case IPPROTO_TCP:
+ if (((struct tcphdr *) &((int *)ip)[ip->ip_hl])->th_dport
+ == htons(pft->port)) goto endfor;
+ break;
+ }
+ }
+ }
+ endfor:
+ if (pft->proto != -1) {
+ if (us->flags & US_DBGLOG)
+ DPRINT3("ppp/%d: found IP pkt, proto=0x%x (%d)\n",
+ us->mn, pft->proto, pft->port);
+ /* Discard if not connected, or if not pass_with_link_up */
+ /* else, if link is up let go by, but don't update time */
+ return pft->ok_if_link_up? -1: 0;
+ }
+ break;
+ } /* end switch (proto) */
+
+ return 1;
+}
+#endif /* FILTER_PACKETS */
+
diff --git a/mdk-stage1/ppp/modules/ppp_ahdlc.c b/mdk-stage1/ppp/modules/ppp_ahdlc.c
new file mode 100644
index 000000000..e3c4baa28
--- /dev/null
+++ b/mdk-stage1/ppp/modules/ppp_ahdlc.c
@@ -0,0 +1,878 @@
+/*
+ * ppp_ahdlc.c - STREAMS module for doing PPP asynchronous HDLC.
+ *
+ * Re-written by Adi Masputra <adi.masputra@sun.com>, based on
+ * the original ppp_ahdlc.c
+ *
+ * Copyright (c) 2000 by Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation is hereby granted, provided that the above copyright
+ * notice appears in all copies.
+ *
+ * SUN MAKES NO REPRESENTATION OR WARRANTIES ABOUT THE SUITABILITY OF
+ * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
+ * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES
+ *
+ * Copyright (c) 1994 The Australian National University.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation is hereby granted, provided that the above copyright
+ * notice appears in all copies. This software is provided without any
+ * warranty, express or implied. The Australian National University
+ * makes no representations about the suitability of this software for
+ * any purpose.
+ *
+ * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
+ * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
+ * THE AUSTRALIAN NATIONAL UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
+ * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
+ * OR MODIFICATIONS.
+ *
+ * $Id: ppp_ahdlc.c 195720 2001-06-11 11:44:34Z gc $
+ */
+
+/*
+ * This file is used under Solaris 2, SVR4, SunOS 4, and Digital UNIX.
+ */
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/stream.h>
+#include <sys/errno.h>
+
+#ifdef SVR4
+#include <sys/conf.h>
+#include <sys/kmem.h>
+#include <sys/cmn_err.h>
+#include <sys/ddi.h>
+#else
+#include <sys/user.h>
+#ifdef __osf__
+#include <sys/cmn_err.h>
+#endif
+#endif /* SVR4 */
+
+#include <net/ppp_defs.h>
+#include <net/pppio.h>
+#include "ppp_mod.h"
+
+/*
+ * Right now, mutex is only enabled for Solaris 2.x
+ */
+#if defined(SOL2)
+#define USE_MUTEX
+#endif /* SOL2 */
+
+/*
+ * intpointer_t and uintpointer_t are signed and unsigned integer types
+ * large enough to hold any data pointer; that is, data pointers can be
+ * assigned into or from these integer types without losing precision.
+ * On recent Solaris releases, these types are defined in sys/int_types.h,
+ * but not on SunOS 4.x or the earlier Solaris versions.
+ */
+#if defined(_LP64) || defined(_I32LPx)
+typedef long intpointer_t;
+typedef unsigned long uintpointer_t;
+#else
+typedef int intpointer_t;
+typedef unsigned int uintpointer_t;
+#endif
+
+MOD_OPEN_DECL(ahdlc_open);
+MOD_CLOSE_DECL(ahdlc_close);
+static int ahdlc_wput __P((queue_t *, mblk_t *));
+static int ahdlc_rput __P((queue_t *, mblk_t *));
+static void ahdlc_encode __P((queue_t *, mblk_t *));
+static void ahdlc_decode __P((queue_t *, mblk_t *));
+static int msg_byte __P((mblk_t *, unsigned int));
+
+#if defined(SOL2)
+/*
+ * Don't send HDLC start flag is last transmit is within 1.5 seconds -
+ * FLAG_TIME is defined is microseconds
+ */
+#define FLAG_TIME 1500
+#define ABS(x) (x >= 0 ? x : (-x))
+#endif /* SOL2 */
+
+/*
+ * Extract byte i of message mp
+ */
+#define MSG_BYTE(mp, i) ((i) < (mp)->b_wptr - (mp)->b_rptr? (mp)->b_rptr[i]: \
+ msg_byte((mp), (i)))
+
+/*
+ * Is this LCP packet one we have to transmit using LCP defaults?
+ */
+#define LCP_USE_DFLT(mp) (1 <= (code = MSG_BYTE((mp), 4)) && code <= 7)
+
+/*
+ * Standard STREAMS declarations
+ */
+static struct module_info minfo = {
+ 0x7d23, "ppp_ahdl", 0, INFPSZ, 32768, 512
+};
+
+static struct qinit rinit = {
+ ahdlc_rput, NULL, ahdlc_open, ahdlc_close, NULL, &minfo, NULL
+};
+
+static struct qinit winit = {
+ ahdlc_wput, NULL, NULL, NULL, NULL, &minfo, NULL
+};
+
+#if defined(SVR4) && !defined(SOL2)
+int phdldevflag = 0;
+#define ppp_ahdlcinfo phdlinfo
+#endif /* defined(SVR4) && !defined(SOL2) */
+
+struct streamtab ppp_ahdlcinfo = {
+ &rinit, /* ptr to st_rdinit */
+ &winit, /* ptr to st_wrinit */
+ NULL, /* ptr to st_muxrinit */
+ NULL, /* ptr to st_muxwinit */
+#if defined(SUNOS4)
+ NULL /* ptr to ptr to st_modlist */
+#endif /* SUNOS4 */
+};
+
+#if defined(SUNOS4)
+int ppp_ahdlc_count = 0; /* open counter */
+#endif /* SUNOS4 */
+
+/*
+ * Per-stream state structure
+ */
+typedef struct ahdlc_state {
+#if defined(USE_MUTEX)
+ kmutex_t lock; /* lock for this structure */
+#endif /* USE_MUTEX */
+ int flags; /* link flags */
+ mblk_t *rx_buf; /* ptr to receive buffer */
+ int rx_buf_size; /* receive buffer size */
+ ushort_t infcs; /* calculated rx HDLC FCS */
+ u_int32_t xaccm[8]; /* 256-bit xmit ACCM */
+ u_int32_t raccm; /* 32-bit rcv ACCM */
+ int mtu; /* interface MTU */
+ int mru; /* link MRU */
+ int unit; /* current PPP unit number */
+ struct pppstat stats; /* statistic structure */
+#if defined(SOL2)
+ clock_t flag_time; /* time in usec between flags */
+ clock_t lbolt; /* last updated lbolt */
+#endif /* SOL2 */
+} ahdlc_state_t;
+
+/*
+ * Values for flags
+ */
+#define ESCAPED 0x100 /* last saw escape char on input */
+#define IFLUSH 0x200 /* flushing input due to error */
+
+/*
+ * RCV_B7_1, etc., defined in net/pppio.h, are stored in flags also.
+ */
+#define RCV_FLAGS (RCV_B7_1|RCV_B7_0|RCV_ODDP|RCV_EVNP)
+
+/*
+ * FCS lookup table as calculated by genfcstab.
+ */
+static u_short fcstab[256] = {
+ 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
+ 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
+ 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
+ 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
+ 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
+ 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
+ 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
+ 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
+ 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
+ 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
+ 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
+ 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
+ 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
+ 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
+ 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
+ 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
+ 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
+ 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
+ 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
+ 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
+ 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
+ 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
+ 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
+ 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
+ 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
+ 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
+ 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
+ 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
+ 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
+ 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
+ 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
+ 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
+};
+
+static u_int32_t paritytab[8] =
+{
+ 0x96696996, 0x69969669, 0x69969669, 0x96696996,
+ 0x69969669, 0x96696996, 0x96696996, 0x69969669
+};
+
+/*
+ * STREAMS module open (entry) point
+ */
+MOD_OPEN(ahdlc_open)
+{
+ ahdlc_state_t *state;
+
+ /*
+ * Return if it's already opened
+ */
+ if (q->q_ptr) {
+ return 0;
+ }
+
+ /*
+ * This can only be opened as a module
+ */
+ if (sflag != MODOPEN) {
+ return 0;
+ }
+
+ state = (ahdlc_state_t *) ALLOC_NOSLEEP(sizeof(ahdlc_state_t));
+ if (state == 0)
+ OPEN_ERROR(ENOSR);
+ bzero((caddr_t) state, sizeof(ahdlc_state_t));
+
+ q->q_ptr = (caddr_t) state;
+ WR(q)->q_ptr = (caddr_t) state;
+
+#if defined(USE_MUTEX)
+ mutex_init(&state->lock, NULL, MUTEX_DEFAULT, NULL);
+ mutex_enter(&state->lock);
+#endif /* USE_MUTEX */
+
+ state->xaccm[0] = ~0; /* escape 0x00 through 0x1f */
+ state->xaccm[3] = 0x60000000; /* escape 0x7d and 0x7e */
+ state->mru = PPP_MRU; /* default of 1500 bytes */
+#if defined(SOL2)
+ state->flag_time = drv_usectohz(FLAG_TIME);
+#endif /* SOL2 */
+
+#if defined(USE_MUTEX)
+ mutex_exit(&state->lock);
+#endif /* USE_MUTEX */
+
+#if defined(SUNOS4)
+ ppp_ahdlc_count++;
+#endif /* SUNOS4 */
+
+ qprocson(q);
+
+ return 0;
+}
+
+/*
+ * STREAMS module close (exit) point
+ */
+MOD_CLOSE(ahdlc_close)
+{
+ ahdlc_state_t *state;
+
+ qprocsoff(q);
+
+ state = (ahdlc_state_t *) q->q_ptr;
+
+ if (state == 0) {
+ DPRINT("state == 0 in ahdlc_close\n");
+ return 0;
+ }
+
+#if defined(USE_MUTEX)
+ mutex_enter(&state->lock);
+#endif /* USE_MUTEX */
+
+ if (state->rx_buf != 0) {
+ freemsg(state->rx_buf);
+ state->rx_buf = 0;
+ }
+
+#if defined(USE_MUTEX)
+ mutex_exit(&state->lock);
+ mutex_destroy(&state->lock);
+#endif /* USE_MUTEX */
+
+ FREE(q->q_ptr, sizeof(ahdlc_state_t));
+ q->q_ptr = NULL;
+ OTHERQ(q)->q_ptr = NULL;
+
+#if defined(SUNOS4)
+ if (ppp_ahdlc_count)
+ ppp_ahdlc_count--;
+#endif /* SUNOS4 */
+
+ return 0;
+}
+
+/*
+ * Write side put routine
+ */
+static int
+ahdlc_wput(q, mp)
+ queue_t *q;
+ mblk_t *mp;
+{
+ ahdlc_state_t *state;
+ struct iocblk *iop;
+ int error;
+ mblk_t *np;
+ struct ppp_stats *psp;
+
+ state = (ahdlc_state_t *) q->q_ptr;
+ if (state == 0) {
+ DPRINT("state == 0 in ahdlc_wput\n");
+ freemsg(mp);
+ return 0;
+ }
+
+ switch (mp->b_datap->db_type) {
+ case M_DATA:
+ /*
+ * A data packet - do character-stuffing and FCS, and
+ * send it onwards.
+ */
+ ahdlc_encode(q, mp);
+ freemsg(mp);
+ break;
+
+ case M_IOCTL:
+ iop = (struct iocblk *) mp->b_rptr;
+ error = EINVAL;
+ switch (iop->ioc_cmd) {
+ case PPPIO_XACCM:
+ if ((iop->ioc_count < sizeof(u_int32_t)) ||
+ (iop->ioc_count > sizeof(ext_accm))) {
+ break;
+ }
+ if (mp->b_cont == 0) {
+ DPRINT1("ahdlc_wput/%d: PPPIO_XACCM b_cont = 0!\n", state->unit);
+ break;
+ }
+#if defined(USE_MUTEX)
+ mutex_enter(&state->lock);
+#endif /* USE_MUTEX */
+ bcopy((caddr_t)mp->b_cont->b_rptr, (caddr_t)state->xaccm,
+ iop->ioc_count);
+ state->xaccm[2] &= ~0x40000000; /* don't escape 0x5e */
+ state->xaccm[3] |= 0x60000000; /* do escape 0x7d, 0x7e */
+#if defined(USE_MUTEX)
+ mutex_exit(&state->lock);
+#endif /* USE_MUTEX */
+ iop->ioc_count = 0;
+ error = 0;
+ break;
+
+ case PPPIO_RACCM:
+ if (iop->ioc_count != sizeof(u_int32_t))
+ break;
+ if (mp->b_cont == 0) {
+ DPRINT1("ahdlc_wput/%d: PPPIO_RACCM b_cont = 0!\n", state->unit);
+ break;
+ }
+#if defined(USE_MUTEX)
+ mutex_enter(&state->lock);
+#endif /* USE_MUTEX */
+ bcopy((caddr_t)mp->b_cont->b_rptr, (caddr_t)&state->raccm,
+ sizeof(u_int32_t));
+#if defined(USE_MUTEX)
+ mutex_exit(&state->lock);
+#endif /* USE_MUTEX */
+ iop->ioc_count = 0;
+ error = 0;
+ break;
+
+ case PPPIO_GCLEAN:
+ np = allocb(sizeof(int), BPRI_HI);
+ if (np == 0) {
+ error = ENOSR;
+ break;
+ }
+ if (mp->b_cont != 0)
+ freemsg(mp->b_cont);
+ mp->b_cont = np;
+#if defined(USE_MUTEX)
+ mutex_enter(&state->lock);
+#endif /* USE_MUTEX */
+ *(int *)np->b_wptr = state->flags & RCV_FLAGS;
+#if defined(USE_MUTEX)
+ mutex_exit(&state->lock);
+#endif /* USE_MUTEX */
+ np->b_wptr += sizeof(int);
+ iop->ioc_count = sizeof(int);
+ error = 0;
+ break;
+
+ case PPPIO_GETSTAT:
+ np = allocb(sizeof(struct ppp_stats), BPRI_HI);
+ if (np == 0) {
+ error = ENOSR;
+ break;
+ }
+ if (mp->b_cont != 0)
+ freemsg(mp->b_cont);
+ mp->b_cont = np;
+ psp = (struct ppp_stats *) np->b_wptr;
+ np->b_wptr += sizeof(struct ppp_stats);
+ bzero((caddr_t)psp, sizeof(struct ppp_stats));
+ psp->p = state->stats;
+ iop->ioc_count = sizeof(struct ppp_stats);
+ error = 0;
+ break;
+
+ case PPPIO_LASTMOD:
+ /* we knew this anyway */
+ error = 0;
+ break;
+
+ default:
+ error = -1;
+ break;
+ }
+
+ if (error < 0)
+ putnext(q, mp);
+ else if (error == 0) {
+ mp->b_datap->db_type = M_IOCACK;
+ qreply(q, mp);
+ } else {
+ mp->b_datap->db_type = M_IOCNAK;
+ iop->ioc_count = 0;
+ iop->ioc_error = error;
+ qreply(q, mp);
+ }
+ break;
+
+ case M_CTL:
+ switch (*mp->b_rptr) {
+ case PPPCTL_MTU:
+#if defined(USE_MUTEX)
+ mutex_enter(&state->lock);
+#endif /* USE_MUTEX */
+ state->mtu = ((unsigned short *)mp->b_rptr)[1];
+#if defined(USE_MUTEX)
+ mutex_exit(&state->lock);
+#endif /* USE_MUTEX */
+ freemsg(mp);
+ break;
+ case PPPCTL_MRU:
+#if defined(USE_MUTEX)
+ mutex_enter(&state->lock);
+#endif /* USE_MUTEX */
+ state->mru = ((unsigned short *)mp->b_rptr)[1];
+#if defined(USE_MUTEX)
+ mutex_exit(&state->lock);
+#endif /* USE_MUTEX */
+ freemsg(mp);
+ break;
+ case PPPCTL_UNIT:
+#if defined(USE_MUTEX)
+ mutex_enter(&state->lock);
+#endif /* USE_MUTEX */
+ state->unit = mp->b_rptr[1];
+#if defined(USE_MUTEX)
+ mutex_exit(&state->lock);
+#endif /* USE_MUTEX */
+ break;
+ default:
+ putnext(q, mp);
+ }
+ break;
+
+ default:
+ putnext(q, mp);
+ }
+
+ return 0;
+}
+
+/*
+ * Read side put routine
+ */
+static int
+ahdlc_rput(q, mp)
+ queue_t *q;
+ mblk_t *mp;
+{
+ ahdlc_state_t *state;
+
+ state = (ahdlc_state_t *) q->q_ptr;
+ if (state == 0) {
+ DPRINT("state == 0 in ahdlc_rput\n");
+ freemsg(mp);
+ return 0;
+ }
+
+ switch (mp->b_datap->db_type) {
+ case M_DATA:
+ ahdlc_decode(q, mp);
+ freemsg(mp);
+ break;
+
+ case M_HANGUP:
+#if defined(USE_MUTEX)
+ mutex_enter(&state->lock);
+#endif /* USE_MUTEX */
+ if (state->rx_buf != 0) {
+ /* XXX would like to send this up for debugging */
+ freemsg(state->rx_buf);
+ state->rx_buf = 0;
+ }
+ state->flags = IFLUSH;
+#if defined(USE_MUTEX)
+ mutex_exit(&state->lock);
+#endif /* USE_MUTEX */
+ putnext(q, mp);
+ break;
+
+ default:
+ putnext(q, mp);
+ }
+ return 0;
+}
+
+/*
+ * Extract bit c from map m, to determine if c needs to be escaped
+ */
+#define IN_TX_MAP(c, m) ((m)[(c) >> 5] & (1 << ((c) & 0x1f)))
+
+static void
+ahdlc_encode(q, mp)
+ queue_t *q;
+ mblk_t *mp;
+{
+ ahdlc_state_t *state;
+ u_int32_t *xaccm, loc_xaccm[8];
+ ushort_t fcs;
+ size_t outmp_len;
+ mblk_t *outmp, *tmp;
+ uchar_t *dp, fcs_val;
+ int is_lcp, code;
+#if defined(SOL2)
+ clock_t lbolt;
+#endif /* SOL2 */
+
+ if (msgdsize(mp) < 4) {
+ return;
+ }
+
+ state = (ahdlc_state_t *)q->q_ptr;
+#if defined(USE_MUTEX)
+ mutex_enter(&state->lock);
+#endif /* USE_MUTEX */
+
+ /*
+ * Allocate an output buffer large enough to handle a case where all
+ * characters need to be escaped
+ */
+ outmp_len = (msgdsize(mp) << 1) + /* input block x 2 */
+ (sizeof(fcs) << 2) + /* HDLC FCS x 4 */
+ (sizeof(uchar_t) << 1); /* HDLC flags x 2 */
+
+ outmp = allocb(outmp_len, BPRI_MED);
+ if (outmp == NULL) {
+ state->stats.ppp_oerrors++;
+#if defined(USE_MUTEX)
+ mutex_exit(&state->lock);
+#endif /* USE_MUTEX */
+ putctl1(RD(q)->q_next, M_CTL, PPPCTL_OERROR);
+ return;
+ }
+
+#if defined(SOL2)
+ /*
+ * Check if our last transmit happenned within flag_time, using
+ * the system's LBOLT value in clock ticks
+ */
+ if (drv_getparm(LBOLT, &lbolt) != -1) {
+ if (ABS((clock_t)lbolt - state->lbolt) > state->flag_time) {
+ *outmp->b_wptr++ = PPP_FLAG;
+ }
+ state->lbolt = lbolt;
+ } else {
+ *outmp->b_wptr++ = PPP_FLAG;
+ }
+#else
+ /*
+ * If the driver below still has a message to process, skip the
+ * HDLC flag, otherwise, put one in the beginning
+ */
+ if (qsize(q->q_next) == 0) {
+ *outmp->b_wptr++ = PPP_FLAG;
+ }
+#endif
+
+ /*
+ * All control characters must be escaped for LCP packets with code
+ * values between 1 (Conf-Req) and 7 (Code-Rej).
+ */
+ is_lcp = ((MSG_BYTE(mp, 0) == PPP_ALLSTATIONS) &&
+ (MSG_BYTE(mp, 1) == PPP_UI) &&
+ (MSG_BYTE(mp, 2) == (PPP_LCP >> 8)) &&
+ (MSG_BYTE(mp, 3) == (PPP_LCP & 0xff)) &&
+ LCP_USE_DFLT(mp));
+
+ xaccm = state->xaccm;
+ if (is_lcp) {
+ bcopy((caddr_t)state->xaccm, (caddr_t)loc_xaccm, sizeof(loc_xaccm));
+ loc_xaccm[0] = ~0; /* force escape on 0x00 through 0x1f */
+ xaccm = loc_xaccm;
+ }
+
+ fcs = PPP_INITFCS; /* Initial FCS is 0xffff */
+
+ /*
+ * Process this block and the rest (if any) attached to the this one
+ */
+ for (tmp = mp; tmp; tmp = tmp->b_cont) {
+ if (tmp->b_datap->db_type == M_DATA) {
+ for (dp = tmp->b_rptr; dp < tmp->b_wptr; dp++) {
+ fcs = PPP_FCS(fcs, *dp);
+ if (IN_TX_MAP(*dp, xaccm)) {
+ *outmp->b_wptr++ = PPP_ESCAPE;
+ *outmp->b_wptr++ = *dp ^ PPP_TRANS;
+ } else {
+ *outmp->b_wptr++ = *dp;
+ }
+ }
+ } else {
+ continue; /* skip if db_type is something other than M_DATA */
+ }
+ }
+
+ /*
+ * Append the HDLC FCS, making sure that escaping is done on any
+ * necessary bytes
+ */
+ fcs_val = (fcs ^ 0xffff) & 0xff;
+ if (IN_TX_MAP(fcs_val, xaccm)) {
+ *outmp->b_wptr++ = PPP_ESCAPE;
+ *outmp->b_wptr++ = fcs_val ^ PPP_TRANS;
+ } else {
+ *outmp->b_wptr++ = fcs_val;
+ }
+
+ fcs_val = ((fcs ^ 0xffff) >> 8) & 0xff;
+ if (IN_TX_MAP(fcs_val, xaccm)) {
+ *outmp->b_wptr++ = PPP_ESCAPE;
+ *outmp->b_wptr++ = fcs_val ^ PPP_TRANS;
+ } else {
+ *outmp->b_wptr++ = fcs_val;
+ }
+
+ /*
+ * And finally, append the HDLC flag, and send it away
+ */
+ *outmp->b_wptr++ = PPP_FLAG;
+
+ state->stats.ppp_obytes += msgdsize(outmp);
+ state->stats.ppp_opackets++;
+
+#if defined(USE_MUTEX)
+ mutex_exit(&state->lock);
+#endif /* USE_MUTEX */
+
+ putnext(q, outmp);
+ return;
+}
+
+/*
+ * Checks the 32-bit receive ACCM to see if the byte needs un-escaping
+ */
+#define IN_RX_MAP(c, m) ((((unsigned int) (uchar_t) (c)) < 0x20) && \
+ (m) & (1 << (c)))
+
+
+/*
+ * Process received characters.
+ */
+static void
+ahdlc_decode(q, mp)
+ queue_t *q;
+ mblk_t *mp;
+{
+ ahdlc_state_t *state;
+ mblk_t *om;
+ uchar_t *dp;
+ ushort_t fcs;
+#if defined(SOL2)
+ mblk_t *zmp;
+#endif /* SOL2 */
+
+#if defined(SOL2)
+ /*
+ * In case the driver (or something below) doesn't send
+ * data upstream in one message block, concatenate everything
+ */
+ if (!((mp->b_wptr - mp->b_rptr == msgdsize(mp)) &&
+ ((intpointer_t)mp->b_rptr % sizeof(intpointer_t) == 0))) {
+
+ zmp = msgpullup(mp, -1);
+ freemsg(mp);
+ mp = zmp;
+ if (mp == 0)
+ return;
+ }
+#endif /* SOL2 */
+
+ state = (ahdlc_state_t *) q->q_ptr;
+
+#if defined(USE_MUTEX)
+ mutex_enter(&state->lock);
+#endif /* USE_MUTEX */
+
+ state->stats.ppp_ibytes += msgdsize(mp);
+
+ for (dp = mp->b_rptr; dp < mp->b_wptr; dp++) {
+
+ /*
+ * This should detect the lack of 8-bit communication channel
+ * which is necessary for PPP to work. In addition, it also
+ * checks on the parity.
+ */
+ if (*dp & 0x80)
+ state->flags |= RCV_B7_1;
+ else
+ state->flags |= RCV_B7_0;
+
+ if (paritytab[*dp >> 5] & (1 << (*dp & 0x1f)))
+ state->flags |= RCV_ODDP;
+ else
+ state->flags |= RCV_EVNP;
+
+ /*
+ * So we have a HDLC flag ...
+ */
+ if (*dp == PPP_FLAG) {
+
+ /*
+ * If we think that it marks the beginning of the frame,
+ * then continue to process the next octects
+ */
+ if ((state->flags & IFLUSH) ||
+ (state->rx_buf == 0) ||
+ (msgdsize(state->rx_buf) == 0)) {
+
+ state->flags &= ~IFLUSH;
+ continue;
+ }
+
+ /*
+ * We get here because the above condition isn't true,
+ * in which case the HDLC flag was there to mark the end
+ * of the frame (or so we think)
+ */
+ om = state->rx_buf;
+
+ if (state->infcs == PPP_GOODFCS) {
+ state->stats.ppp_ipackets++;
+ adjmsg(om, -PPP_FCSLEN);
+ putnext(q, om);
+ } else {
+ DPRINT2("ppp%d: bad fcs (len=%d)\n",
+ state->unit, msgdsize(state->rx_buf));
+ freemsg(state->rx_buf);
+ state->flags &= ~(IFLUSH | ESCAPED);
+ state->stats.ppp_ierrors++;
+ putctl1(q->q_next, M_CTL, PPPCTL_IERROR);
+ }
+
+ state->rx_buf = 0;
+ continue;
+ }
+
+ if (state->flags & IFLUSH) {
+ continue;
+ }
+
+ /*
+ * Allocate a receive buffer, large enough to store a frame (after
+ * un-escaping) of at least 1500 octets. If MRU is negotiated to
+ * be more than the default, then allocate that much. In addition,
+ * we add an extra 32-bytes for a fudge factor
+ */
+ if (state->rx_buf == 0) {
+ state->rx_buf_size = (state->mru < PPP_MRU ? PPP_MRU : state->mru);
+ state->rx_buf_size += (sizeof(u_int32_t) << 3);
+ state->rx_buf = allocb(state->rx_buf_size, BPRI_MED);
+
+ /*
+ * If allocation fails, try again on the next frame
+ */
+ if (state->rx_buf == 0) {
+ state->flags |= IFLUSH;
+ continue;
+ }
+ state->flags &= ~(IFLUSH | ESCAPED);
+ state->infcs = PPP_INITFCS;
+ }
+
+ if (*dp == PPP_ESCAPE) {
+ state->flags |= ESCAPED;
+ continue;
+ }
+
+ /*
+ * Make sure we un-escape the necessary characters, as well as the
+ * ones in our receive async control character map
+ */
+ if (state->flags & ESCAPED) {
+ *dp ^= PPP_TRANS;
+ state->flags &= ~ESCAPED;
+ } else if (IN_RX_MAP(*dp, state->raccm))
+ continue;
+
+ /*
+ * Unless the peer lied to us about the negotiated MRU, we should
+ * never get a frame which is too long. If it happens, toss it away
+ * and grab the next incoming one
+ */
+ if (msgdsize(state->rx_buf) < state->rx_buf_size) {
+ state->infcs = PPP_FCS(state->infcs, *dp);
+ *state->rx_buf->b_wptr++ = *dp;
+ } else {
+ DPRINT2("ppp%d: frame too long (%d)\n",
+ state->unit, msgdsize(state->rx_buf));
+ freemsg(state->rx_buf);
+ state->rx_buf = 0;
+ state->flags |= IFLUSH;
+ }
+ }
+
+#if defined(USE_MUTEX)
+ mutex_exit(&state->lock);
+#endif /* USE_MUTEX */
+}
+
+static int
+msg_byte(mp, i)
+ mblk_t *mp;
+ unsigned int i;
+{
+ while (mp != 0 && i >= mp->b_wptr - mp->b_rptr)
+ mp = mp->b_cont;
+ if (mp == 0)
+ return -1;
+ return mp->b_rptr[i];
+}
diff --git a/mdk-stage1/ppp/modules/ppp_comp.c b/mdk-stage1/ppp/modules/ppp_comp.c
new file mode 100644
index 000000000..941e9d8c5
--- /dev/null
+++ b/mdk-stage1/ppp/modules/ppp_comp.c
@@ -0,0 +1,1126 @@
+/*
+ * ppp_comp.c - STREAMS module for kernel-level compression and CCP support.
+ *
+ * Copyright (c) 1994 The Australian National University.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation is hereby granted, provided that the above copyright
+ * notice appears in all copies. This software is provided without any
+ * warranty, express or implied. The Australian National University
+ * makes no representations about the suitability of this software for
+ * any purpose.
+ *
+ * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
+ * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
+ * THE AUSTRALIAN NATIONAL UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
+ * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
+ * OR MODIFICATIONS.
+ *
+ * $Id: ppp_comp.c 195720 2001-06-11 11:44:34Z gc $
+ */
+
+/*
+ * This file is used under SVR4, Solaris 2, SunOS 4, and Digital UNIX.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/errno.h>
+#include <sys/stream.h>
+
+#ifdef SVR4
+#include <sys/conf.h>
+#include <sys/cmn_err.h>
+#include <sys/ddi.h>
+#else
+#include <sys/user.h>
+#ifdef __osf__
+#include <sys/cmn_err.h>
+#endif
+#endif /* SVR4 */
+
+#include <net/ppp_defs.h>
+#include <net/pppio.h>
+#include "ppp_mod.h"
+
+#ifdef __osf__
+#include <sys/mbuf.h>
+#include <sys/protosw.h>
+#endif
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <net/vjcompress.h>
+
+#define PACKETPTR mblk_t *
+#include <net/ppp-comp.h>
+
+MOD_OPEN_DECL(ppp_comp_open);
+MOD_CLOSE_DECL(ppp_comp_close);
+static int ppp_comp_rput __P((queue_t *, mblk_t *));
+static int ppp_comp_rsrv __P((queue_t *));
+static int ppp_comp_wput __P((queue_t *, mblk_t *));
+static int ppp_comp_wsrv __P((queue_t *));
+static void ppp_comp_ccp __P((queue_t *, mblk_t *, int));
+static int msg_byte __P((mblk_t *, unsigned int));
+
+/* Extract byte i of message mp. */
+#define MSG_BYTE(mp, i) ((i) < (mp)->b_wptr - (mp)->b_rptr? (mp)->b_rptr[i]: \
+ msg_byte((mp), (i)))
+
+/* Is this LCP packet one we have to transmit using LCP defaults? */
+#define LCP_USE_DFLT(mp) (1 <= (code = MSG_BYTE((mp), 4)) && code <= 7)
+
+#define PPP_COMP_ID 0xbadf
+static struct module_info minfo = {
+#ifdef PRIOQ
+ PPP_COMP_ID, "ppp_comp", 0, INFPSZ, 16512, 16384,
+#else
+ PPP_COMP_ID, "ppp_comp", 0, INFPSZ, 16384, 4096,
+#endif
+};
+
+static struct qinit r_init = {
+ ppp_comp_rput, ppp_comp_rsrv, ppp_comp_open, ppp_comp_close,
+ NULL, &minfo, NULL
+};
+
+static struct qinit w_init = {
+ ppp_comp_wput, ppp_comp_wsrv, NULL, NULL, NULL, &minfo, NULL
+};
+
+#if defined(SVR4) && !defined(SOL2)
+int pcmpdevflag = 0;
+#define ppp_compinfo pcmpinfo
+#endif
+struct streamtab ppp_compinfo = {
+ &r_init, &w_init, NULL, NULL
+};
+
+int ppp_comp_count; /* number of module instances in use */
+
+#ifdef __osf__
+
+static void ppp_comp_alloc __P((comp_state_t *));
+typedef struct memreq {
+ unsigned char comp_opts[20];
+ int cmd;
+ int thread_status;
+ char *returned_mem;
+} memreq_t;
+
+#endif
+
+typedef struct comp_state {
+ int flags;
+ int mru;
+ int mtu;
+ int unit;
+ struct compressor *xcomp;
+ void *xstate;
+ struct compressor *rcomp;
+ void *rstate;
+ struct vjcompress vj_comp;
+ int vj_last_ierrors;
+ struct pppstat stats;
+#ifdef __osf__
+ memreq_t memreq;
+ thread_t thread;
+#endif
+} comp_state_t;
+
+
+#ifdef __osf__
+extern task_t first_task;
+#endif
+
+/* Bits in flags are as defined in pppio.h. */
+#define CCP_ERR (CCP_ERROR | CCP_FATALERROR)
+#define LAST_MOD 0x1000000 /* no ppp modules below us */
+#define DBGLOG 0x2000000 /* log debugging stuff */
+
+#define MAX_IPHDR 128 /* max TCP/IP header size */
+#define MAX_VJHDR 20 /* max VJ compressed header size (?) */
+
+#undef MIN /* just in case */
+#define MIN(a, b) ((a) < (b)? (a): (b))
+
+/*
+ * List of compressors we know about.
+ */
+
+#if DO_BSD_COMPRESS
+extern struct compressor ppp_bsd_compress;
+#endif
+#if DO_DEFLATE
+extern struct compressor ppp_deflate, ppp_deflate_draft;
+#endif
+
+struct compressor *ppp_compressors[] = {
+#if DO_BSD_COMPRESS
+ &ppp_bsd_compress,
+#endif
+#if DO_DEFLATE
+ &ppp_deflate,
+ &ppp_deflate_draft,
+#endif
+ NULL
+};
+
+/*
+ * STREAMS module entry points.
+ */
+MOD_OPEN(ppp_comp_open)
+{
+ comp_state_t *cp;
+#ifdef __osf__
+ thread_t thread;
+#endif
+
+ if (q->q_ptr == NULL) {
+ cp = (comp_state_t *) ALLOC_SLEEP(sizeof(comp_state_t));
+ if (cp == NULL)
+ OPEN_ERROR(ENOSR);
+ bzero((caddr_t)cp, sizeof(comp_state_t));
+ WR(q)->q_ptr = q->q_ptr = (caddr_t) cp;
+ cp->mru = PPP_MRU;
+ cp->mtu = PPP_MTU;
+ cp->xstate = NULL;
+ cp->rstate = NULL;
+ vj_compress_init(&cp->vj_comp, -1);
+#ifdef __osf__
+ if (!(thread = kernel_thread_w_arg(first_task, ppp_comp_alloc, (void *)cp)))
+ OPEN_ERROR(ENOSR);
+ cp->thread = thread;
+#endif
+ ++ppp_comp_count;
+ qprocson(q);
+ }
+ return 0;
+}
+
+MOD_CLOSE(ppp_comp_close)
+{
+ comp_state_t *cp;
+
+ qprocsoff(q);
+ cp = (comp_state_t *) q->q_ptr;
+ if (cp != NULL) {
+ if (cp->xstate != NULL)
+ (*cp->xcomp->comp_free)(cp->xstate);
+ if (cp->rstate != NULL)
+ (*cp->rcomp->decomp_free)(cp->rstate);
+#ifdef __osf__
+ if (!cp->thread)
+ printf("ppp_comp_close: NULL thread!\n");
+ else
+ thread_terminate(cp->thread);
+#endif
+ FREE(cp, sizeof(comp_state_t));
+ q->q_ptr = NULL;
+ OTHERQ(q)->q_ptr = NULL;
+ --ppp_comp_count;
+ }
+ return 0;
+}
+
+#ifdef __osf__
+
+/* thread for calling back to a compressor's memory allocator
+ * Needed for Digital UNIX since it's VM can't handle requests
+ * for large amounts of memory without blocking. The thread
+ * provides a context in which we can call a memory allocator
+ * that may block.
+ */
+static void
+ppp_comp_alloc(comp_state_t *cp)
+{
+ int len, cmd;
+ unsigned char *compressor_options;
+ thread_t thread;
+ void *(*comp_allocator)();
+
+
+#if defined(MAJOR_VERSION) && (MAJOR_VERSION <= 2)
+
+ /* In 2.x and earlier the argument gets passed
+ * in the thread structure itself. Yuck.
+ */
+ thread = current_thread();
+ cp = thread->reply_port;
+ thread->reply_port = PORT_NULL;
+
+#endif
+
+ for (;;) {
+ assert_wait((vm_offset_t)&cp->memreq.thread_status, TRUE);
+ thread_block();
+
+ if (thread_should_halt(current_thread()))
+ thread_halt_self();
+ cmd = cp->memreq.cmd;
+ compressor_options = &cp->memreq.comp_opts[0];
+ len = compressor_options[1];
+ if (cmd == PPPIO_XCOMP) {
+ cp->memreq.returned_mem = cp->xcomp->comp_alloc(compressor_options, len);
+ if (!cp->memreq.returned_mem) {
+ cp->memreq.thread_status = ENOSR;
+ } else {
+ cp->memreq.thread_status = 0;
+ }
+ } else {
+ cp->memreq.returned_mem = cp->rcomp->decomp_alloc(compressor_options, len);
+ if (!cp->memreq.returned_mem) {
+ cp->memreq.thread_status = ENOSR;
+ } else {
+ cp->memreq.thread_status = 0;
+ }
+ }
+ }
+}
+
+#endif /* __osf__ */
+
+/* here's the deal with memory allocation under Digital UNIX.
+ * Some other may also benefit from this...
+ * We can't ask for huge chunks of memory in a context where
+ * the caller can't be put to sleep (like, here.) The alloc
+ * is likely to fail. Instead we do this: the first time we
+ * get called, kick off a thread to do the allocation. Return
+ * immediately to the caller with EAGAIN, as an indication that
+ * they should send down the ioctl again. By the time the
+ * second call comes in it's likely that the memory allocation
+ * thread will have returned with the requested memory. We will
+ * continue to return EAGAIN however until the thread has completed.
+ * When it has, we return zero (and the memory) if the allocator
+ * was successful and ENOSR otherwise.
+ *
+ * Callers of the RCOMP and XCOMP ioctls are encouraged (but not
+ * required) to loop for some number of iterations with a small
+ * delay in the loop body (for instance a 1/10-th second "sleep"
+ * via select.)
+ */
+static int
+ppp_comp_wput(q, mp)
+ queue_t *q;
+ mblk_t *mp;
+{
+ struct iocblk *iop;
+ comp_state_t *cp;
+ int error, len, n;
+ int flags, mask;
+ mblk_t *np;
+ struct compressor **comp;
+ struct ppp_stats *psp;
+ struct ppp_comp_stats *csp;
+ unsigned char *opt_data;
+ int nxslots, nrslots;
+
+ cp = (comp_state_t *) q->q_ptr;
+ if (cp == 0) {
+ DPRINT("cp == 0 in ppp_comp_wput\n");
+ freemsg(mp);
+ return 0;
+ }
+
+ switch (mp->b_datap->db_type) {
+
+ case M_DATA:
+ putq(q, mp);
+ break;
+
+ case M_IOCTL:
+ iop = (struct iocblk *) mp->b_rptr;
+ error = EINVAL;
+ switch (iop->ioc_cmd) {
+
+ case PPPIO_CFLAGS:
+ /* set/get CCP state */
+ if (iop->ioc_count != 2 * sizeof(int))
+ break;
+ if (mp->b_cont == 0) {
+ DPRINT1("ppp_comp_wput/%d: PPPIO_CFLAGS b_cont = 0!\n", cp->unit);
+ break;
+ }
+ flags = ((int *) mp->b_cont->b_rptr)[0];
+ mask = ((int *) mp->b_cont->b_rptr)[1];
+ cp->flags = (cp->flags & ~mask) | (flags & mask);
+ if ((mask & CCP_ISOPEN) && (flags & CCP_ISOPEN) == 0) {
+ if (cp->xstate != NULL) {
+ (*cp->xcomp->comp_free)(cp->xstate);
+ cp->xstate = NULL;
+ }
+ if (cp->rstate != NULL) {
+ (*cp->rcomp->decomp_free)(cp->rstate);
+ cp->rstate = NULL;
+ }
+ cp->flags &= ~CCP_ISUP;
+ }
+ error = 0;
+ iop->ioc_count = sizeof(int);
+ ((int *) mp->b_cont->b_rptr)[0] = cp->flags;
+ mp->b_cont->b_wptr = mp->b_cont->b_rptr + sizeof(int);
+ break;
+
+ case PPPIO_VJINIT:
+ /*
+ * Initialize VJ compressor/decompressor
+ */
+ if (iop->ioc_count != 2)
+ break;
+ if (mp->b_cont == 0) {
+ DPRINT1("ppp_comp_wput/%d: PPPIO_VJINIT b_cont = 0!\n", cp->unit);
+ break;
+ }
+ nxslots = mp->b_cont->b_rptr[0] + 1;
+ nrslots = mp->b_cont->b_rptr[1] + 1;
+ if (nxslots > MAX_STATES || nrslots > MAX_STATES)
+ break;
+ vj_compress_init(&cp->vj_comp, nxslots);
+ cp->vj_last_ierrors = cp->stats.ppp_ierrors;
+ error = 0;
+ iop->ioc_count = 0;
+ break;
+
+ case PPPIO_XCOMP:
+ case PPPIO_RCOMP:
+ if (iop->ioc_count <= 0)
+ break;
+ if (mp->b_cont == 0) {
+ DPRINT1("ppp_comp_wput/%d: PPPIO_[XR]COMP b_cont = 0!\n", cp->unit);
+ break;
+ }
+ opt_data = mp->b_cont->b_rptr;
+ len = mp->b_cont->b_wptr - opt_data;
+ if (len > iop->ioc_count)
+ len = iop->ioc_count;
+ if (opt_data[1] < 2 || opt_data[1] > len)
+ break;
+ for (comp = ppp_compressors; *comp != NULL; ++comp)
+ if ((*comp)->compress_proto == opt_data[0]) {
+ /* here's the handler! */
+ error = 0;
+#ifndef __osf__
+ if (iop->ioc_cmd == PPPIO_XCOMP) {
+ /* A previous call may have fetched memory for a compressor
+ * that's now being retired or reset. Free it using it's
+ * mechanism for freeing stuff.
+ */
+ if (cp->xstate != NULL) {
+ (*cp->xcomp->comp_free)(cp->xstate);
+ cp->xstate = NULL;
+ }
+ cp->xcomp = *comp;
+ cp->xstate = (*comp)->comp_alloc(opt_data, len);
+ if (cp->xstate == NULL)
+ error = ENOSR;
+ } else {
+ if (cp->rstate != NULL) {
+ (*cp->rcomp->decomp_free)(cp->rstate);
+ cp->rstate = NULL;
+ }
+ cp->rcomp = *comp;
+ cp->rstate = (*comp)->decomp_alloc(opt_data, len);
+ if (cp->rstate == NULL)
+ error = ENOSR;
+ }
+#else
+ if ((error = cp->memreq.thread_status) != EAGAIN)
+ if (iop->ioc_cmd == PPPIO_XCOMP) {
+ if (cp->xstate) {
+ (*cp->xcomp->comp_free)(cp->xstate);
+ cp->xstate = 0;
+ }
+ /* sanity check for compressor options
+ */
+ if (sizeof (cp->memreq.comp_opts) < len) {
+ printf("can't handle options for compressor %d (%d)\n", opt_data[0],
+ opt_data[1]);
+ cp->memreq.thread_status = ENOSR;
+ cp->memreq.returned_mem = 0;
+ }
+ /* fill in request for the thread and kick it off
+ */
+ if (cp->memreq.thread_status == 0 && !cp->memreq.returned_mem) {
+ bcopy(opt_data, cp->memreq.comp_opts, len);
+ cp->memreq.cmd = PPPIO_XCOMP;
+ cp->xcomp = *comp;
+ error = cp->memreq.thread_status = EAGAIN;
+ thread_wakeup((vm_offset_t)&cp->memreq.thread_status);
+ } else {
+ cp->xstate = cp->memreq.returned_mem;
+ cp->memreq.returned_mem = 0;
+ cp->memreq.thread_status = 0;
+ }
+ } else {
+ if (cp->rstate) {
+ (*cp->rcomp->decomp_free)(cp->rstate);
+ cp->rstate = NULL;
+ }
+ if (sizeof (cp->memreq.comp_opts) < len) {
+ printf("can't handle options for compressor %d (%d)\n", opt_data[0],
+ opt_data[1]);
+ cp->memreq.thread_status = ENOSR;
+ cp->memreq.returned_mem = 0;
+ }
+ if (cp->memreq.thread_status == 0 && !cp->memreq.returned_mem) {
+ bcopy(opt_data, cp->memreq.comp_opts, len);
+ cp->memreq.cmd = PPPIO_RCOMP;
+ cp->rcomp = *comp;
+ error = cp->memreq.thread_status = EAGAIN;
+ thread_wakeup((vm_offset_t)&cp->memreq.thread_status);
+ } else {
+ cp->rstate = cp->memreq.returned_mem;
+ cp->memreq.returned_mem = 0;
+ cp->memreq.thread_status = 0;
+ }
+ }
+#endif
+ break;
+ }
+ iop->ioc_count = 0;
+ break;
+
+ case PPPIO_GETSTAT:
+ if ((cp->flags & LAST_MOD) == 0) {
+ error = -1; /* let the ppp_ahdl module handle it */
+ break;
+ }
+ np = allocb(sizeof(struct ppp_stats), BPRI_HI);
+ if (np == 0) {
+ error = ENOSR;
+ break;
+ }
+ if (mp->b_cont != 0)
+ freemsg(mp->b_cont);
+ mp->b_cont = np;
+ psp = (struct ppp_stats *) np->b_wptr;
+ np->b_wptr += sizeof(struct ppp_stats);
+ iop->ioc_count = sizeof(struct ppp_stats);
+ psp->p = cp->stats;
+ psp->vj = cp->vj_comp.stats;
+ error = 0;
+ break;
+
+ case PPPIO_GETCSTAT:
+ np = allocb(sizeof(struct ppp_comp_stats), BPRI_HI);
+ if (np == 0) {
+ error = ENOSR;
+ break;
+ }
+ if (mp->b_cont != 0)
+ freemsg(mp->b_cont);
+ mp->b_cont = np;
+ csp = (struct ppp_comp_stats *) np->b_wptr;
+ np->b_wptr += sizeof(struct ppp_comp_stats);
+ iop->ioc_count = sizeof(struct ppp_comp_stats);
+ bzero((caddr_t)csp, sizeof(struct ppp_comp_stats));
+ if (cp->xstate != 0)
+ (*cp->xcomp->comp_stat)(cp->xstate, &csp->c);
+ if (cp->rstate != 0)
+ (*cp->rcomp->decomp_stat)(cp->rstate, &csp->d);
+ error = 0;
+ break;
+
+ case PPPIO_DEBUG:
+ if (iop->ioc_count != sizeof(int))
+ break;
+ if (mp->b_cont == 0) {
+ DPRINT1("ppp_comp_wput/%d: PPPIO_DEBUG b_cont = 0!\n", cp->unit);
+ break;
+ }
+ n = *(int *)mp->b_cont->b_rptr;
+ if (n == PPPDBG_LOG + PPPDBG_COMP) {
+ DPRINT1("ppp_comp%d: debug log enabled\n", cp->unit);
+ cp->flags |= DBGLOG;
+ error = 0;
+ iop->ioc_count = 0;
+ } else {
+ error = -1;
+ }
+ break;
+
+ case PPPIO_LASTMOD:
+ cp->flags |= LAST_MOD;
+ error = 0;
+ break;
+
+ default:
+ error = -1;
+ break;
+ }
+
+ if (error < 0)
+ putnext(q, mp);
+ else if (error == 0) {
+ mp->b_datap->db_type = M_IOCACK;
+ qreply(q, mp);
+ } else {
+ mp->b_datap->db_type = M_IOCNAK;
+ iop->ioc_error = error;
+ iop->ioc_count = 0;
+ qreply(q, mp);
+ }
+ break;
+
+ case M_CTL:
+ switch (*mp->b_rptr) {
+ case PPPCTL_MTU:
+ cp->mtu = ((unsigned short *)mp->b_rptr)[1];
+ break;
+ case PPPCTL_MRU:
+ cp->mru = ((unsigned short *)mp->b_rptr)[1];
+ break;
+ case PPPCTL_UNIT:
+ cp->unit = mp->b_rptr[1];
+ break;
+ }
+ putnext(q, mp);
+ break;
+
+ default:
+ putnext(q, mp);
+ }
+
+ return 0;
+}
+
+static int
+ppp_comp_wsrv(q)
+ queue_t *q;
+{
+ mblk_t *mp, *cmp = NULL;
+ comp_state_t *cp;
+ int len, proto, type, hlen, code;
+ struct ip *ip;
+ unsigned char *vjhdr, *dp;
+
+ cp = (comp_state_t *) q->q_ptr;
+ if (cp == 0) {
+ DPRINT("cp == 0 in ppp_comp_wsrv\n");
+ return 0;
+ }
+
+ while ((mp = getq(q)) != 0) {
+ /* assert(mp->b_datap->db_type == M_DATA) */
+#ifdef PRIOQ
+ if (!bcanputnext(q,mp->b_band))
+#else
+ if (!canputnext(q))
+#endif PRIOQ
+ {
+ putbq(q, mp);
+ break;
+ }
+
+ /*
+ * First check the packet length and work out what the protocol is.
+ */
+ len = msgdsize(mp);
+ if (len < PPP_HDRLEN) {
+ DPRINT1("ppp_comp_wsrv: bogus short packet (%d)\n", len);
+ freemsg(mp);
+ cp->stats.ppp_oerrors++;
+ putctl1(RD(q)->q_next, M_CTL, PPPCTL_OERROR);
+ continue;
+ }
+ proto = (MSG_BYTE(mp, 2) << 8) + MSG_BYTE(mp, 3);
+
+ /*
+ * Make sure we've got enough data in the first mblk
+ * and that we are its only user.
+ */
+ if (proto == PPP_CCP)
+ hlen = len;
+ else if (proto == PPP_IP)
+ hlen = PPP_HDRLEN + MAX_IPHDR;
+ else
+ hlen = PPP_HDRLEN;
+ if (hlen > len)
+ hlen = len;
+ if (mp->b_wptr < mp->b_rptr + hlen || mp->b_datap->db_ref > 1) {
+ PULLUP(mp, hlen);
+ if (mp == 0) {
+ DPRINT1("ppp_comp_wsrv: pullup failed (%d)\n", hlen);
+ cp->stats.ppp_oerrors++;
+ putctl1(RD(q)->q_next, M_CTL, PPPCTL_OERROR);
+ continue;
+ }
+ }
+
+ /*
+ * Do VJ compression if requested.
+ */
+ if (proto == PPP_IP && (cp->flags & COMP_VJC)) {
+ ip = (struct ip *) (mp->b_rptr + PPP_HDRLEN);
+ if (ip->ip_p == IPPROTO_TCP) {
+ type = vj_compress_tcp(ip, len - PPP_HDRLEN, &cp->vj_comp,
+ (cp->flags & COMP_VJCCID), &vjhdr);
+ switch (type) {
+ case TYPE_UNCOMPRESSED_TCP:
+ mp->b_rptr[3] = proto = PPP_VJC_UNCOMP;
+ break;
+ case TYPE_COMPRESSED_TCP:
+ dp = vjhdr - PPP_HDRLEN;
+ dp[1] = mp->b_rptr[1]; /* copy control field */
+ dp[0] = mp->b_rptr[0]; /* copy address field */
+ dp[2] = 0; /* set protocol field */
+ dp[3] = proto = PPP_VJC_COMP;
+ mp->b_rptr = dp;
+ break;
+ }
+ }
+ }
+
+ /*
+ * Do packet compression if enabled.
+ */
+ if (proto == PPP_CCP)
+ ppp_comp_ccp(q, mp, 0);
+ else if (proto != PPP_LCP && (cp->flags & CCP_COMP_RUN)
+ && cp->xstate != NULL) {
+ len = msgdsize(mp);
+ (*cp->xcomp->compress)(cp->xstate, &cmp, mp, len,
+ (cp->flags & CCP_ISUP? cp->mtu + PPP_HDRLEN: 0));
+ if (cmp != NULL) {
+#ifdef PRIOQ
+ cmp->b_band=mp->b_band;
+#endif PRIOQ
+ freemsg(mp);
+ mp = cmp;
+ }
+ }
+
+ /*
+ * Do address/control and protocol compression if enabled.
+ */
+ if ((cp->flags & COMP_AC)
+ && !(proto == PPP_LCP && LCP_USE_DFLT(mp))) {
+ mp->b_rptr += 2; /* drop the address & ctrl fields */
+ if (proto < 0x100 && (cp->flags & COMP_PROT))
+ ++mp->b_rptr; /* drop the high protocol byte */
+ } else if (proto < 0x100 && (cp->flags & COMP_PROT)) {
+ /* shuffle up the address & ctrl fields */
+ mp->b_rptr[2] = mp->b_rptr[1];
+ mp->b_rptr[1] = mp->b_rptr[0];
+ ++mp->b_rptr;
+ }
+
+ cp->stats.ppp_opackets++;
+ cp->stats.ppp_obytes += msgdsize(mp);
+ putnext(q, mp);
+ }
+
+ return 0;
+}
+
+static int
+ppp_comp_rput(q, mp)
+ queue_t *q;
+ mblk_t *mp;
+{
+ comp_state_t *cp;
+ struct iocblk *iop;
+ struct ppp_stats *psp;
+
+ cp = (comp_state_t *) q->q_ptr;
+ if (cp == 0) {
+ DPRINT("cp == 0 in ppp_comp_rput\n");
+ freemsg(mp);
+ return 0;
+ }
+
+ switch (mp->b_datap->db_type) {
+
+ case M_DATA:
+ putq(q, mp);
+ break;
+
+ case M_IOCACK:
+ iop = (struct iocblk *) mp->b_rptr;
+ switch (iop->ioc_cmd) {
+ case PPPIO_GETSTAT:
+ /*
+ * Catch this on the way back from the ppp_ahdl module
+ * so we can fill in the VJ stats.
+ */
+ if (mp->b_cont == 0 || iop->ioc_count != sizeof(struct ppp_stats))
+ break;
+ psp = (struct ppp_stats *) mp->b_cont->b_rptr;
+ psp->vj = cp->vj_comp.stats;
+ break;
+ }
+ putnext(q, mp);
+ break;
+
+ case M_CTL:
+ switch (mp->b_rptr[0]) {
+ case PPPCTL_IERROR:
+ ++cp->stats.ppp_ierrors;
+ break;
+ case PPPCTL_OERROR:
+ ++cp->stats.ppp_oerrors;
+ break;
+ }
+ putnext(q, mp);
+ break;
+
+ default:
+ putnext(q, mp);
+ }
+
+ return 0;
+}
+
+static int
+ppp_comp_rsrv(q)
+ queue_t *q;
+{
+ int proto, rv, i;
+ mblk_t *mp, *dmp = NULL, *np;
+ uchar_t *dp, *iphdr;
+ comp_state_t *cp;
+ int len, hlen, vjlen;
+ u_int iphlen;
+
+ cp = (comp_state_t *) q->q_ptr;
+ if (cp == 0) {
+ DPRINT("cp == 0 in ppp_comp_rsrv\n");
+ return 0;
+ }
+
+ while ((mp = getq(q)) != 0) {
+ /* assert(mp->b_datap->db_type == M_DATA) */
+ if (!canputnext(q)) {
+ putbq(q, mp);
+ break;
+ }
+
+ len = msgdsize(mp);
+ cp->stats.ppp_ibytes += len;
+ cp->stats.ppp_ipackets++;
+
+ /*
+ * First work out the protocol and where the PPP header ends.
+ */
+ i = 0;
+ proto = MSG_BYTE(mp, 0);
+ if (proto == PPP_ALLSTATIONS) {
+ i = 2;
+ proto = MSG_BYTE(mp, 2);
+ }
+ if ((proto & 1) == 0) {
+ ++i;
+ proto = (proto << 8) + MSG_BYTE(mp, i);
+ }
+ hlen = i + 1;
+
+ /*
+ * Now reconstruct a complete, contiguous PPP header at the
+ * start of the packet.
+ */
+ if (hlen < ((cp->flags & DECOMP_AC)? 0: 2)
+ + ((cp->flags & DECOMP_PROT)? 1: 2)) {
+ /* count these? */
+ goto bad;
+ }
+ if (mp->b_rptr + hlen > mp->b_wptr) {
+ adjmsg(mp, hlen); /* XXX check this call */
+ hlen = 0;
+ }
+ if (hlen != PPP_HDRLEN) {
+ /*
+ * We need to put some bytes on the front of the packet
+ * to make a full-length PPP header.
+ * If we can put them in *mp, we do, otherwise we
+ * tack another mblk on the front.
+ * XXX we really shouldn't need to carry around
+ * the address and control at this stage.
+ */
+ dp = mp->b_rptr + hlen - PPP_HDRLEN;
+ if (dp < mp->b_datap->db_base || mp->b_datap->db_ref > 1) {
+ np = allocb(PPP_HDRLEN, BPRI_MED);
+ if (np == 0)
+ goto bad;
+ np->b_cont = mp;
+ mp->b_rptr += hlen;
+ mp = np;
+ dp = mp->b_wptr;
+ mp->b_wptr += PPP_HDRLEN;
+ } else
+ mp->b_rptr = dp;
+
+ dp[0] = PPP_ALLSTATIONS;
+ dp[1] = PPP_UI;
+ dp[2] = proto >> 8;
+ dp[3] = proto;
+ }
+
+ /*
+ * Now see if we have a compressed packet to decompress,
+ * or a CCP packet to take notice of.
+ */
+ proto = PPP_PROTOCOL(mp->b_rptr);
+ if (proto == PPP_CCP) {
+ len = msgdsize(mp);
+ if (mp->b_wptr < mp->b_rptr + len) {
+ PULLUP(mp, len);
+ if (mp == 0)
+ goto bad;
+ }
+ ppp_comp_ccp(q, mp, 1);
+ } else if (proto == PPP_COMP) {
+ if ((cp->flags & CCP_ISUP)
+ && (cp->flags & CCP_DECOMP_RUN) && cp->rstate
+ && (cp->flags & CCP_ERR) == 0) {
+ rv = (*cp->rcomp->decompress)(cp->rstate, mp, &dmp);
+ switch (rv) {
+ case DECOMP_OK:
+ freemsg(mp);
+ mp = dmp;
+ if (mp == NULL) {
+ /* no error, but no packet returned either. */
+ continue;
+ }
+ break;
+ case DECOMP_ERROR:
+ cp->flags |= CCP_ERROR;
+ ++cp->stats.ppp_ierrors;
+ putctl1(q->q_next, M_CTL, PPPCTL_IERROR);
+ break;
+ case DECOMP_FATALERROR:
+ cp->flags |= CCP_FATALERROR;
+ ++cp->stats.ppp_ierrors;
+ putctl1(q->q_next, M_CTL, PPPCTL_IERROR);
+ break;
+ }
+ }
+ } else if (cp->rstate && (cp->flags & CCP_DECOMP_RUN)) {
+ (*cp->rcomp->incomp)(cp->rstate, mp);
+ }
+
+ /*
+ * Now do VJ decompression.
+ */
+ proto = PPP_PROTOCOL(mp->b_rptr);
+ if (proto == PPP_VJC_COMP || proto == PPP_VJC_UNCOMP) {
+ len = msgdsize(mp) - PPP_HDRLEN;
+ if ((cp->flags & DECOMP_VJC) == 0 || len <= 0)
+ goto bad;
+
+ /*
+ * Advance past the ppp header.
+ * Here we assume that the whole PPP header is in the first mblk.
+ */
+ np = mp;
+ dp = np->b_rptr + PPP_HDRLEN;
+ if (dp >= mp->b_wptr) {
+ np = np->b_cont;
+ dp = np->b_rptr;
+ }
+
+ /*
+ * Make sure we have sufficient contiguous data at this point.
+ */
+ hlen = (proto == PPP_VJC_COMP)? MAX_VJHDR: MAX_IPHDR;
+ if (hlen > len)
+ hlen = len;
+ if (np->b_wptr < dp + hlen || np->b_datap->db_ref > 1) {
+ PULLUP(mp, hlen + PPP_HDRLEN);
+ if (mp == 0)
+ goto bad;
+ np = mp;
+ dp = np->b_rptr + PPP_HDRLEN;
+ }
+
+ if (proto == PPP_VJC_COMP) {
+ /*
+ * Decompress VJ-compressed packet.
+ * First reset compressor if an input error has occurred.
+ */
+ if (cp->stats.ppp_ierrors != cp->vj_last_ierrors) {
+ if (cp->flags & DBGLOG)
+ DPRINT1("ppp%d: resetting VJ\n", cp->unit);
+ vj_uncompress_err(&cp->vj_comp);
+ cp->vj_last_ierrors = cp->stats.ppp_ierrors;
+ }
+
+ vjlen = vj_uncompress_tcp(dp, np->b_wptr - dp, len,
+ &cp->vj_comp, &iphdr, &iphlen);
+ if (vjlen < 0) {
+ if (cp->flags & DBGLOG)
+ DPRINT2("ppp%d: vj_uncomp_tcp failed, pkt len %d\n",
+ cp->unit, len);
+ ++cp->vj_last_ierrors; /* so we don't reset next time */
+ goto bad;
+ }
+
+ /* drop ppp and vj headers off */
+ if (mp != np) {
+ freeb(mp);
+ mp = np;
+ }
+ mp->b_rptr = dp + vjlen;
+
+ /* allocate a new mblk for the ppp and ip headers */
+ if ((np = allocb(iphlen + PPP_HDRLEN + 4, BPRI_MED)) == 0)
+ goto bad;
+ dp = np->b_rptr; /* prepend mblk with TCP/IP hdr */
+ dp[0] = PPP_ALLSTATIONS; /* reconstruct PPP header */
+ dp[1] = PPP_UI;
+ dp[2] = PPP_IP >> 8;
+ dp[3] = PPP_IP;
+ bcopy((caddr_t)iphdr, (caddr_t)dp + PPP_HDRLEN, iphlen);
+ np->b_wptr = dp + iphlen + PPP_HDRLEN;
+ np->b_cont = mp;
+
+ /* XXX there seems to be a bug which causes panics in strread
+ if we make an mbuf with only the IP header in it :-( */
+ if (mp->b_wptr - mp->b_rptr > 4) {
+ bcopy((caddr_t)mp->b_rptr, (caddr_t)np->b_wptr, 4);
+ mp->b_rptr += 4;
+ np->b_wptr += 4;
+ } else {
+ bcopy((caddr_t)mp->b_rptr, (caddr_t)np->b_wptr,
+ mp->b_wptr - mp->b_rptr);
+ np->b_wptr += mp->b_wptr - mp->b_rptr;
+ np->b_cont = mp->b_cont;
+ freeb(mp);
+ }
+
+ mp = np;
+
+ } else {
+ /*
+ * "Decompress" a VJ-uncompressed packet.
+ */
+ cp->vj_last_ierrors = cp->stats.ppp_ierrors;
+ if (!vj_uncompress_uncomp(dp, hlen, &cp->vj_comp)) {
+ if (cp->flags & DBGLOG)
+ DPRINT2("ppp%d: vj_uncomp_uncomp failed, pkt len %d\n",
+ cp->unit, len);
+ ++cp->vj_last_ierrors; /* don't need to reset next time */
+ goto bad;
+ }
+ mp->b_rptr[3] = PPP_IP; /* fix up the PPP protocol field */
+ }
+ }
+
+ putnext(q, mp);
+ continue;
+
+ bad:
+ if (mp != 0)
+ freemsg(mp);
+ cp->stats.ppp_ierrors++;
+ putctl1(q->q_next, M_CTL, PPPCTL_IERROR);
+ }
+
+ return 0;
+}
+
+/*
+ * Handle a CCP packet being sent or received.
+ * Here all the data in the packet is in a single mbuf.
+ */
+static void
+ppp_comp_ccp(q, mp, rcvd)
+ queue_t *q;
+ mblk_t *mp;
+ int rcvd;
+{
+ int len, clen;
+ comp_state_t *cp;
+ unsigned char *dp;
+
+ len = msgdsize(mp);
+ if (len < PPP_HDRLEN + CCP_HDRLEN)
+ return;
+
+ cp = (comp_state_t *) q->q_ptr;
+ dp = mp->b_rptr + PPP_HDRLEN;
+ len -= PPP_HDRLEN;
+ clen = CCP_LENGTH(dp);
+ if (clen > len)
+ return;
+
+ switch (CCP_CODE(dp)) {
+ case CCP_CONFREQ:
+ case CCP_TERMREQ:
+ case CCP_TERMACK:
+ cp->flags &= ~CCP_ISUP;
+ break;
+
+ case CCP_CONFACK:
+ if ((cp->flags & (CCP_ISOPEN | CCP_ISUP)) == CCP_ISOPEN
+ && clen >= CCP_HDRLEN + CCP_OPT_MINLEN
+ && clen >= CCP_HDRLEN + CCP_OPT_LENGTH(dp + CCP_HDRLEN)) {
+ if (!rcvd) {
+ if (cp->xstate != NULL
+ && (*cp->xcomp->comp_init)
+ (cp->xstate, dp + CCP_HDRLEN, clen - CCP_HDRLEN,
+ cp->unit, 0, ((cp->flags & DBGLOG) != 0)))
+ cp->flags |= CCP_COMP_RUN;
+ } else {
+ if (cp->rstate != NULL
+ && (*cp->rcomp->decomp_init)
+ (cp->rstate, dp + CCP_HDRLEN, clen - CCP_HDRLEN,
+ cp->unit, 0, cp->mru, ((cp->flags & DBGLOG) != 0)))
+ cp->flags = (cp->flags & ~CCP_ERR) | CCP_DECOMP_RUN;
+ }
+ }
+ break;
+
+ case CCP_RESETACK:
+ if (cp->flags & CCP_ISUP) {
+ if (!rcvd) {
+ if (cp->xstate && (cp->flags & CCP_COMP_RUN))
+ (*cp->xcomp->comp_reset)(cp->xstate);
+ } else {
+ if (cp->rstate && (cp->flags & CCP_DECOMP_RUN)) {
+ (*cp->rcomp->decomp_reset)(cp->rstate);
+ cp->flags &= ~CCP_ERROR;
+ }
+ }
+ }
+ break;
+ }
+}
+
+#if 0
+dump_msg(mp)
+ mblk_t *mp;
+{
+ dblk_t *db;
+
+ while (mp != 0) {
+ db = mp->b_datap;
+ DPRINT2("mp=%x cont=%x ", mp, mp->b_cont);
+ DPRINT3("rptr=%x wptr=%x datap=%x\n", mp->b_rptr, mp->b_wptr, db);
+ DPRINT2(" base=%x lim=%x", db->db_base, db->db_lim);
+ DPRINT2(" ref=%d type=%d\n", db->db_ref, db->db_type);
+ mp = mp->b_cont;
+ }
+}
+#endif
+
+static int
+msg_byte(mp, i)
+ mblk_t *mp;
+ unsigned int i;
+{
+ while (mp != 0 && i >= mp->b_wptr - mp->b_rptr)
+ mp = mp->b_cont;
+ if (mp == 0)
+ return -1;
+ return mp->b_rptr[i];
+}
diff --git a/mdk-stage1/ppp/modules/ppp_mod.h b/mdk-stage1/ppp/modules/ppp_mod.h
new file mode 100644
index 000000000..f0af00886
--- /dev/null
+++ b/mdk-stage1/ppp/modules/ppp_mod.h
@@ -0,0 +1,190 @@
+/*
+ * Miscellaneous definitions for PPP STREAMS modules.
+ */
+
+/*
+ * Macros for allocating and freeing kernel memory.
+ */
+#ifdef SVR4 /* SVR4, including Solaris 2 */
+#include <sys/kmem.h>
+#define ALLOC_SLEEP(n) kmem_alloc((n), KM_SLEEP)
+#define ALLOC_NOSLEEP(n) kmem_alloc((n), KM_NOSLEEP)
+#define FREE(p, n) kmem_free((p), (n))
+#endif
+
+#ifdef SUNOS4
+#include <sys/kmem_alloc.h> /* SunOS 4.x */
+#define ALLOC_SLEEP(n) kmem_alloc((n), KMEM_SLEEP)
+#define ALLOC_NOSLEEP(n) kmem_alloc((n), KMEM_NOSLEEP)
+#define FREE(p, n) kmem_free((p), (n))
+#define NOTSUSER() (suser()? 0: EPERM)
+#define bcanputnext(q, band) canputnext((q))
+#endif /* SunOS 4 */
+
+#ifdef __osf__
+#include <sys/malloc.h>
+
+/* caution: this mirrors macros in sys/malloc.h, and uses interfaces
+ * which are subject to change.
+ * The problems are that:
+ * - the official MALLOC macro wants the lhs of the assignment as an argument,
+ * and it takes care of the assignment itself (yuck.)
+ * - PPP insists on using "FREE" which conflicts with a macro of the same name.
+ *
+ */
+#ifdef BUCKETINDX /* V2.0 */
+#define ALLOC_SLEEP(n) (void *)malloc((u_long)(n), BUCKETP(n), M_DEVBUF, M_WAITOK)
+#define ALLOC_NOSLEEP(n) (void *)malloc((u_long)(n), BUCKETP(n), M_DEVBUF, M_NOWAIT)
+#else
+#define ALLOC_SLEEP(n) (void *)malloc((u_long)(n), BUCKETINDEX(n), M_DEVBUF, M_WAITOK)
+#define ALLOC_NOSLEEP(n) (void *)malloc((u_long)(n), BUCKETINDEX(n), M_DEVBUF, M_NOWAIT)
+#endif
+
+#define bcanputnext(q, band) canputnext((q))
+
+#ifdef FREE
+#undef FREE
+#endif
+#define FREE(p, n) free((void *)(p), M_DEVBUF)
+
+#define NO_DLPI 1
+
+#ifndef IFT_PPP
+#define IFT_PPP 0x17
+#endif
+
+#include <sys/proc.h>
+#define NOTSUSER() (suser(u.u_procp->p_rcred, &u.u_acflag) ? EPERM : 0)
+
+/* #include "ppp_osf.h" */
+
+#endif /* __osf__ */
+
+#ifdef AIX4
+#define ALLOC_SLEEP(n) xmalloc((n), 0, pinned_heap) /* AIX V4.x */
+#define ALLOC_NOSLEEP(n) xmalloc((n), 0, pinned_heap) /* AIX V4.x */
+#define FREE(p, n) xmfree((p), pinned_heap)
+#define NOTSUSER() (suser()? 0: EPERM)
+#endif /* AIX */
+
+/*
+ * Macros for printing debugging stuff.
+ */
+#ifdef DEBUG
+#if defined(SVR4) || defined(__osf__)
+#if defined(SNI)
+#include <sys/strlog.h>
+#define STRLOG_ID 4712
+#define DPRINT(f) strlog(STRLOG_ID, 0, 0, SL_TRACE, f)
+#define DPRINT1(f, a1) strlog(STRLOG_ID, 0, 0, SL_TRACE, f, a1)
+#define DPRINT2(f, a1, a2) strlog(STRLOG_ID, 0, 0, SL_TRACE, f, a1, a2)
+#define DPRINT3(f, a1, a2, a3) strlog(STRLOG_ID, 0, 0, SL_TRACE, f, a1, a2, a3)
+#else
+#define DPRINT(f) cmn_err(CE_CONT, f)
+#define DPRINT1(f, a1) cmn_err(CE_CONT, f, a1)
+#define DPRINT2(f, a1, a2) cmn_err(CE_CONT, f, a1, a2)
+#define DPRINT3(f, a1, a2, a3) cmn_err(CE_CONT, f, a1, a2, a3)
+#endif /* SNI */
+#else
+#define DPRINT(f) printf(f)
+#define DPRINT1(f, a1) printf(f, a1)
+#define DPRINT2(f, a1, a2) printf(f, a1, a2)
+#define DPRINT3(f, a1, a2, a3) printf(f, a1, a2, a3)
+#endif /* SVR4 or OSF */
+
+#else
+#define DPRINT(f) 0
+#define DPRINT1(f, a1) 0
+#define DPRINT2(f, a1, a2) 0
+#define DPRINT3(f, a1, a2, a3) 0
+#endif /* DEBUG */
+
+#ifndef SVR4
+typedef unsigned char uchar_t;
+typedef unsigned short ushort_t;
+#ifndef __osf__
+typedef int minor_t;
+#endif
+#endif
+
+/*
+ * If we don't have multithreading support, define substitutes.
+ */
+#ifndef D_MP
+# define qprocson(q)
+# define qprocsoff(q)
+# define put(q, mp) ((*(q)->q_qinfo->qi_putp)((q), (mp)))
+# define canputnext(q) canput((q)->q_next)
+# define qwriter(q, mp, func, scope) (func)((q), (mp))
+#endif
+
+#ifdef D_MP
+/* Use msgpullup if we have other multithreading support. */
+#define PULLUP(mp, len) \
+ do { \
+ mblk_t *np = msgpullup((mp), (len)); \
+ freemsg((mp)); \
+ mp = np; \
+ } while (0)
+
+#else
+/* Use pullupmsg if we don't have any multithreading support. */
+#define PULLUP(mp, len) \
+ do { \
+ if (!pullupmsg((mp), (len))) { \
+ freemsg((mp)); \
+ mp = 0; \
+ } \
+ } while (0)
+#endif
+
+/*
+ * How to declare the open and close procedures for a module.
+ */
+#ifdef SVR4
+#define MOD_OPEN_DECL(name) \
+static int name __P((queue_t *, dev_t *, int, int, cred_t *))
+
+#define MOD_CLOSE_DECL(name) \
+static int name __P((queue_t *, int, cred_t *))
+
+#define MOD_OPEN(name) \
+static int name(q, devp, flag, sflag, credp) \
+ queue_t *q; \
+ dev_t *devp; \
+ int flag, sflag; \
+ cred_t *credp;
+
+#define MOD_CLOSE(name) \
+static int name(q, flag, credp) \
+ queue_t *q; \
+ int flag; \
+ cred_t *credp;
+
+#define OPEN_ERROR(x) return (x)
+#define DRV_OPEN_OK(dev) return 0
+
+#define NOTSUSER() (drv_priv(credp))
+
+#else /* not SVR4 */
+#define MOD_OPEN_DECL(name) \
+static int name __P((queue_t *, int, int, int))
+
+#define MOD_CLOSE_DECL(name) \
+static int name __P((queue_t *, int))
+
+#define MOD_OPEN(name) \
+static int name(q, dev, flag, sflag) \
+ queue_t *q; \
+ int dev; \
+ int flag, sflag;
+
+#define MOD_CLOSE(name) \
+static int name(q, flag) \
+ queue_t *q; \
+ int flag;
+
+#define OPEN_ERROR(x) { u.u_error = (x); return OPENFAIL; }
+#define DRV_OPEN_OK(dev) return (dev)
+
+#endif /* SVR4 */
diff --git a/mdk-stage1/ppp/modules/vjcompress.c b/mdk-stage1/ppp/modules/vjcompress.c
new file mode 100644
index 000000000..af519b434
--- /dev/null
+++ b/mdk-stage1/ppp/modules/vjcompress.c
@@ -0,0 +1,587 @@
+/*
+ * Routines to compress and uncompess tcp packets (for transmission
+ * over low speed serial lines.
+ *
+ * Copyright (c) 1989 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Van Jacobson (van@helios.ee.lbl.gov), Dec 31, 1989:
+ * - Initial distribution.
+ *
+ * Modified June 1993 by Paul Mackerras, paulus@cs.anu.edu.au,
+ * so that the entire packet being decompressed doesn't have
+ * to be in contiguous memory (just the compressed header).
+ */
+
+/*
+ * This version is used under SunOS 4.x, Digital UNIX, AIX 4.x,
+ * and SVR4 systems including Solaris 2.
+ *
+ * $Id: vjcompress.c 195720 2001-06-11 11:44:34Z gc $
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+
+#ifdef SVR4
+#ifndef __GNUC__
+#include <sys/byteorder.h> /* for ntohl, etc. */
+#else
+/* make sure we don't get the gnu "fixed" one! */
+#include "/usr/include/sys/byteorder.h"
+#endif
+#endif
+
+#ifdef __osf__
+#include <net/net_globals.h>
+#endif
+#include <netinet/in.h>
+
+#ifdef AIX4
+#define _NETINET_IN_SYSTM_H_
+typedef u_long n_long;
+#else
+#include <netinet/in_systm.h>
+#endif
+
+#include <netinet/ip.h>
+#include <netinet/tcp.h>
+
+#include <net/ppp_defs.h>
+#include <net/vjcompress.h>
+
+#ifndef VJ_NO_STATS
+#define INCR(counter) ++comp->stats.counter
+#else
+#define INCR(counter)
+#endif
+
+#define BCMP(p1, p2, n) bcmp((char *)(p1), (char *)(p2), (int)(n))
+#undef BCOPY
+#define BCOPY(p1, p2, n) bcopy((char *)(p1), (char *)(p2), (int)(n))
+#ifndef KERNEL
+#define ovbcopy bcopy
+#endif
+
+#ifdef __osf__
+#define getip_hl(base) (((base).ip_vhl)&0xf)
+#define getth_off(base) ((((base).th_xoff)&0xf0)>>4)
+
+#else
+#define getip_hl(base) ((base).ip_hl)
+#define getth_off(base) ((base).th_off)
+#endif
+
+void
+vj_compress_init(comp, max_state)
+ struct vjcompress *comp;
+ int max_state;
+{
+ register u_int i;
+ register struct cstate *tstate = comp->tstate;
+
+ if (max_state == -1)
+ max_state = MAX_STATES - 1;
+ bzero((char *)comp, sizeof(*comp));
+ for (i = max_state; i > 0; --i) {
+ tstate[i].cs_id = i;
+ tstate[i].cs_next = &tstate[i - 1];
+ }
+ tstate[0].cs_next = &tstate[max_state];
+ tstate[0].cs_id = 0;
+ comp->last_cs = &tstate[0];
+ comp->last_recv = 255;
+ comp->last_xmit = 255;
+ comp->flags = VJF_TOSS;
+}
+
+
+/* ENCODE encodes a number that is known to be non-zero. ENCODEZ
+ * checks for zero (since zero has to be encoded in the long, 3 byte
+ * form).
+ */
+#define ENCODE(n) { \
+ if ((u_short)(n) >= 256) { \
+ *cp++ = 0; \
+ cp[1] = (n); \
+ cp[0] = (n) >> 8; \
+ cp += 2; \
+ } else { \
+ *cp++ = (n); \
+ } \
+}
+#define ENCODEZ(n) { \
+ if ((u_short)(n) >= 256 || (u_short)(n) == 0) { \
+ *cp++ = 0; \
+ cp[1] = (n); \
+ cp[0] = (n) >> 8; \
+ cp += 2; \
+ } else { \
+ *cp++ = (n); \
+ } \
+}
+
+#define DECODEL(f) { \
+ if (*cp == 0) {\
+ u_int32_t tmp = ntohl(f) + ((cp[1] << 8) | cp[2]); \
+ (f) = htonl(tmp); \
+ cp += 3; \
+ } else { \
+ u_int32_t tmp = ntohl(f) + (u_int32_t)*cp++; \
+ (f) = htonl(tmp); \
+ } \
+}
+
+#define DECODES(f) { \
+ if (*cp == 0) {\
+ u_short tmp = ntohs(f) + ((cp[1] << 8) | cp[2]); \
+ (f) = htons(tmp); \
+ cp += 3; \
+ } else { \
+ u_short tmp = ntohs(f) + (u_int32_t)*cp++; \
+ (f) = htons(tmp); \
+ } \
+}
+
+#define DECODEU(f) { \
+ if (*cp == 0) {\
+ (f) = htons((cp[1] << 8) | cp[2]); \
+ cp += 3; \
+ } else { \
+ (f) = htons((u_int32_t)*cp++); \
+ } \
+}
+
+u_int
+vj_compress_tcp(ip, mlen, comp, compress_cid, vjhdrp)
+ register struct ip *ip;
+ u_int mlen;
+ struct vjcompress *comp;
+ int compress_cid;
+ u_char **vjhdrp;
+{
+ register struct cstate *cs = comp->last_cs->cs_next;
+ register u_int hlen = getip_hl(*ip);
+ register struct tcphdr *oth;
+ register struct tcphdr *th;
+ register u_int deltaS, deltaA;
+ register u_int changes = 0;
+ u_char new_seq[16];
+ register u_char *cp = new_seq;
+
+ /*
+ * Bail if this is an IP fragment or if the TCP packet isn't
+ * `compressible' (i.e., ACK isn't set or some other control bit is
+ * set). (We assume that the caller has already made sure the
+ * packet is IP proto TCP).
+ */
+ if ((ip->ip_off & htons(0x3fff)) || mlen < 40)
+ return (TYPE_IP);
+
+ th = (struct tcphdr *)&((int *)ip)[hlen];
+ if ((th->th_flags & (TH_SYN|TH_FIN|TH_RST|TH_ACK)) != TH_ACK)
+ return (TYPE_IP);
+ /*
+ * Packet is compressible -- we're going to send either a
+ * COMPRESSED_TCP or UNCOMPRESSED_TCP packet. Either way we need
+ * to locate (or create) the connection state. Special case the
+ * most recently used connection since it's most likely to be used
+ * again & we don't have to do any reordering if it's used.
+ */
+ INCR(vjs_packets);
+ if (ip->ip_src.s_addr != cs->cs_ip.ip_src.s_addr ||
+ ip->ip_dst.s_addr != cs->cs_ip.ip_dst.s_addr ||
+ *(int *)th != ((int *)&cs->cs_ip)[getip_hl(cs->cs_ip)]) {
+ /*
+ * Wasn't the first -- search for it.
+ *
+ * States are kept in a circularly linked list with
+ * last_cs pointing to the end of the list. The
+ * list is kept in lru order by moving a state to the
+ * head of the list whenever it is referenced. Since
+ * the list is short and, empirically, the connection
+ * we want is almost always near the front, we locate
+ * states via linear search. If we don't find a state
+ * for the datagram, the oldest state is (re-)used.
+ */
+ register struct cstate *lcs;
+ register struct cstate *lastcs = comp->last_cs;
+
+ do {
+ lcs = cs; cs = cs->cs_next;
+ INCR(vjs_searches);
+ if (ip->ip_src.s_addr == cs->cs_ip.ip_src.s_addr
+ && ip->ip_dst.s_addr == cs->cs_ip.ip_dst.s_addr
+ && *(int *)th == ((int *)&cs->cs_ip)[getip_hl(cs->cs_ip)])
+ goto found;
+ } while (cs != lastcs);
+
+ /*
+ * Didn't find it -- re-use oldest cstate. Send an
+ * uncompressed packet that tells the other side what
+ * connection number we're using for this conversation.
+ * Note that since the state list is circular, the oldest
+ * state points to the newest and we only need to set
+ * last_cs to update the lru linkage.
+ */
+ INCR(vjs_misses);
+ comp->last_cs = lcs;
+ hlen += getth_off(*th);
+ hlen <<= 2;
+ if (hlen > mlen)
+ return (TYPE_IP);
+ goto uncompressed;
+
+ found:
+ /*
+ * Found it -- move to the front on the connection list.
+ */
+ if (cs == lastcs)
+ comp->last_cs = lcs;
+ else {
+ lcs->cs_next = cs->cs_next;
+ cs->cs_next = lastcs->cs_next;
+ lastcs->cs_next = cs;
+ }
+ }
+
+ /*
+ * Make sure that only what we expect to change changed. The first
+ * line of the `if' checks the IP protocol version, header length &
+ * type of service. The 2nd line checks the "Don't fragment" bit.
+ * The 3rd line checks the time-to-live and protocol (the protocol
+ * check is unnecessary but costless). The 4th line checks the TCP
+ * header length. The 5th line checks IP options, if any. The 6th
+ * line checks TCP options, if any. If any of these things are
+ * different between the previous & current datagram, we send the
+ * current datagram `uncompressed'.
+ */
+ oth = (struct tcphdr *)&((int *)&cs->cs_ip)[hlen];
+ deltaS = hlen;
+ hlen += getth_off(*th);
+ hlen <<= 2;
+ if (hlen > mlen)
+ return (TYPE_IP);
+
+ if (((u_short *)ip)[0] != ((u_short *)&cs->cs_ip)[0] ||
+ ((u_short *)ip)[3] != ((u_short *)&cs->cs_ip)[3] ||
+ ((u_short *)ip)[4] != ((u_short *)&cs->cs_ip)[4] ||
+ getth_off(*th) != getth_off(*oth) ||
+ (deltaS > 5 && BCMP(ip + 1, &cs->cs_ip + 1, (deltaS - 5) << 2)) ||
+ (getth_off(*th) > 5 && BCMP(th + 1, oth + 1, (getth_off(*th) - 5) << 2)))
+ goto uncompressed;
+
+ /*
+ * Figure out which of the changing fields changed. The
+ * receiver expects changes in the order: urgent, window,
+ * ack, seq (the order minimizes the number of temporaries
+ * needed in this section of code).
+ */
+ if (th->th_flags & TH_URG) {
+ deltaS = ntohs(th->th_urp);
+ ENCODEZ(deltaS);
+ changes |= NEW_U;
+ } else if (th->th_urp != oth->th_urp)
+ /* argh! URG not set but urp changed -- a sensible
+ * implementation should never do this but RFC793
+ * doesn't prohibit the change so we have to deal
+ * with it. */
+ goto uncompressed;
+
+ if ((deltaS = (u_short)(ntohs(th->th_win) - ntohs(oth->th_win))) > 0) {
+ ENCODE(deltaS);
+ changes |= NEW_W;
+ }
+
+ if ((deltaA = ntohl(th->th_ack) - ntohl(oth->th_ack)) > 0) {
+ if (deltaA > 0xffff)
+ goto uncompressed;
+ ENCODE(deltaA);
+ changes |= NEW_A;
+ }
+
+ if ((deltaS = ntohl(th->th_seq) - ntohl(oth->th_seq)) > 0) {
+ if (deltaS > 0xffff)
+ goto uncompressed;
+ ENCODE(deltaS);
+ changes |= NEW_S;
+ }
+
+ switch(changes) {
+
+ case 0:
+ /*
+ * Nothing changed. If this packet contains data and the
+ * last one didn't, this is probably a data packet following
+ * an ack (normal on an interactive connection) and we send
+ * it compressed. Otherwise it's probably a retransmit,
+ * retransmitted ack or window probe. Send it uncompressed
+ * in case the other side missed the compressed version.
+ */
+ if (ip->ip_len != cs->cs_ip.ip_len &&
+ ntohs(cs->cs_ip.ip_len) == hlen)
+ break;
+
+ /* (fall through) */
+
+ case SPECIAL_I:
+ case SPECIAL_D:
+ /*
+ * actual changes match one of our special case encodings --
+ * send packet uncompressed.
+ */
+ goto uncompressed;
+
+ case NEW_S|NEW_A:
+ if (deltaS == deltaA && deltaS == ntohs(cs->cs_ip.ip_len) - hlen) {
+ /* special case for echoed terminal traffic */
+ changes = SPECIAL_I;
+ cp = new_seq;
+ }
+ break;
+
+ case NEW_S:
+ if (deltaS == ntohs(cs->cs_ip.ip_len) - hlen) {
+ /* special case for data xfer */
+ changes = SPECIAL_D;
+ cp = new_seq;
+ }
+ break;
+ }
+
+ deltaS = ntohs(ip->ip_id) - ntohs(cs->cs_ip.ip_id);
+ if (deltaS != 1) {
+ ENCODEZ(deltaS);
+ changes |= NEW_I;
+ }
+ if (th->th_flags & TH_PUSH)
+ changes |= TCP_PUSH_BIT;
+ /*
+ * Grab the cksum before we overwrite it below. Then update our
+ * state with this packet's header.
+ */
+ deltaA = ntohs(th->th_sum);
+ BCOPY(ip, &cs->cs_ip, hlen);
+
+ /*
+ * We want to use the original packet as our compressed packet.
+ * (cp - new_seq) is the number of bytes we need for compressed
+ * sequence numbers. In addition we need one byte for the change
+ * mask, one for the connection id and two for the tcp checksum.
+ * So, (cp - new_seq) + 4 bytes of header are needed. hlen is how
+ * many bytes of the original packet to toss so subtract the two to
+ * get the new packet size.
+ */
+ deltaS = cp - new_seq;
+ cp = (u_char *)ip;
+ if (compress_cid == 0 || comp->last_xmit != cs->cs_id) {
+ comp->last_xmit = cs->cs_id;
+ hlen -= deltaS + 4;
+ *vjhdrp = (cp += hlen);
+ *cp++ = changes | NEW_C;
+ *cp++ = cs->cs_id;
+ } else {
+ hlen -= deltaS + 3;
+ *vjhdrp = (cp += hlen);
+ *cp++ = changes;
+ }
+ *cp++ = deltaA >> 8;
+ *cp++ = deltaA;
+ BCOPY(new_seq, cp, deltaS);
+ INCR(vjs_compressed);
+ return (TYPE_COMPRESSED_TCP);
+
+ /*
+ * Update connection state cs & send uncompressed packet (that is,
+ * a regular ip/tcp packet but with the 'conversation id' we hope
+ * to use on future compressed packets in the protocol field).
+ */
+ uncompressed:
+ BCOPY(ip, &cs->cs_ip, hlen);
+ ip->ip_p = cs->cs_id;
+ comp->last_xmit = cs->cs_id;
+ return (TYPE_UNCOMPRESSED_TCP);
+}
+
+/*
+ * Called when we may have missed a packet.
+ */
+void
+vj_uncompress_err(comp)
+ struct vjcompress *comp;
+{
+ comp->flags |= VJF_TOSS;
+ INCR(vjs_errorin);
+}
+
+/*
+ * "Uncompress" a packet of type TYPE_UNCOMPRESSED_TCP.
+ */
+int
+vj_uncompress_uncomp(buf, buflen, comp)
+ u_char *buf;
+ int buflen;
+ struct vjcompress *comp;
+{
+ register u_int hlen;
+ register struct cstate *cs;
+ register struct ip *ip;
+
+ ip = (struct ip *) buf;
+ hlen = getip_hl(*ip) << 2;
+ if (ip->ip_p >= MAX_STATES
+ || hlen + sizeof(struct tcphdr) > buflen
+ || (hlen += getth_off(*((struct tcphdr *)&((char *)ip)[hlen])) << 2)
+ > buflen
+ || hlen > MAX_HDR) {
+ comp->flags |= VJF_TOSS;
+ INCR(vjs_errorin);
+ return (0);
+ }
+ cs = &comp->rstate[comp->last_recv = ip->ip_p];
+ comp->flags &=~ VJF_TOSS;
+ ip->ip_p = IPPROTO_TCP;
+ BCOPY(ip, &cs->cs_ip, hlen);
+ cs->cs_hlen = hlen;
+ INCR(vjs_uncompressedin);
+ return (1);
+}
+
+/*
+ * Uncompress a packet of type TYPE_COMPRESSED_TCP.
+ * The packet starts at buf and is of total length total_len.
+ * The first buflen bytes are at buf; this must include the entire
+ * compressed TCP/IP header. This procedure returns the length
+ * of the VJ header, with a pointer to the uncompressed IP header
+ * in *hdrp and its length in *hlenp.
+ */
+int
+vj_uncompress_tcp(buf, buflen, total_len, comp, hdrp, hlenp)
+ u_char *buf;
+ int buflen, total_len;
+ struct vjcompress *comp;
+ u_char **hdrp;
+ u_int *hlenp;
+{
+ register u_char *cp;
+ register u_int hlen, changes;
+ register struct tcphdr *th;
+ register struct cstate *cs;
+ register u_short *bp;
+ register u_int vjlen;
+ register u_int32_t tmp;
+
+ INCR(vjs_compressedin);
+ cp = buf;
+ changes = *cp++;
+ if (changes & NEW_C) {
+ /* Make sure the state index is in range, then grab the state.
+ * If we have a good state index, clear the 'discard' flag. */
+ if (*cp >= MAX_STATES)
+ goto bad;
+
+ comp->flags &=~ VJF_TOSS;
+ comp->last_recv = *cp++;
+ } else {
+ /* this packet has an implicit state index. If we've
+ * had a line error since the last time we got an
+ * explicit state index, we have to toss the packet. */
+ if (comp->flags & VJF_TOSS) {
+ INCR(vjs_tossed);
+ return (-1);
+ }
+ }
+ cs = &comp->rstate[comp->last_recv];
+ hlen = getip_hl(cs->cs_ip) << 2;
+ th = (struct tcphdr *)&((u_char *)&cs->cs_ip)[hlen];
+ th->th_sum = htons((*cp << 8) | cp[1]);
+ cp += 2;
+ if (changes & TCP_PUSH_BIT)
+ th->th_flags |= TH_PUSH;
+ else
+ th->th_flags &=~ TH_PUSH;
+
+ switch (changes & SPECIALS_MASK) {
+ case SPECIAL_I:
+ {
+ register u_int32_t i = ntohs(cs->cs_ip.ip_len) - cs->cs_hlen;
+ /* some compilers can't nest inline assembler.. */
+ tmp = ntohl(th->th_ack) + i;
+ th->th_ack = htonl(tmp);
+ tmp = ntohl(th->th_seq) + i;
+ th->th_seq = htonl(tmp);
+ }
+ break;
+
+ case SPECIAL_D:
+ /* some compilers can't nest inline assembler.. */
+ tmp = ntohl(th->th_seq) + ntohs(cs->cs_ip.ip_len) - cs->cs_hlen;
+ th->th_seq = htonl(tmp);
+ break;
+
+ default:
+ if (changes & NEW_U) {
+ th->th_flags |= TH_URG;
+ DECODEU(th->th_urp);
+ } else
+ th->th_flags &=~ TH_URG;
+ if (changes & NEW_W)
+ DECODES(th->th_win);
+ if (changes & NEW_A)
+ DECODEL(th->th_ack);
+ if (changes & NEW_S)
+ DECODEL(th->th_seq);
+ break;
+ }
+ if (changes & NEW_I) {
+ DECODES(cs->cs_ip.ip_id);
+ } else {
+ cs->cs_ip.ip_id = ntohs(cs->cs_ip.ip_id) + 1;
+ cs->cs_ip.ip_id = htons(cs->cs_ip.ip_id);
+ }
+
+ /*
+ * At this point, cp points to the first byte of data in the
+ * packet. Fill in the IP total length and update the IP
+ * header checksum.
+ */
+ vjlen = cp - buf;
+ buflen -= vjlen;
+ if (buflen < 0)
+ /* we must have dropped some characters (crc should detect
+ * this but the old slip framing won't) */
+ goto bad;
+
+ total_len += cs->cs_hlen - vjlen;
+ cs->cs_ip.ip_len = htons(total_len);
+
+ /* recompute the ip header checksum */
+ bp = (u_short *) &cs->cs_ip;
+ cs->cs_ip.ip_sum = 0;
+ for (changes = 0; hlen > 0; hlen -= 2)
+ changes += *bp++;
+ changes = (changes & 0xffff) + (changes >> 16);
+ changes = (changes & 0xffff) + (changes >> 16);
+ cs->cs_ip.ip_sum = ~ changes;
+
+ *hdrp = (u_char *) &cs->cs_ip;
+ *hlenp = cs->cs_hlen;
+ return vjlen;
+
+ bad:
+ comp->flags |= VJF_TOSS;
+ INCR(vjs_errorin);
+ return (-1);
+}
diff --git a/mdk-stage1/ppp/pppd/Makefile b/mdk-stage1/ppp/pppd/Makefile
new file mode 100644
index 000000000..fb5658879
--- /dev/null
+++ b/mdk-stage1/ppp/pppd/Makefile
@@ -0,0 +1,51 @@
+ #******************************************************************************
+ #
+ # Guillaume Cottenceau (gc@mandrakesoft.com)
+ #
+ # Copyright 2000 Mandrakesoft
+ #
+ # This software may be freely redistributed under the terms of the GNU
+ # public license.
+ #
+ # 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.
+ #
+ #*****************************************************************************
+
+top_dir = ../..
+
+include $(top_dir)/Makefile.common
+
+
+TARGETS = pppd
+
+BINTARGET = ../../pppd
+
+
+all: $(TARGETS)
+
+clean:
+ rm -f *.o *.a $(BINTARGET) pppd
+
+FLAGS = -Wall -Wno-deprecated-declarations -Werror -Os -fomit-frame-pointer -DDO_BSD_COMPRESS=0 -D_linux_=1 -DHAVE_MMAP -DNO_DRAND48 -D_BSD_SOURCE -D_GNU_SOURCE
+# (blino) for gcc-4.1.1, dereferencing type-punned pointer will break strict-aliasing rules, in options.c:711
+FLAGS += -fno-strict-aliasing
+
+INCS = -I../include -I.
+
+ifeq (GLIBC, $(L))
+LIBS = -static -lcrypt
+endif
+
+
+OBJS = main.o magic.o fsm.o lcp.o ipcp.o upap.o chap.o md5.o ccp.o auth.o options.o demand.o utils.o sys-linux.o ipxcp.o multilink.o tdb.o tty.o
+
+
+pppd: $(OBJS)
+ $(DIET) gcc -o $@ $^ $(LIBS)
+ $(STRIPCMD) $@
+ cp -f $@ $(BINTARGET)
+
+$(OBJS): %.o: %.c
+ $(DIET) gcc $(FLAGS) $(INCS) $(INCLUDES) -c $< -o $@
diff --git a/mdk-stage1/ppp/pppd/Makefile.linux b/mdk-stage1/ppp/pppd/Makefile.linux
new file mode 100644
index 000000000..4438ea824
--- /dev/null
+++ b/mdk-stage1/ppp/pppd/Makefile.linux
@@ -0,0 +1,129 @@
+#
+# pppd makefile for Linux
+# $Id: Makefile.linux 195720 2001-06-11 11:44:34Z gc $
+#
+
+# Default installation locations
+BINDIR = $(DESTDIR)/usr/sbin
+MANDIR = $(DESTDIR)/usr/man
+
+PPPDSRCS = main.c magic.c fsm.c lcp.c ipcp.c upap.c chap.c md5.c ccp.c \
+ ipxcp.c auth.c options.c sys-linux.c md4.c chap_ms.c cbcp.c \
+ demand.c utils.c multilink.c tdb.c tty.c
+HEADERS = callout.h pathnames.h patchlevel.h chap.h md5.h chap_ms.h md4.h \
+ ipxcp.h cbcp.h tdb.h
+MANPAGES = pppd.8
+PPPDOBJS = main.o magic.o fsm.o lcp.o ipcp.o upap.o chap.o md5.o ccp.o \
+ auth.o options.o demand.o utils.o sys-linux.o ipxcp.o multilink.o \
+ tdb.o tty.o
+
+all: pppd
+
+#
+# include dependancies if present and backup if as a header file
+ifeq (.depend,$(wildcard .depend))
+include .depend
+endif
+
+CC = gcc
+#
+COPTS = -Wall $(RPM_OPT_FLAGS)
+LIBS = -lutil
+
+ifneq ($(wildcard /usr/lib/libcrypt.*),)
+LIBS += -lcrypt
+endif
+
+# Uncomment the next 2 lines to include support for Microsoft's
+# MS-CHAP authentication protocol.
+CHAPMS=y
+USE_CRYPT=y
+ifneq ($(wildcard /usr/lib/libcrypt.*),)
+HAVE_CRYPT_H=y
+endif
+
+# Uncomment the next line to include support for PPP packet filtering.
+# This requires that the libpcap library and headers be installed
+# and that the kernel driver support PPP packet filtering, which it
+# doesn't yet.
+#FILTER=y
+
+HAS_SHADOW=y
+USE_PAM=y
+#HAVE_INET6=y
+
+PLUGIN=y
+
+INCLUDE_DIRS= -I../include
+
+COMPILE_FLAGS= -D_linux_=1 -DHAVE_PATHS_H -DIPX_CHANGE -DHAVE_MULTILINK -DHAVE_MMAP
+
+CFLAGS= $(COPTS) $(COMPILE_FLAGS) $(INCLUDE_DIRS)
+
+ifdef CHAPMS
+CFLAGS += -DCHAPMS=1
+ifndef USE_CRYPT
+LIBS := -ldes $(LIBS)
+else
+CFLAGS += -DUSE_CRYPT=1
+ifneq ($(wildcard /usr/include/crypt.h),)
+CFLAGS += -DHAVE_CRYPT_H=1
+endif
+endif
+PPPDOBJS += md4.o chap_ms.o
+ifdef MSLANMAN
+CFLAGS += -DMSLANMAN=1
+endif
+endif
+
+ifdef HAS_SHADOW
+CFLAGS += -DHAS_SHADOW
+#LIBS := -lshadow $(LIBS)
+endif
+
+# For "Pluggable Authentication Modules", see ftp.redhat.com:/pub/pam/.
+ifdef USE_PAM
+CFLAGS += -DUSE_PAM
+LIBS := -lpam -ldl $(LIBS)
+endif
+
+# Lock library binary for Linux is included in 'linux' subdirectory.
+ifdef LOCKLIB
+LIBS := -llock $(LIBS)
+CFLAGS += -DLOCKLIB=1
+endif
+
+ifdef PLUGIN
+CFLAGS += -DPLUGIN
+LDFLAGS += -Wl,-E
+LIBS += -ldl
+endif
+
+ifdef FILTER
+LIBS += -lpcap
+CFLAGS += -DPPP_FILTER -I/usr/include/pcap
+endif
+
+ifdef HAVE_INET6
+ PPPDSRCS += ipv6cp.c eui64.c
+ HEADERS += ipv6cp.h eui64.h
+ PPPDOBJS += ipv6cp.o eui64.o
+ CFLAGS += -DINET6=1
+endif
+
+
+INSTALL= install
+
+install: pppd
+ mkdir -p $(BINDIR) $(MANDIR)
+ $(INSTALL) -m 555 pppd $(BINDIR)/pppd
+ $(INSTALL) -c -m 444 pppd.8 $(MANDIR)/man8
+
+pppd: $(PPPDOBJS)
+ $(CC) $(CFLAGS) $(LDFLAGS) -o pppd $(PPPDOBJS) $(LIBS)
+
+clean:
+ rm -f $(PPPDOBJS) pppd *~ #* core
+
+depend:
+ $(CPP) -M $(CFLAGS) $(PPPDSRCS) >.depend
diff --git a/mdk-stage1/ppp/pppd/Makefile.linux.make b/mdk-stage1/ppp/pppd/Makefile.linux.make
new file mode 100644
index 000000000..3a2eca00e
--- /dev/null
+++ b/mdk-stage1/ppp/pppd/Makefile.linux.make
@@ -0,0 +1,131 @@
+#
+# pppd makefile for Linux
+# $Id: Makefile.linux.make 195720 2001-06-11 11:44:34Z gc $
+#
+
+# Default installation locations
+BINDIR = /usr/sbin
+MANDIR = /usr/man
+
+PPPDSRCS = main.c magic.c fsm.c lcp.c ipcp.c upap.c chap.c md5.c ccp.c \
+ ipxcp.c auth.c options.c sys-linux.c md4.c chap_ms.c cbcp.c \
+ demand.c utils.c multilink.c tdb.c tty.c
+HEADERS = callout.h pathnames.h patchlevel.h chap.h md5.h chap_ms.h md4.h \
+ ipxcp.h cbcp.h tdb.h
+MANPAGES = pppd.8
+PPPDOBJS = main.o magic.o fsm.o lcp.o ipcp.o upap.o chap.o md5.o ccp.o \
+ auth.o options.o demand.o utils.o sys-linux.o ipxcp.o multilink.o \
+ tdb.o tty.o
+
+all: pppd
+
+#
+# include dependancies if present and backup if as a header file
+ifeq (.depend,$(wildcard .depend))
+include .depend
+endif
+
+# CC = gcc
+#
+COPTS = -O2 -pipe -Wall -g
+LIBS =
+
+ifneq ($(wildcard /usr/lib/libcrypt.*),)
+LIBS += -lcrypt
+endif
+
+# Uncomment the next 2 lines to include support for Microsoft's
+# MS-CHAP authentication protocol.
+CHAPMS=y
+USE_CRYPT=y
+ifneq ($(wildcard /usr/lib/libcrypt.*),)
+HAVE_CRYPT_H=y
+endif
+
+# Uncomment the next line to include support for PPP packet filtering.
+# This requires that the libpcap library and headers be installed
+# and that the kernel driver support PPP packet filtering, which it
+# doesn't yet.
+#FILTER=y
+
+HAS_SHADOW=y
+#USE_PAM=y
+#HAVE_INET6=y
+
+PLUGIN=y
+
+INCLUDE_DIRS= -I../include
+
+COMPILE_FLAGS= -D_linux_=1 -DHAVE_PATHS_H -DIPX_CHANGE -DHAVE_MULTILINK -DHAVE_MMAP
+
+CFLAGS= $(COPTS) $(COMPILE_FLAGS) $(INCLUDE_DIRS)
+
+ifdef CHAPMS
+CFLAGS += -DCHAPMS=1
+ifndef USE_CRYPT
+LIBS := -ldes $(LIBS)
+else
+CFLAGS += -DUSE_CRYPT=1
+ifneq ($(wildcard /usr/include/crypt.h),)
+CFLAGS += -DHAVE_CRYPT_H=1
+endif
+endif
+PPPDOBJS += md4.o chap_ms.o
+ifdef MSLANMAN
+CFLAGS += -DMSLANMAN=1
+endif
+endif
+
+ifdef HAS_SHADOW
+CFLAGS += -DHAS_SHADOW
+#LIBS := -lshadow $(LIBS)
+endif
+
+# For "Pluggable Authentication Modules", see ftp.redhat.com:/pub/pam/.
+ifdef USE_PAM
+CFLAGS += -DUSE_PAM
+LIBS := -lpam -ldl $(LIBS)
+endif
+
+# Lock library binary for Linux is included in 'linux' subdirectory.
+ifdef LOCKLIB
+LIBS := -llock $(LIBS)
+CFLAGS += -DLOCKLIB=1
+endif
+
+ifdef PLUGIN
+CFLAGS += -DPLUGIN
+LDFLAGS += -Wl,-E
+LIBS += -ldl
+endif
+
+ifdef FILTER
+LIBS += -lpcap
+CFLAGS += -DPPP_FILTER -I/usr/include/pcap
+endif
+
+ifdef HAVE_INET6
+ PPPDSRCS += ipv6cp.c eui64.c
+ HEADERS += ipv6cp.h eui64.h
+ PPPDOBJS += ipv6cp.o eui64.o
+ CFLAGS += -DINET6=1
+endif
+
+
+INSTALL= install -o root
+
+install: pppd
+ mkdir -p $(BINDIR) $(MANDIR)
+ $(INSTALL) -s -c -m 555 pppd $(BINDIR)/pppd
+ if chgrp pppusers $(BINDIR)/pppd 2>/dev/null; then \
+ chmod o-rx,u+s $(BINDIR)/pppd; fi
+ $(INSTALL) -c -m 444 pppd.8 $(MANDIR)/man8
+
+pppd: $(PPPDOBJS)
+ $(CC) $(CFLAGS) $(LDFLAGS) -o pppd $(PPPDOBJS) $(LIBS)
+
+clean:
+ rm -f $(PPPDOBJS) pppd *~ #* core
+
+depend:
+ $(CPP) -M $(CFLAGS) $(PPPDSRCS) >.depend
diff --git a/mdk-stage1/ppp/pppd/Makefile.linux.makeopt b/mdk-stage1/ppp/pppd/Makefile.linux.makeopt
new file mode 100644
index 000000000..1b58114cd
--- /dev/null
+++ b/mdk-stage1/ppp/pppd/Makefile.linux.makeopt
@@ -0,0 +1,129 @@
+#
+# pppd makefile for Linux
+# $Id: Makefile.linux.makeopt 195720 2001-06-11 11:44:34Z gc $
+#
+
+# Default installation locations
+BINDIR = $(DESTDIR)/usr/sbin
+MANDIR = $(DESTDIR)/usr/man
+
+PPPDSRCS = main.c magic.c fsm.c lcp.c ipcp.c upap.c chap.c md5.c ccp.c \
+ ipxcp.c auth.c options.c sys-linux.c md4.c chap_ms.c cbcp.c \
+ demand.c utils.c multilink.c tdb.c tty.c
+HEADERS = callout.h pathnames.h patchlevel.h chap.h md5.h chap_ms.h md4.h \
+ ipxcp.h cbcp.h tdb.h
+MANPAGES = pppd.8
+PPPDOBJS = main.o magic.o fsm.o lcp.o ipcp.o upap.o chap.o md5.o ccp.o \
+ auth.o options.o demand.o utils.o sys-linux.o ipxcp.o multilink.o \
+ tdb.o tty.o
+
+all: pppd
+
+#
+# include dependancies if present and backup if as a header file
+ifeq (.depend,$(wildcard .depend))
+include .depend
+endif
+
+CC = gcc
+#
+COPTS = -O2 -pipe -Wall -g
+LIBS = -lutil
+
+ifneq ($(wildcard /usr/lib/libcrypt.*),)
+LIBS += -lcrypt
+endif
+
+# Uncomment the next 2 lines to include support for Microsoft's
+# MS-CHAP authentication protocol.
+CHAPMS=y
+USE_CRYPT=y
+ifneq ($(wildcard /usr/lib/libcrypt.*),)
+HAVE_CRYPT_H=y
+endif
+
+# Uncomment the next line to include support for PPP packet filtering.
+# This requires that the libpcap library and headers be installed
+# and that the kernel driver support PPP packet filtering, which it
+# doesn't yet.
+#FILTER=y
+
+HAS_SHADOW=y
+USE_PAM=y
+#HAVE_INET6=y
+
+PLUGIN=y
+
+INCLUDE_DIRS= -I../include
+
+COMPILE_FLAGS= -D_linux_=1 -DHAVE_PATHS_H -DIPX_CHANGE -DHAVE_MULTILINK -DHAVE_MMAP
+
+CFLAGS= $(COPTS) $(COMPILE_FLAGS) $(INCLUDE_DIRS)
+
+ifdef CHAPMS
+CFLAGS += -DCHAPMS=1
+ifndef USE_CRYPT
+LIBS := -ldes $(LIBS)
+else
+CFLAGS += -DUSE_CRYPT=1
+ifneq ($(wildcard /usr/include/crypt.h),)
+CFLAGS += -DHAVE_CRYPT_H=1
+endif
+endif
+PPPDOBJS += md4.o chap_ms.o
+ifdef MSLANMAN
+CFLAGS += -DMSLANMAN=1
+endif
+endif
+
+ifdef HAS_SHADOW
+CFLAGS += -DHAS_SHADOW
+#LIBS := -lshadow $(LIBS)
+endif
+
+# For "Pluggable Authentication Modules", see ftp.redhat.com:/pub/pam/.
+ifdef USE_PAM
+CFLAGS += -DUSE_PAM
+LIBS := -lpam -ldl $(LIBS)
+endif
+
+# Lock library binary for Linux is included in 'linux' subdirectory.
+ifdef LOCKLIB
+LIBS := -llock $(LIBS)
+CFLAGS += -DLOCKLIB=1
+endif
+
+ifdef PLUGIN
+CFLAGS += -DPLUGIN
+LDFLAGS += -Wl,-E
+LIBS += -ldl
+endif
+
+ifdef FILTER
+LIBS += -lpcap
+CFLAGS += -DPPP_FILTER -I/usr/include/pcap
+endif
+
+ifdef HAVE_INET6
+ PPPDSRCS += ipv6cp.c eui64.c
+ HEADERS += ipv6cp.h eui64.h
+ PPPDOBJS += ipv6cp.o eui64.o
+ CFLAGS += -DINET6=1
+endif
+
+
+INSTALL= install
+
+install: pppd
+ mkdir -p $(BINDIR) $(MANDIR)
+ $(INSTALL) -m 555 pppd $(BINDIR)/pppd
+ $(INSTALL) -c -m 444 pppd.8 $(MANDIR)/man8
+
+pppd: $(PPPDOBJS)
+ $(CC) $(CFLAGS) $(LDFLAGS) -o pppd $(PPPDOBJS) $(LIBS)
+
+clean:
+ rm -f $(PPPDOBJS) pppd *~ #* core
+
+depend:
+ $(CPP) -M $(CFLAGS) $(PPPDSRCS) >.depend
diff --git a/mdk-stage1/ppp/pppd/Makefile.sol2 b/mdk-stage1/ppp/pppd/Makefile.sol2
new file mode 100644
index 000000000..ead5685d7
--- /dev/null
+++ b/mdk-stage1/ppp/pppd/Makefile.sol2
@@ -0,0 +1,48 @@
+#
+# Makefile for pppd under Solaris 2.
+# $Id: Makefile.sol2 195720 2001-06-11 11:44:34Z gc $
+#
+
+include ../solaris/Makedefs
+
+COPTS += -xO2 -xspace -W0,-Lt
+CFLAGS = -I../include -DSVR4 -DSOL2 $(COPTS)
+LIBS = -lsocket -lnsl
+
+OBJS = main.o magic.o fsm.o lcp.o ipcp.o upap.o chap.o md5.o tty.o \
+ ccp.o auth.o options.o demand.o utils.o sys-solaris.o tdb.o
+
+#
+# uncomment the following to enable plugins
+#
+CFLAGS += -DPLUGIN
+LIBS += -ldl
+
+#
+# Solaris 8 and above accomodates /var/run, so uncomment the
+# following to place pppd process IDs on that location
+#
+#CFLAGS += -D_PATH_VARRUN='"/var/run/"'
+
+#
+# uncomment the following to enable IPv6
+#
+# Solaris 8 and on includes support for IPv6
+#
+#CFLAGS += -DINET6
+#OBJS += ipv6cp.o eui64.o
+
+#
+# Make targets
+#
+all: pppd
+
+pppd: $(OBJS)
+ $(CC) -o pppd $(OBJS) $(LIBS)
+
+install:
+ $(INSTALL) -f $(BINDIR) -m 4755 -u root pppd
+ $(INSTALL) -f $(MANDIR)/man8 -m 444 pppd.8
+
+clean:
+ rm -f $(OBJS) pppd *~ core y.tab.c y.tab.h
diff --git a/mdk-stage1/ppp/pppd/Makefile.sunos4 b/mdk-stage1/ppp/pppd/Makefile.sunos4
new file mode 100644
index 000000000..340a8747b
--- /dev/null
+++ b/mdk-stage1/ppp/pppd/Makefile.sunos4
@@ -0,0 +1,26 @@
+#
+# Makefile for pppd under SunOS 4.
+# $Id: Makefile.sunos4 195720 2001-06-11 11:44:34Z gc $
+#
+
+include ../sunos4/Makedefs
+
+LIBS =
+
+CFLAGS = $(COPTS) -I../include -DSUNOS4 -DGIDSET_TYPE=int \
+ -DLOCK_DIR=\"/usr/spool/locks\"
+
+all: pppd
+
+OBJS = main.o magic.o fsm.o lcp.o ipcp.o upap.o chap.o md5.o ccp.o \
+ auth.o options.o demand.o utils.o sys-sunos4.o tty.o
+
+pppd: $(OBJS)
+ $(CC) -o pppd $(OBJS) $(LIBS)
+
+install:
+ $(INSTALL) -c -m 4555 pppd $(BINDIR)/pppd
+ $(INSTALL) -c -m 444 pppd.8 $(MANDIR)/man8/pppd.8
+
+clean:
+ rm -f $(OBJS) pppd *~ core
diff --git a/mdk-stage1/ppp/pppd/auth.c b/mdk-stage1/ppp/pppd/auth.c
new file mode 100644
index 000000000..0520c1eef
--- /dev/null
+++ b/mdk-stage1/ppp/pppd/auth.c
@@ -0,0 +1,1939 @@
+/*
+ * auth.c - PPP authentication and phase control.
+ *
+ * Copyright (c) 1993 The Australian National University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the Australian National University. The name of the University
+ * may not be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#define RCSID "$Id: auth.c 195734 2001-06-11 14:46:02Z gc $"
+
+#include <stdio.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <pwd.h>
+#include <grp.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <utmp.h>
+#include <fcntl.h>
+#if defined(_PATH_LASTLOG) && defined(_linux_)
+#include <lastlog.h>
+#endif
+
+#include <netdb.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#ifdef USE_PAM
+#include <security/pam_appl.h>
+#endif
+
+#ifdef HAS_SHADOW
+#include <shadow.h>
+#ifndef PW_PPP
+#define PW_PPP PW_LOGIN
+#endif
+#endif
+
+#include "pppd.h"
+#include "fsm.h"
+#include "lcp.h"
+#include "ipcp.h"
+#include "upap.h"
+#include "chap.h"
+#ifdef CBCP_SUPPORT
+#include "cbcp.h"
+#endif
+#include "pathnames.h"
+
+#include <time.h>
+
+static const char rcsid[] = RCSID;
+
+/* Bits in scan_authfile return value */
+#define NONWILD_SERVER 1
+#define NONWILD_CLIENT 2
+
+#define ISWILD(word) (word[0] == '*' && word[1] == 0)
+
+/* The name by which the peer authenticated itself to us. */
+char peer_authname[MAXNAMELEN];
+
+/* Records which authentication operations haven't completed yet. */
+static int auth_pending[NUM_PPP];
+
+/* Set if we have successfully called plogin() */
+static int logged_in;
+
+/* List of addresses which the peer may use. */
+static struct permitted_ip *addresses[NUM_PPP];
+
+/* Wordlist giving addresses which the peer may use
+ without authenticating itself. */
+static struct wordlist *noauth_addrs;
+
+/* Extra options to apply, from the secrets file entry for the peer. */
+static struct wordlist *extra_options;
+
+/* Number of network protocols which we have opened. */
+static int num_np_open;
+
+/* Number of network protocols which have come up. */
+static int num_np_up;
+
+/* Set if we got the contents of passwd[] from the pap-secrets file. */
+static int passwd_from_file;
+
+/* Set if we require authentication only because we have a default route. */
+static bool default_auth;
+
+/* Hook to enable a plugin to control the idle time limit */
+int (*idle_time_hook) __P((struct ppp_idle *)) = NULL;
+
+/* Hook for a plugin to say whether we can possibly authenticate any peer */
+int (*pap_check_hook) __P((void)) = NULL;
+
+/* Hook for a plugin to check the PAP user and password */
+int (*pap_auth_hook) __P((char *user, char *passwd, char **msgp,
+ struct wordlist **paddrs,
+ struct wordlist **popts)) = NULL;
+
+/* Hook for a plugin to know about the PAP user logout */
+void (*pap_logout_hook) __P((void)) = NULL;
+
+/* Hook for a plugin to get the PAP password for authenticating us */
+int (*pap_passwd_hook) __P((char *user, char *passwd)) = NULL;
+
+/*
+ * This is used to ensure that we don't start an auth-up/down
+ * script while one is already running.
+ */
+enum script_state {
+ s_down,
+ s_up
+};
+
+static enum script_state auth_state = s_down;
+static enum script_state auth_script_state = s_down;
+static pid_t auth_script_pid = 0;
+
+static int used_login; /* peer authenticated against login database */
+
+/*
+ * Option variables.
+ */
+bool uselogin = 0; /* Use /etc/passwd for checking PAP */
+bool cryptpap = 0; /* Passwords in pap-secrets are encrypted */
+bool refuse_pap = 0; /* Don't wanna auth. ourselves with PAP */
+bool refuse_chap = 0; /* Don't wanna auth. ourselves with CHAP */
+bool usehostname = 0; /* Use hostname for our_name */
+bool auth_required = 0; /* Always require authentication from peer */
+bool allow_any_ip = 0; /* Allow peer to use any IP address */
+bool explicit_remote = 0; /* User specified explicit remote name */
+char remote_name[MAXNAMELEN]; /* Peer's name for authentication */
+
+static char *uafname; /* name of most recent +ua file */
+
+/* Bits in auth_pending[] */
+#define PAP_WITHPEER 1
+#define PAP_PEER 2
+#define CHAP_WITHPEER 4
+#define CHAP_PEER 8
+
+extern char *crypt __P((const char *, const char *));
+
+/* Prototypes for procedures local to this file. */
+
+static void network_phase __P((int));
+static void check_idle __P((void *));
+static void connect_time_expired __P((void *));
+static int plogin __P((char *, char *, char **));
+static void plogout __P((void));
+static int null_login __P((int));
+static int get_pap_passwd __P((char *));
+static int have_pap_secret __P((int *));
+static int have_chap_secret __P((char *, char *, int, int *));
+static int ip_addr_check __P((u_int32_t, struct permitted_ip *));
+static int scan_authfile __P((FILE *, char *, char *, char *,
+ struct wordlist **, struct wordlist **,
+ char *));
+static void free_wordlist __P((struct wordlist *));
+static void auth_script __P((char *));
+static void auth_script_done __P((void *));
+static void set_allowed_addrs __P((int, struct wordlist *, struct wordlist *));
+static int some_ip_ok __P((struct wordlist *));
+static int setupapfile __P((char **));
+static int privgroup __P((char **));
+static int set_noauth_addr __P((char **));
+static void check_access __P((FILE *, char *));
+static int wordlist_count __P((struct wordlist *));
+
+/*
+ * Authentication-related options.
+ */
+option_t auth_options[] = {
+ { "auth", o_bool, &auth_required,
+ "Require authentication from peer", OPT_PRIO | 1 },
+ { "noauth", o_bool, &auth_required,
+ "Don't require peer to authenticate", OPT_PRIOSUB | OPT_PRIV,
+ &allow_any_ip },
+ { "require-pap", o_bool, &lcp_wantoptions[0].neg_upap,
+ "Require PAP authentication from peer",
+ OPT_PRIOSUB | 1, &auth_required },
+ { "+pap", o_bool, &lcp_wantoptions[0].neg_upap,
+ "Require PAP authentication from peer",
+ OPT_ALIAS | OPT_PRIOSUB | 1, &auth_required },
+ { "require-chap", o_bool, &lcp_wantoptions[0].neg_chap,
+ "Require CHAP authentication from peer",
+ OPT_PRIOSUB | 1, &auth_required },
+ { "+chap", o_bool, &lcp_wantoptions[0].neg_chap,
+ "Require CHAP authentication from peer",
+ OPT_ALIAS | OPT_PRIOSUB | 1, &auth_required },
+
+ { "refuse-pap", o_bool, &refuse_pap,
+ "Don't agree to auth to peer with PAP", 1 },
+ { "-pap", o_bool, &refuse_pap,
+ "Don't allow PAP authentication with peer", OPT_ALIAS | 1 },
+
+ { "refuse-chap", o_bool, &refuse_chap,
+ "Don't agree to auth to peer with CHAP", 1 },
+ { "-chap", o_bool, &refuse_chap,
+ "Don't allow CHAP authentication with peer", OPT_ALIAS | 1 },
+
+ { "name", o_string, our_name,
+ "Set local name for authentication",
+ OPT_PRIO | OPT_PRIV | OPT_STATIC, NULL, MAXNAMELEN },
+
+ { "+ua", o_special, (void *)setupapfile,
+ "Get PAP user and password from file",
+ OPT_PRIO | OPT_A2STRVAL, &uafname },
+
+ { "user", o_string, user,
+ "Set name for auth with peer", OPT_PRIO | OPT_STATIC, NULL, MAXNAMELEN },
+
+ { "password", o_string, passwd,
+ "Password for authenticating us to the peer",
+ OPT_PRIO | OPT_STATIC | OPT_HIDE, NULL, MAXSECRETLEN },
+
+ { "usehostname", o_bool, &usehostname,
+ "Must use hostname for authentication", 1 },
+
+ { "remotename", o_string, remote_name,
+ "Set remote name for authentication", OPT_PRIO | OPT_STATIC,
+ &explicit_remote, MAXNAMELEN },
+
+ { "login", o_bool, &uselogin,
+ "Use system password database for PAP", 1 },
+
+ { "papcrypt", o_bool, &cryptpap,
+ "PAP passwords are encrypted", 1 },
+
+ { "privgroup", o_special, (void *)privgroup,
+ "Allow group members to use privileged options", OPT_PRIV | OPT_A2LIST },
+
+ { "allow-ip", o_special, (void *)set_noauth_addr,
+ "Set IP address(es) which can be used without authentication",
+ OPT_PRIV | OPT_A2LIST },
+
+ { NULL }
+};
+
+/*
+ * setupapfile - specifies UPAP info for authenticating with peer.
+ */
+static int
+setupapfile(argv)
+ char **argv;
+{
+ FILE *ufile;
+ int l;
+ char u[MAXNAMELEN], p[MAXSECRETLEN];
+ char *fname;
+
+ lcp_allowoptions[0].neg_upap = 1;
+
+ /* open user info file */
+ fname = strdup(*argv);
+ if (fname == NULL)
+ novm("+ua file name");
+ seteuid(getuid());
+ ufile = fopen(fname, "r");
+ seteuid(0);
+ if (ufile == NULL) {
+ option_error("unable to open user login data file %s", fname);
+ return 0;
+ }
+ check_access(ufile, fname);
+ uafname = fname;
+
+ /* get username */
+ if (fgets(u, MAXNAMELEN - 1, ufile) == NULL
+ || fgets(p, MAXSECRETLEN - 1, ufile) == NULL){
+ option_error("unable to read user login data file %s", fname);
+ return 0;
+ }
+ fclose(ufile);
+
+ /* get rid of newlines */
+ l = strlen(u);
+ if (l > 0 && u[l-1] == '\n')
+ u[l-1] = 0;
+ l = strlen(p);
+ if (l > 0 && p[l-1] == '\n')
+ p[l-1] = 0;
+
+ if (override_value("user", option_priority, fname))
+ strlcpy(user, u, sizeof(user));
+ if (override_value("passwd", option_priority, fname))
+ strlcpy(passwd, p, sizeof(passwd));
+
+ return (1);
+}
+
+
+/*
+ * privgroup - allow members of the group to have privileged access.
+ */
+static int
+privgroup(argv)
+ char **argv;
+{
+ struct group *g;
+ int i;
+
+ g = getgrnam(*argv);
+ if (g == 0) {
+ option_error("group %s is unknown", *argv);
+ return 0;
+ }
+ for (i = 0; i < ngroups; ++i) {
+ if (groups[i] == g->gr_gid) {
+ privileged = 1;
+ break;
+ }
+ }
+ return 1;
+}
+
+
+/*
+ * set_noauth_addr - set address(es) that can be used without authentication.
+ * Equivalent to specifying an entry like `"" * "" addr' in pap-secrets.
+ */
+static int
+set_noauth_addr(argv)
+ char **argv;
+{
+ char *addr = *argv;
+ int l = strlen(addr) + 1;
+ struct wordlist *wp;
+
+ wp = (struct wordlist *) malloc(sizeof(struct wordlist) + l);
+ if (wp == NULL)
+ novm("allow-ip argument");
+ wp->word = (char *) (wp + 1);
+ wp->next = noauth_addrs;
+ BCOPY(addr, wp->word, l);
+ noauth_addrs = wp;
+ return 1;
+}
+
+
+/*
+ * An Open on LCP has requested a change from Dead to Establish phase.
+ * Do what's necessary to bring the physical layer up.
+ */
+void
+link_required(unit)
+ int unit;
+{
+}
+
+/*
+ * LCP has terminated the link; go to the Dead phase and take the
+ * physical layer down.
+ */
+void
+link_terminated(unit)
+ int unit;
+{
+ if (phase == PHASE_DEAD)
+ return;
+ if (pap_logout_hook) {
+ pap_logout_hook();
+ } else {
+ if (logged_in)
+ plogout();
+ }
+ new_phase(PHASE_DEAD);
+ notice("Connection terminated.");
+}
+
+/*
+ * LCP has gone down; it will either die or try to re-establish.
+ */
+void
+link_down(unit)
+ int unit;
+{
+ int i;
+ struct protent *protp;
+
+ auth_state = s_down;
+ if (auth_script_state == s_up && auth_script_pid == 0) {
+ update_link_stats(unit);
+ auth_script_state = s_down;
+ auth_script(_PATH_AUTHDOWN);
+ }
+ for (i = 0; (protp = protocols[i]) != NULL; ++i) {
+ if (!protp->enabled_flag)
+ continue;
+ if (protp->protocol != PPP_LCP && protp->lowerdown != NULL)
+ (*protp->lowerdown)(unit);
+ if (protp->protocol < 0xC000 && protp->close != NULL)
+ (*protp->close)(unit, "LCP down");
+ }
+ num_np_open = 0;
+ num_np_up = 0;
+ if (phase != PHASE_DEAD)
+ new_phase(PHASE_TERMINATE);
+}
+
+/*
+ * The link is established.
+ * Proceed to the Dead, Authenticate or Network phase as appropriate.
+ */
+void
+link_established(unit)
+ int unit;
+{
+ int auth;
+ lcp_options *wo = &lcp_wantoptions[unit];
+ lcp_options *go = &lcp_gotoptions[unit];
+ lcp_options *ho = &lcp_hisoptions[unit];
+ int i;
+ struct protent *protp;
+
+ /*
+ * Tell higher-level protocols that LCP is up.
+ */
+ for (i = 0; (protp = protocols[i]) != NULL; ++i)
+ if (protp->protocol != PPP_LCP && protp->enabled_flag
+ && protp->lowerup != NULL)
+ (*protp->lowerup)(unit);
+
+ if (auth_required && !(go->neg_chap || go->neg_upap)) {
+ /*
+ * We wanted the peer to authenticate itself, and it refused:
+ * if we have some address(es) it can use without auth, fine,
+ * otherwise treat it as though it authenticated with PAP using
+ * a username * of "" and a password of "". If that's not OK,
+ * boot it out.
+ */
+ if (noauth_addrs != NULL) {
+ set_allowed_addrs(unit, NULL, NULL);
+ } else if (!wo->neg_upap || uselogin || !null_login(unit)) {
+ warn("peer refused to authenticate: terminating link");
+ lcp_close(unit, "peer refused to authenticate");
+ status = EXIT_PEER_AUTH_FAILED;
+ return;
+ }
+ }
+
+ new_phase(PHASE_AUTHENTICATE);
+ used_login = 0;
+ auth = 0;
+ if (go->neg_chap) {
+ ChapAuthPeer(unit, our_name, go->chap_mdtype);
+ auth |= CHAP_PEER;
+ } else if (go->neg_upap) {
+ upap_authpeer(unit);
+ auth |= PAP_PEER;
+ }
+ if (ho->neg_chap) {
+ ChapAuthWithPeer(unit, user, ho->chap_mdtype);
+ auth |= CHAP_WITHPEER;
+ } else if (ho->neg_upap) {
+ if (passwd[0] == 0) {
+ passwd_from_file = 1;
+ if (!get_pap_passwd(passwd))
+ error("No secret found for PAP login");
+ }
+ upap_authwithpeer(unit, user, passwd);
+ auth |= PAP_WITHPEER;
+ }
+ auth_pending[unit] = auth;
+
+ if (!auth)
+ network_phase(unit);
+}
+
+/*
+ * Proceed to the network phase.
+ */
+static void
+network_phase(unit)
+ int unit;
+{
+ lcp_options *go = &lcp_gotoptions[unit];
+
+ /*
+ * If the peer had to authenticate, run the auth-up script now.
+ */
+ if (go->neg_chap || go->neg_upap) {
+ auth_state = s_up;
+ if (auth_script_state == s_down && auth_script_pid == 0) {
+ auth_script_state = s_up;
+ auth_script(_PATH_AUTHUP);
+ }
+ }
+
+#ifdef CBCP_SUPPORT
+ /*
+ * If we negotiated callback, do it now.
+ */
+ if (go->neg_cbcp) {
+ new_phase(PHASE_CALLBACK);
+ (*cbcp_protent.open)(unit);
+ return;
+ }
+#endif
+
+ /*
+ * Process extra options from the secrets file
+ */
+ if (extra_options) {
+ options_from_list(extra_options, 1);
+ free_wordlist(extra_options);
+ extra_options = 0;
+ }
+ start_networks();
+}
+
+void
+start_networks()
+{
+ int i;
+ struct protent *protp;
+
+ new_phase(PHASE_NETWORK);
+
+#ifdef HAVE_MULTILINK
+ if (multilink) {
+ if (mp_join_bundle()) {
+ if (updetach && !nodetach)
+ detach();
+ return;
+ }
+ }
+#endif /* HAVE_MULTILINK */
+
+#ifdef PPP_FILTER
+ if (!demand)
+ set_filters(&pass_filter, &active_filter);
+#endif
+ for (i = 0; (protp = protocols[i]) != NULL; ++i)
+ if (protp->protocol < 0xC000 && protp->enabled_flag
+ && protp->open != NULL) {
+ (*protp->open)(0);
+ if (protp->protocol != PPP_CCP)
+ ++num_np_open;
+ }
+
+ if (num_np_open == 0)
+ /* nothing to do */
+ lcp_close(0, "No network protocols running");
+}
+
+/*
+ * The peer has failed to authenticate himself using `protocol'.
+ */
+void
+auth_peer_fail(unit, protocol)
+ int unit, protocol;
+{
+ /*
+ * Authentication failure: take the link down
+ */
+ lcp_close(unit, "Authentication failed");
+ status = EXIT_PEER_AUTH_FAILED;
+}
+
+/*
+ * The peer has been successfully authenticated using `protocol'.
+ */
+void
+auth_peer_success(unit, protocol, name, namelen)
+ int unit, protocol;
+ char *name;
+ int namelen;
+{
+ int bit;
+
+ switch (protocol) {
+ case PPP_CHAP:
+ bit = CHAP_PEER;
+ break;
+ case PPP_PAP:
+ bit = PAP_PEER;
+ break;
+ default:
+ warn("auth_peer_success: unknown protocol %x", protocol);
+ return;
+ }
+
+ /*
+ * Save the authenticated name of the peer for later.
+ */
+ if (namelen > sizeof(peer_authname) - 1)
+ namelen = sizeof(peer_authname) - 1;
+ BCOPY(name, peer_authname, namelen);
+ peer_authname[namelen] = 0;
+ script_setenv("PEERNAME", peer_authname, 0);
+
+ /*
+ * If there is no more authentication still to be done,
+ * proceed to the network (or callback) phase.
+ */
+ if ((auth_pending[unit] &= ~bit) == 0)
+ network_phase(unit);
+}
+
+/*
+ * We have failed to authenticate ourselves to the peer using `protocol'.
+ */
+void
+auth_withpeer_fail(unit, protocol)
+ int unit, protocol;
+{
+ if (passwd_from_file)
+ BZERO(passwd, MAXSECRETLEN);
+ /*
+ * We've failed to authenticate ourselves to our peer.
+ * Some servers keep sending CHAP challenges, but there
+ * is no point in persisting without any way to get updated
+ * authentication secrets.
+ */
+ lcp_close(unit, "Failed to authenticate ourselves to peer");
+ status = EXIT_AUTH_TOPEER_FAILED;
+}
+
+/*
+ * We have successfully authenticated ourselves with the peer using `protocol'.
+ */
+void
+auth_withpeer_success(unit, protocol)
+ int unit, protocol;
+{
+ int bit;
+
+ switch (protocol) {
+ case PPP_CHAP:
+ bit = CHAP_WITHPEER;
+ break;
+ case PPP_PAP:
+ if (passwd_from_file)
+ BZERO(passwd, MAXSECRETLEN);
+ bit = PAP_WITHPEER;
+ break;
+ default:
+ warn("auth_withpeer_success: unknown protocol %x", protocol);
+ bit = 0;
+ }
+
+ /*
+ * If there is no more authentication still being done,
+ * proceed to the network (or callback) phase.
+ */
+ if ((auth_pending[unit] &= ~bit) == 0)
+ network_phase(unit);
+}
+
+
+/*
+ * np_up - a network protocol has come up.
+ */
+void
+np_up(unit, proto)
+ int unit, proto;
+{
+ int tlim;
+
+ if (num_np_up == 0) {
+ /*
+ * At this point we consider that the link has come up successfully.
+ */
+ status = EXIT_OK;
+ unsuccess = 0;
+ new_phase(PHASE_RUNNING);
+
+ if (idle_time_hook != 0)
+ tlim = (*idle_time_hook)(NULL);
+ else
+ tlim = idle_time_limit;
+ if (tlim > 0)
+ TIMEOUT(check_idle, NULL, tlim);
+
+ /*
+ * Set a timeout to close the connection once the maximum
+ * connect time has expired.
+ */
+ if (maxconnect > 0)
+ TIMEOUT(connect_time_expired, 0, maxconnect);
+
+ /*
+ * Detach now, if the updetach option was given.
+ */
+ if (updetach && !nodetach)
+ detach();
+ }
+ ++num_np_up;
+}
+
+/*
+ * np_down - a network protocol has gone down.
+ */
+void
+np_down(unit, proto)
+ int unit, proto;
+{
+ if (--num_np_up == 0) {
+ UNTIMEOUT(check_idle, NULL);
+ new_phase(PHASE_NETWORK);
+ }
+}
+
+/*
+ * np_finished - a network protocol has finished using the link.
+ */
+void
+np_finished(unit, proto)
+ int unit, proto;
+{
+ if (--num_np_open <= 0) {
+ /* no further use for the link: shut up shop. */
+ lcp_close(0, "No network protocols running");
+ }
+}
+
+/*
+ * check_idle - check whether the link has been idle for long
+ * enough that we can shut it down.
+ */
+static void
+check_idle(arg)
+ void *arg;
+{
+ struct ppp_idle idle;
+ time_t itime;
+ int tlim;
+
+ if (!get_idle_time(0, &idle))
+ return;
+ if (idle_time_hook != 0) {
+ tlim = idle_time_hook(&idle);
+ } else {
+ itime = MIN(idle.xmit_idle, idle.recv_idle);
+ tlim = idle_time_limit - itime;
+ }
+ if (tlim <= 0) {
+ /* link is idle: shut it down. */
+ notice("Terminating connection due to lack of activity.");
+ lcp_close(0, "Link inactive");
+ need_holdoff = 0;
+ status = EXIT_IDLE_TIMEOUT;
+ } else {
+ TIMEOUT(check_idle, NULL, tlim);
+ }
+}
+
+/*
+ * connect_time_expired - log a message and close the connection.
+ */
+static void
+connect_time_expired(arg)
+ void *arg;
+{
+ info("Connect time expired");
+ lcp_close(0, "Connect time expired"); /* Close connection */
+ status = EXIT_CONNECT_TIME;
+}
+
+/*
+ * auth_check_options - called to check authentication options.
+ */
+void
+auth_check_options()
+{
+ lcp_options *wo = &lcp_wantoptions[0];
+ int can_auth;
+ int lacks_ip;
+
+ /* Default our_name to hostname, and user to our_name */
+ if (our_name[0] == 0 || usehostname)
+ strlcpy(our_name, hostname, sizeof(our_name));
+ if (user[0] == 0)
+ strlcpy(user, our_name, sizeof(user));
+
+ /*
+ * If we have a default route, require the peer to authenticate
+ * unless the noauth option was given or the real user is root.
+ */
+ if (!auth_required && !allow_any_ip && have_route_to(0) && !privileged) {
+ auth_required = 1;
+ default_auth = 1;
+ }
+
+ /* If authentication is required, ask peer for CHAP or PAP. */
+ if (auth_required) {
+ allow_any_ip = 0;
+ if (!wo->neg_chap && !wo->neg_upap) {
+ wo->neg_chap = 1;
+ wo->neg_upap = 1;
+ }
+ } else {
+ wo->neg_chap = 0;
+ wo->neg_upap = 0;
+ }
+
+ /*
+ * Check whether we have appropriate secrets to use
+ * to authenticate the peer.
+ */
+ lacks_ip = 0;
+ can_auth = wo->neg_upap && (uselogin || have_pap_secret(&lacks_ip));
+ if (!can_auth && wo->neg_chap) {
+ can_auth = have_chap_secret((explicit_remote? remote_name: NULL),
+ our_name, 1, &lacks_ip);
+ }
+
+ if (auth_required && !can_auth && noauth_addrs == NULL) {
+ if (default_auth) {
+ option_error(
+"By default the remote system is required to authenticate itself");
+ option_error(
+"(because this system has a default route to the internet)");
+ } else if (explicit_remote)
+ option_error(
+"The remote system (%s) is required to authenticate itself",
+ remote_name);
+ else
+ option_error(
+"The remote system is required to authenticate itself");
+ option_error(
+"but I couldn't find any suitable secret (password) for it to use to do so.");
+ if (lacks_ip)
+ option_error(
+"(None of the available passwords would let it use an IP address.)");
+
+ exit(1);
+ }
+}
+
+/*
+ * auth_reset - called when LCP is starting negotiations to recheck
+ * authentication options, i.e. whether we have appropriate secrets
+ * to use for authenticating ourselves and/or the peer.
+ */
+void
+auth_reset(unit)
+ int unit;
+{
+ lcp_options *go = &lcp_gotoptions[unit];
+ lcp_options *ao = &lcp_allowoptions[0];
+
+ ao->neg_upap = !refuse_pap && (passwd[0] != 0 || get_pap_passwd(NULL));
+ ao->neg_chap = !refuse_chap
+ && (passwd[0] != 0
+ || have_chap_secret(user, (explicit_remote? remote_name: NULL),
+ 0, NULL));
+
+ if (go->neg_upap && !uselogin && !have_pap_secret(NULL))
+ go->neg_upap = 0;
+ if (go->neg_chap) {
+ if (!have_chap_secret((explicit_remote? remote_name: NULL),
+ our_name, 1, NULL))
+ go->neg_chap = 0;
+ }
+}
+
+
+/*
+ * check_passwd - Check the user name and passwd against the PAP secrets
+ * file. If requested, also check against the system password database,
+ * and login the user if OK.
+ *
+ * returns:
+ * UPAP_AUTHNAK: Authentication failed.
+ * UPAP_AUTHACK: Authentication succeeded.
+ * In either case, msg points to an appropriate message.
+ */
+int
+check_passwd(unit, auser, userlen, apasswd, passwdlen, msg)
+ int unit;
+ char *auser;
+ int userlen;
+ char *apasswd;
+ int passwdlen;
+ char **msg;
+{
+ int ret;
+ char *filename;
+ FILE *f;
+ struct wordlist *addrs = NULL, *opts = NULL;
+ char passwd[256], user[256];
+ char secret[MAXWORDLEN];
+ static int attempts = 0;
+
+ /*
+ * Make copies of apasswd and auser, then null-terminate them.
+ * If there are unprintable characters in the password, make
+ * them visible.
+ */
+ slprintf(passwd, sizeof(passwd), "%.*v", passwdlen, apasswd);
+ slprintf(user, sizeof(user), "%.*v", userlen, auser);
+ *msg = "";
+
+ /*
+ * Check if a plugin wants to handle this.
+ */
+ if (pap_auth_hook) {
+ ret = (*pap_auth_hook)(user, passwd, msg, &addrs, &opts);
+ if (ret >= 0) {
+ if (ret)
+ set_allowed_addrs(unit, addrs, opts);
+ BZERO(passwd, sizeof(passwd));
+ if (addrs != 0)
+ free_wordlist(addrs);
+ return ret? UPAP_AUTHACK: UPAP_AUTHNAK;
+ }
+ }
+
+ /*
+ * Open the file of pap secrets and scan for a suitable secret
+ * for authenticating this user.
+ */
+ filename = _PATH_UPAPFILE;
+ addrs = opts = NULL;
+ ret = UPAP_AUTHNAK;
+ f = fopen(filename, "r");
+ if (f == NULL) {
+ error("Can't open PAP password file %s: %m", filename);
+
+ } else {
+ check_access(f, filename);
+ if (scan_authfile(f, user, our_name, secret, &addrs, &opts, filename) < 0) {
+ warn("no PAP secret found for %s", user);
+ } else {
+ /*
+ * If the secret is "@login", it means to check
+ * the password against the login database.
+ */
+ int login_secret = strcmp(secret, "@login") == 0;
+ ret = UPAP_AUTHACK;
+ if (uselogin || login_secret) {
+ /* login option or secret is @login */
+ ret = plogin(user, passwd, msg);
+ if (ret == UPAP_AUTHNAK)
+ warn("PAP login failure for %s", user);
+ else
+ used_login = 1;
+ }
+ if (secret[0] != 0 && !login_secret) {
+ /* password given in pap-secrets - must match */
+ if ((cryptpap || strcmp(passwd, secret) != 0)
+ && strcmp(crypt(passwd, secret), secret) != 0) {
+ ret = UPAP_AUTHNAK;
+ warn("PAP authentication failure for %s", user);
+ }
+ }
+ }
+ fclose(f);
+ }
+
+ if (ret == UPAP_AUTHNAK) {
+ if (**msg == 0)
+ *msg = "Login incorrect";
+ /*
+ * XXX can we ever get here more than once??
+ * Frustrate passwd stealer programs.
+ * Allow 10 tries, but start backing off after 3 (stolen from login).
+ * On 10'th, drop the connection.
+ */
+ if (attempts++ >= 10) {
+ warn("%d LOGIN FAILURES ON %s, %s", attempts, devnam, user);
+ lcp_close(unit, "login failed");
+ }
+ if (attempts > 3)
+ sleep((u_int) (attempts - 3) * 5);
+ if (opts != NULL)
+ free_wordlist(opts);
+
+ } else {
+ attempts = 0; /* Reset count */
+ if (**msg == 0)
+ *msg = "Login ok";
+ set_allowed_addrs(unit, addrs, opts);
+ }
+
+ if (addrs != NULL)
+ free_wordlist(addrs);
+ BZERO(passwd, sizeof(passwd));
+ BZERO(secret, sizeof(secret));
+
+ return ret;
+}
+
+/*
+ * This function is needed for PAM.
+ */
+
+#ifdef USE_PAM
+/* Static variables used to communicate between the conversation function
+ * and the server_login function
+ */
+static char *PAM_username;
+static char *PAM_password;
+static int PAM_error = 0;
+static pam_handle_t *pamh = NULL;
+
+/* PAM conversation function
+ * Here we assume (for now, at least) that echo on means login name, and
+ * echo off means password.
+ */
+
+static int PAM_conv (int num_msg, const struct pam_message **msg,
+ struct pam_response **resp, void *appdata_ptr)
+{
+ int replies = 0;
+ struct pam_response *reply = NULL;
+
+#define COPY_STRING(s) (s) ? strdup(s) : NULL
+
+ reply = malloc(sizeof(struct pam_response) * num_msg);
+ if (!reply) return PAM_CONV_ERR;
+
+ for (replies = 0; replies < num_msg; replies++) {
+ switch (msg[replies]->msg_style) {
+ case PAM_PROMPT_ECHO_ON:
+ reply[replies].resp_retcode = PAM_SUCCESS;
+ reply[replies].resp = COPY_STRING(PAM_username);
+ /* PAM frees resp */
+ break;
+ case PAM_PROMPT_ECHO_OFF:
+ reply[replies].resp_retcode = PAM_SUCCESS;
+ reply[replies].resp = COPY_STRING(PAM_password);
+ /* PAM frees resp */
+ break;
+ case PAM_TEXT_INFO:
+ /* fall through */
+ case PAM_ERROR_MSG:
+ /* ignore it, but pam still wants a NULL response... */
+ reply[replies].resp_retcode = PAM_SUCCESS;
+ reply[replies].resp = NULL;
+ break;
+ default:
+ /* Must be an error of some sort... */
+ free (reply);
+ PAM_error = 1;
+ return PAM_CONV_ERR;
+ }
+ }
+ *resp = reply;
+ return PAM_SUCCESS;
+}
+
+static struct pam_conv PAM_conversation = {
+ &PAM_conv,
+ NULL
+};
+#endif /* USE_PAM */
+
+/*
+ * plogin - Check the user name and password against the system
+ * password database, and login the user if OK.
+ *
+ * returns:
+ * UPAP_AUTHNAK: Login failed.
+ * UPAP_AUTHACK: Login succeeded.
+ * In either case, msg points to an appropriate message.
+ */
+
+static int
+plogin(user, passwd, msg)
+ char *user;
+ char *passwd;
+ char **msg;
+{
+ char *tty;
+
+#ifdef USE_PAM
+ int pam_error;
+
+ pam_error = pam_start ("ppp", user, &PAM_conversation, &pamh);
+ if (pam_error != PAM_SUCCESS) {
+ *msg = (char *) pam_strerror (pamh, pam_error);
+ reopen_log();
+ return UPAP_AUTHNAK;
+ }
+ /*
+ * Define the fields for the credential validation
+ */
+
+ PAM_username = user;
+ PAM_password = passwd;
+ PAM_error = 0;
+ pam_set_item (pamh, PAM_TTY, devnam); /* this might be useful to some modules */
+
+ /*
+ * Validate the user
+ */
+ pam_error = pam_authenticate (pamh, PAM_SILENT);
+ if (pam_error == PAM_SUCCESS && !PAM_error) {
+ pam_error = pam_acct_mgmt (pamh, PAM_SILENT);
+ if (pam_error == PAM_SUCCESS)
+ pam_error = pam_open_session (pamh, PAM_SILENT);
+ }
+
+ *msg = (char *) pam_strerror (pamh, pam_error);
+
+ /*
+ * Clean up the mess
+ */
+ reopen_log(); /* apparently the PAM stuff does closelog() */
+ PAM_username = NULL;
+ PAM_password = NULL;
+ if (pam_error != PAM_SUCCESS)
+ return UPAP_AUTHNAK;
+#else /* #ifdef USE_PAM */
+
+/*
+ * Use the non-PAM methods directly
+ */
+
+#ifdef HAS_SHADOW
+ struct spwd *spwd;
+ struct spwd *getspnam();
+#endif
+ struct passwd *pw = getpwnam(user);
+
+ endpwent();
+ if (pw == NULL)
+ return (UPAP_AUTHNAK);
+
+#ifdef HAS_SHADOW
+ spwd = getspnam(user);
+ endspent();
+ if (spwd) {
+ /* check the age of the password entry */
+ long now = time(NULL) / 86400L;
+
+ if ((spwd->sp_expire > 0 && now >= spwd->sp_expire)
+ || ((spwd->sp_max >= 0 && spwd->sp_max < 10000)
+ && spwd->sp_lstchg >= 0
+ && now >= spwd->sp_lstchg + spwd->sp_max)) {
+ warn("Password for %s has expired", user);
+ return (UPAP_AUTHNAK);
+ }
+ pw->pw_passwd = spwd->sp_pwdp;
+ }
+#endif
+
+ /*
+ * If no passwd, don't let them login.
+ */
+ if (pw->pw_passwd == NULL || strlen(pw->pw_passwd) < 2
+ || strcmp(crypt(passwd, pw->pw_passwd), pw->pw_passwd) != 0)
+ return (UPAP_AUTHNAK);
+
+#endif /* #ifdef USE_PAM */
+
+ /*
+ * Write a wtmp entry for this user.
+ */
+
+ tty = devnam;
+ if (strncmp(tty, "/dev/", 5) == 0)
+ tty += 5;
+// logwtmp(tty, user, remote_name); /* Add wtmp login entry */
+
+#if defined(_PATH_LASTLOG) && !defined(USE_PAM)
+ if (pw != (struct passwd *)NULL) {
+ struct lastlog ll;
+ int fd;
+
+ if ((fd = open(_PATH_LASTLOG, O_RDWR, 0)) >= 0) {
+ (void)lseek(fd, (off_t)(pw->pw_uid * sizeof(ll)), SEEK_SET);
+ memset((void *)&ll, 0, sizeof(ll));
+ (void)time(&ll.ll_time);
+ (void)strncpy(ll.ll_line, tty, sizeof(ll.ll_line));
+ (void)write(fd, (char *)&ll, sizeof(ll));
+ (void)close(fd);
+ }
+ }
+#endif /* _PATH_LASTLOG and not USE_PAM */
+
+ info("user %s logged in", user);
+ logged_in = 1;
+
+ return (UPAP_AUTHACK);
+}
+
+/*
+ * plogout - Logout the user.
+ */
+static void
+plogout()
+{
+#ifdef USE_PAM
+ int pam_error;
+
+ if (pamh != NULL) {
+ pam_error = pam_close_session (pamh, PAM_SILENT);
+ pam_end (pamh, pam_error);
+ pamh = NULL;
+ }
+ /* Apparently the pam stuff does closelog(). */
+ reopen_log();
+#else /* ! USE_PAM */
+ char *tty;
+
+ tty = devnam;
+ if (strncmp(tty, "/dev/", 5) == 0)
+ tty += 5;
+// logwtmp(tty, "", ""); /* Wipe out utmp logout entry */
+#endif /* ! USE_PAM */
+ logged_in = 0;
+}
+
+
+/*
+ * null_login - Check if a username of "" and a password of "" are
+ * acceptable, and iff so, set the list of acceptable IP addresses
+ * and return 1.
+ */
+static int
+null_login(unit)
+ int unit;
+{
+ char *filename;
+ FILE *f;
+ int i, ret;
+ struct wordlist *addrs, *opts;
+ char secret[MAXWORDLEN];
+
+ /*
+ * Open the file of pap secrets and scan for a suitable secret.
+ */
+ filename = _PATH_UPAPFILE;
+ addrs = NULL;
+ f = fopen(filename, "r");
+ if (f == NULL)
+ return 0;
+ check_access(f, filename);
+
+ i = scan_authfile(f, "", our_name, secret, &addrs, &opts, filename);
+ ret = i >= 0 && secret[0] == 0;
+ BZERO(secret, sizeof(secret));
+
+ if (ret)
+ set_allowed_addrs(unit, addrs, opts);
+ else if (opts != 0)
+ free_wordlist(opts);
+ if (addrs != 0)
+ free_wordlist(addrs);
+
+ fclose(f);
+ return ret;
+}
+
+
+/*
+ * get_pap_passwd - get a password for authenticating ourselves with
+ * our peer using PAP. Returns 1 on success, 0 if no suitable password
+ * could be found.
+ * Assumes passwd points to MAXSECRETLEN bytes of space (if non-null).
+ */
+static int
+get_pap_passwd(passwd)
+ char *passwd;
+{
+ char *filename;
+ FILE *f;
+ int ret;
+ char secret[MAXWORDLEN];
+
+ /*
+ * Check whether a plugin wants to supply this.
+ */
+ if (pap_passwd_hook) {
+ ret = (*pap_passwd_hook)(user, passwd);
+ if (ret >= 0)
+ return ret;
+ }
+
+ filename = _PATH_UPAPFILE;
+ f = fopen(filename, "r");
+ if (f == NULL)
+ return 0;
+ check_access(f, filename);
+ ret = scan_authfile(f, user,
+ (remote_name[0]? remote_name: NULL),
+ secret, NULL, NULL, filename);
+ fclose(f);
+ if (ret < 0)
+ return 0;
+ if (passwd != NULL)
+ strlcpy(passwd, secret, MAXSECRETLEN);
+ BZERO(secret, sizeof(secret));
+ return 1;
+}
+
+
+/*
+ * have_pap_secret - check whether we have a PAP file with any
+ * secrets that we could possibly use for authenticating the peer.
+ */
+static int
+have_pap_secret(lacks_ipp)
+ int *lacks_ipp;
+{
+ FILE *f;
+ int ret;
+ char *filename;
+ struct wordlist *addrs;
+
+ /* let the plugin decide, if there is one */
+ if (pap_check_hook) {
+ ret = (*pap_check_hook)();
+ if (ret >= 0)
+ return ret;
+ }
+
+ filename = _PATH_UPAPFILE;
+ f = fopen(filename, "r");
+ if (f == NULL)
+ return 0;
+
+ ret = scan_authfile(f, (explicit_remote? remote_name: NULL), our_name,
+ NULL, &addrs, NULL, filename);
+ fclose(f);
+ if (ret >= 0 && !some_ip_ok(addrs)) {
+ if (lacks_ipp != 0)
+ *lacks_ipp = 1;
+ ret = -1;
+ }
+ if (addrs != 0)
+ free_wordlist(addrs);
+
+ return ret >= 0;
+}
+
+
+/*
+ * have_chap_secret - check whether we have a CHAP file with a
+ * secret that we could possibly use for authenticating `client'
+ * on `server'. Either can be the null string, meaning we don't
+ * know the identity yet.
+ */
+static int
+have_chap_secret(client, server, need_ip, lacks_ipp)
+ char *client;
+ char *server;
+ int need_ip;
+ int *lacks_ipp;
+{
+ FILE *f;
+ int ret;
+ char *filename;
+ struct wordlist *addrs;
+
+ filename = _PATH_CHAPFILE;
+ f = fopen(filename, "r");
+ if (f == NULL)
+ return 0;
+
+ if (client != NULL && client[0] == 0)
+ client = NULL;
+ else if (server != NULL && server[0] == 0)
+ server = NULL;
+
+ ret = scan_authfile(f, client, server, NULL, &addrs, NULL, filename);
+ fclose(f);
+ if (ret >= 0 && need_ip && !some_ip_ok(addrs)) {
+ if (lacks_ipp != 0)
+ *lacks_ipp = 1;
+ ret = -1;
+ }
+ if (addrs != 0)
+ free_wordlist(addrs);
+
+ return ret >= 0;
+}
+
+
+/*
+ * get_secret - open the CHAP secret file and return the secret
+ * for authenticating the given client on the given server.
+ * (We could be either client or server).
+ */
+int
+get_secret(unit, client, server, secret, secret_len, am_server)
+ int unit;
+ char *client;
+ char *server;
+ char *secret;
+ int *secret_len;
+ int am_server;
+{
+ FILE *f;
+ int ret, len;
+ char *filename;
+ struct wordlist *addrs, *opts;
+ char secbuf[MAXWORDLEN];
+
+ if (!am_server && passwd[0] != 0) {
+ strlcpy(secbuf, passwd, sizeof(secbuf));
+ } else {
+ filename = _PATH_CHAPFILE;
+ addrs = NULL;
+ secbuf[0] = 0;
+
+ f = fopen(filename, "r");
+ if (f == NULL) {
+ error("Can't open chap secret file %s: %m", filename);
+ return 0;
+ }
+ check_access(f, filename);
+
+ ret = scan_authfile(f, client, server, secbuf, &addrs, &opts, filename);
+ fclose(f);
+ if (ret < 0)
+ return 0;
+
+ if (am_server)
+ set_allowed_addrs(unit, addrs, opts);
+ else if (opts != 0)
+ free_wordlist(opts);
+ if (addrs != 0)
+ free_wordlist(addrs);
+ }
+
+ len = strlen(secbuf);
+ if (len > MAXSECRETLEN) {
+ error("Secret for %s on %s is too long", client, server);
+ len = MAXSECRETLEN;
+ }
+ BCOPY(secbuf, secret, len);
+ BZERO(secbuf, sizeof(secbuf));
+ *secret_len = len;
+
+ return 1;
+}
+
+/*
+ * set_allowed_addrs() - set the list of allowed addresses.
+ * Also looks for `--' indicating options to apply for this peer
+ * and leaves the following words in extra_options.
+ */
+static void
+set_allowed_addrs(unit, addrs, opts)
+ int unit;
+ struct wordlist *addrs;
+ struct wordlist *opts;
+{
+ int n;
+ struct wordlist *ap, **plink;
+ struct permitted_ip *ip;
+ char *ptr_word, *ptr_mask;
+ struct hostent *hp;
+ u_int32_t a, mask, offset;
+ struct ipcp_options *wo = &ipcp_wantoptions[unit];
+ u_int32_t suggested_ip = 0;
+
+ if (addresses[unit] != NULL)
+ free(addresses[unit]);
+ addresses[unit] = NULL;
+ if (extra_options != NULL)
+ free_wordlist(extra_options);
+ extra_options = opts;
+
+ /*
+ * Count the number of IP addresses given.
+ */
+ n = wordlist_count(addrs) + wordlist_count(noauth_addrs);
+ if (n == 0)
+ return;
+ ip = (struct permitted_ip *) malloc((n + 1) * sizeof(struct permitted_ip));
+ if (ip == 0)
+ return;
+
+ /* temporarily append the noauth_addrs list to addrs */
+ for (plink = &addrs; *plink != NULL; plink = &(*plink)->next)
+ ;
+ *plink = noauth_addrs;
+
+ n = 0;
+ for (ap = addrs; ap != NULL; ap = ap->next) {
+ /* "-" means no addresses authorized, "*" means any address allowed */
+ ptr_word = ap->word;
+ if (strcmp(ptr_word, "-") == 0)
+ break;
+ if (strcmp(ptr_word, "*") == 0) {
+ ip[n].permit = 1;
+ ip[n].base = ip[n].mask = 0;
+ ++n;
+ break;
+ }
+
+ ip[n].permit = 1;
+ if (*ptr_word == '!') {
+ ip[n].permit = 0;
+ ++ptr_word;
+ }
+
+ mask = ~ (u_int32_t) 0;
+ offset = 0;
+ ptr_mask = strchr (ptr_word, '/');
+ if (ptr_mask != NULL) {
+ int bit_count;
+ char *endp;
+
+ bit_count = (int) strtol (ptr_mask+1, &endp, 10);
+ if (bit_count <= 0 || bit_count > 32) {
+ warn("invalid address length %v in auth. address list",
+ ptr_mask+1);
+ continue;
+ }
+ bit_count = 32 - bit_count; /* # bits in host part */
+ if (*endp == '+') {
+ offset = ifunit + 1;
+ ++endp;
+ }
+ if (*endp != 0) {
+ warn("invalid address length syntax: %v", ptr_mask+1);
+ continue;
+ }
+ *ptr_mask = '\0';
+ mask <<= bit_count;
+ }
+
+ hp = gethostbyname(ptr_word);
+ if (hp != NULL && hp->h_addrtype == AF_INET) {
+ a = *(u_int32_t *)hp->h_addr;
+ } else {
+ printf("*** getnetbyname is unsupported, please report bug! ***\n");
+ return;
+ }
+
+ if (ptr_mask != NULL)
+ *ptr_mask = '/';
+
+ if (a == (u_int32_t)-1L) {
+ warn("unknown host %s in auth. address list", ap->word);
+ continue;
+ }
+ if (offset != 0) {
+ if (offset >= ~mask) {
+ warn("interface unit %d too large for subnet %v",
+ ifunit, ptr_word);
+ continue;
+ }
+ a = htonl((ntohl(a) & mask) + offset);
+ mask = ~(u_int32_t)0;
+ }
+ ip[n].mask = htonl(mask);
+ ip[n].base = a & ip[n].mask;
+ ++n;
+ if (~mask == 0 && suggested_ip == 0)
+ suggested_ip = a;
+ }
+ *plink = NULL;
+
+ ip[n].permit = 0; /* make the last entry forbid all addresses */
+ ip[n].base = 0; /* to terminate the list */
+ ip[n].mask = 0;
+
+ addresses[unit] = ip;
+
+ /*
+ * If the address given for the peer isn't authorized, or if
+ * the user hasn't given one, AND there is an authorized address
+ * which is a single host, then use that if we find one.
+ */
+ if (suggested_ip != 0
+ && (wo->hisaddr == 0 || !auth_ip_addr(unit, wo->hisaddr))) {
+ wo->hisaddr = suggested_ip;
+ /*
+ * Do we insist on this address? No, if there are other
+ * addresses authorized than the suggested one.
+ */
+ if (n > 1)
+ wo->accept_remote = 1;
+ }
+}
+
+/*
+ * auth_ip_addr - check whether the peer is authorized to use
+ * a given IP address. Returns 1 if authorized, 0 otherwise.
+ */
+int
+auth_ip_addr(unit, addr)
+ int unit;
+ u_int32_t addr;
+{
+ int ok;
+
+ /* don't allow loopback or multicast address */
+ if (bad_ip_adrs(addr))
+ return 0;
+
+ if (addresses[unit] != NULL) {
+ ok = ip_addr_check(addr, addresses[unit]);
+ if (ok >= 0)
+ return ok;
+ }
+ if (auth_required)
+ return 0; /* no addresses authorized */
+ return allow_any_ip || privileged || !have_route_to(addr);
+}
+
+static int
+ip_addr_check(addr, addrs)
+ u_int32_t addr;
+ struct permitted_ip *addrs;
+{
+ for (; ; ++addrs)
+ if ((addr & addrs->mask) == addrs->base)
+ return addrs->permit;
+}
+
+/*
+ * bad_ip_adrs - return 1 if the IP address is one we don't want
+ * to use, such as an address in the loopback net or a multicast address.
+ * addr is in network byte order.
+ */
+int
+bad_ip_adrs(addr)
+ u_int32_t addr;
+{
+ addr = ntohl(addr);
+ return (addr >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET
+ || IN_MULTICAST(addr) || IN_BADCLASS(addr);
+}
+
+/*
+ * some_ip_ok - check a wordlist to see if it authorizes any
+ * IP address(es).
+ */
+static int
+some_ip_ok(addrs)
+ struct wordlist *addrs;
+{
+ for (; addrs != 0; addrs = addrs->next) {
+ if (addrs->word[0] == '-')
+ break;
+ if (addrs->word[0] != '!')
+ return 1; /* some IP address is allowed */
+ }
+ return 0;
+}
+
+/*
+ * check_access - complain if a secret file has too-liberal permissions.
+ */
+static void
+check_access(f, filename)
+ FILE *f;
+ char *filename;
+{
+ struct stat sbuf;
+
+ if (fstat(fileno(f), &sbuf) < 0) {
+ warn("cannot stat secret file %s: %m", filename);
+ } else if ((sbuf.st_mode & (S_IRWXG | S_IRWXO)) != 0) {
+ warn("Warning - secret file %s has world and/or group access",
+ filename);
+ }
+}
+
+
+/*
+ * scan_authfile - Scan an authorization file for a secret suitable
+ * for authenticating `client' on `server'. The return value is -1
+ * if no secret is found, otherwise >= 0. The return value has
+ * NONWILD_CLIENT set if the secret didn't have "*" for the client, and
+ * NONWILD_SERVER set if the secret didn't have "*" for the server.
+ * Any following words on the line up to a "--" (i.e. address authorization
+ * info) are placed in a wordlist and returned in *addrs. Any
+ * following words (extra options) are placed in a wordlist and
+ * returned in *opts.
+ * We assume secret is NULL or points to MAXWORDLEN bytes of space.
+ */
+static int
+scan_authfile(f, client, server, secret, addrs, opts, filename)
+ FILE *f;
+ char *client;
+ char *server;
+ char *secret;
+ struct wordlist **addrs;
+ struct wordlist **opts;
+ char *filename;
+{
+ int newline, xxx;
+ int got_flag, best_flag;
+ FILE *sf;
+ struct wordlist *ap, *addr_list, *alist, **app;
+ char word[MAXWORDLEN];
+ char atfile[MAXWORDLEN];
+ char lsecret[MAXWORDLEN];
+
+ if (addrs != NULL)
+ *addrs = NULL;
+ if (opts != NULL)
+ *opts = NULL;
+ addr_list = NULL;
+ if (!getword(f, word, &newline, filename))
+ return -1; /* file is empty??? */
+ newline = 1;
+ best_flag = -1;
+ for (;;) {
+ /*
+ * Skip until we find a word at the start of a line.
+ */
+ while (!newline && getword(f, word, &newline, filename))
+ ;
+ if (!newline)
+ break; /* got to end of file */
+
+ /*
+ * Got a client - check if it's a match or a wildcard.
+ */
+ got_flag = 0;
+ if (client != NULL && strcmp(word, client) != 0 && !ISWILD(word)) {
+ newline = 0;
+ continue;
+ }
+ if (!ISWILD(word))
+ got_flag = NONWILD_CLIENT;
+
+ /*
+ * Now get a server and check if it matches.
+ */
+ if (!getword(f, word, &newline, filename))
+ break;
+ if (newline)
+ continue;
+ if (!ISWILD(word)) {
+ if (server != NULL && strcmp(word, server) != 0)
+ continue;
+ got_flag |= NONWILD_SERVER;
+ }
+
+ /*
+ * Got some sort of a match - see if it's better than what
+ * we have already.
+ */
+ if (got_flag <= best_flag)
+ continue;
+
+ /*
+ * Get the secret.
+ */
+ if (!getword(f, word, &newline, filename))
+ break;
+ if (newline)
+ continue;
+
+ if (secret != NULL) {
+ /*
+ * Special syntax: @/pathname means read secret from file.
+ */
+ if (word[0] == '@' && word[1] == '/') {
+ strlcpy(atfile, word+1, sizeof(atfile));
+ if ((sf = fopen(atfile, "r")) == NULL) {
+ warn("can't open indirect secret file %s", atfile);
+ continue;
+ }
+ check_access(sf, atfile);
+ if (!getword(sf, word, &xxx, atfile)) {
+ warn("no secret in indirect secret file %s", atfile);
+ fclose(sf);
+ continue;
+ }
+ fclose(sf);
+ }
+ strlcpy(lsecret, word, sizeof(lsecret));
+ }
+
+ /*
+ * Now read address authorization info and make a wordlist.
+ */
+ app = &alist;
+ for (;;) {
+ if (!getword(f, word, &newline, filename) || newline)
+ break;
+ ap = (struct wordlist *)
+ malloc(sizeof(struct wordlist) + strlen(word) + 1);
+ if (ap == NULL)
+ novm("authorized addresses");
+ ap->word = (char *) (ap + 1);
+ strcpy(ap->word, word);
+ *app = ap;
+ app = &ap->next;
+ }
+ *app = NULL;
+
+ /*
+ * This is the best so far; remember it.
+ */
+ best_flag = got_flag;
+ if (addr_list)
+ free_wordlist(addr_list);
+ addr_list = alist;
+ if (secret != NULL)
+ strlcpy(secret, lsecret, MAXWORDLEN);
+
+ if (!newline)
+ break;
+ }
+
+ /* scan for a -- word indicating the start of options */
+ for (app = &addr_list; (ap = *app) != NULL; app = &ap->next)
+ if (strcmp(ap->word, "--") == 0)
+ break;
+ /* ap = start of options */
+ if (ap != NULL) {
+ ap = ap->next; /* first option */
+ free(*app); /* free the "--" word */
+ *app = NULL; /* terminate addr list */
+ }
+ if (opts != NULL)
+ *opts = ap;
+ else if (ap != NULL)
+ free_wordlist(ap);
+ if (addrs != NULL)
+ *addrs = addr_list;
+ else if (addr_list != NULL)
+ free_wordlist(addr_list);
+
+ return best_flag;
+}
+
+/*
+ * wordlist_count - return the number of items in a wordlist
+ */
+static int
+wordlist_count(wp)
+ struct wordlist *wp;
+{
+ int n;
+
+ for (n = 0; wp != NULL; wp = wp->next)
+ ++n;
+ return n;
+}
+
+/*
+ * free_wordlist - release memory allocated for a wordlist.
+ */
+static void
+free_wordlist(wp)
+ struct wordlist *wp;
+{
+ struct wordlist *next;
+
+ while (wp != NULL) {
+ next = wp->next;
+ free(wp);
+ wp = next;
+ }
+}
+
+/*
+ * auth_script_done - called when the auth-up or auth-down script
+ * has finished.
+ */
+static void
+auth_script_done(arg)
+ void *arg;
+{
+ auth_script_pid = 0;
+ switch (auth_script_state) {
+ case s_up:
+ if (auth_state == s_down) {
+ auth_script_state = s_down;
+ auth_script(_PATH_AUTHDOWN);
+ }
+ break;
+ case s_down:
+ if (auth_state == s_up) {
+ auth_script_state = s_up;
+ auth_script(_PATH_AUTHUP);
+ }
+ break;
+ }
+}
+
+/*
+ * auth_script - execute a script with arguments
+ * interface-name peer-name real-user tty speed
+ */
+static void
+auth_script(script)
+ char *script;
+{
+ char strspeed[32];
+ struct passwd *pw;
+ char struid[32];
+ char *user_name;
+ char *argv[8];
+
+ if ((pw = getpwuid(getuid())) != NULL && pw->pw_name != NULL)
+ user_name = pw->pw_name;
+ else {
+ slprintf(struid, sizeof(struid), "%d", getuid());
+ user_name = struid;
+ }
+ slprintf(strspeed, sizeof(strspeed), "%d", baud_rate);
+
+ argv[0] = script;
+ argv[1] = ifname;
+ argv[2] = peer_authname;
+ argv[3] = user_name;
+ argv[4] = devnam;
+ argv[5] = strspeed;
+ argv[6] = NULL;
+
+ auth_script_pid = run_program(script, argv, 0, auth_script_done, NULL);
+}
diff --git a/mdk-stage1/ppp/pppd/cbcp.c b/mdk-stage1/ppp/pppd/cbcp.c
new file mode 100644
index 000000000..b286ef9f9
--- /dev/null
+++ b/mdk-stage1/ppp/pppd/cbcp.c
@@ -0,0 +1,456 @@
+/*
+ * cbcp - Call Back Configuration Protocol.
+ *
+ * Copyright (c) 1995 Pedro Roque Marques
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Pedro Roque Marques. The name of the author may not be used to
+ * endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#define RCSID "$Id: cbcp.c 195720 2001-06-11 11:44:34Z gc $"
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/time.h>
+
+#include "pppd.h"
+#include "cbcp.h"
+#include "fsm.h"
+#include "lcp.h"
+
+static const char rcsid[] = RCSID;
+
+/*
+ * Options.
+ */
+static int setcbcp __P((char **));
+
+static option_t cbcp_option_list[] = {
+ { "callback", o_special, setcbcp,
+ "Ask for callback", OPT_PRIO | OPT_A2STRVAL, &cbcp[0].us_number },
+ { NULL }
+};
+
+/*
+ * Protocol entry points.
+ */
+static void cbcp_init __P((int unit));
+static void cbcp_open __P((int unit));
+static void cbcp_lowerup __P((int unit));
+static void cbcp_input __P((int unit, u_char *pkt, int len));
+static void cbcp_protrej __P((int unit));
+static int cbcp_printpkt __P((u_char *pkt, int len,
+ void (*printer) __P((void *, char *, ...)),
+ void *arg));
+
+struct protent cbcp_protent = {
+ PPP_CBCP,
+ cbcp_init,
+ cbcp_input,
+ cbcp_protrej,
+ cbcp_lowerup,
+ NULL,
+ cbcp_open,
+ NULL,
+ cbcp_printpkt,
+ NULL,
+ 0,
+ "CBCP",
+ NULL,
+ cbcp_option_list,
+ NULL,
+ NULL,
+ NULL
+};
+
+cbcp_state cbcp[NUM_PPP];
+
+/* internal prototypes */
+
+static void cbcp_recvreq __P((cbcp_state *us, char *pckt, int len));
+static void cbcp_resp __P((cbcp_state *us));
+static void cbcp_up __P((cbcp_state *us));
+static void cbcp_recvack __P((cbcp_state *us, char *pckt, int len));
+static void cbcp_send __P((cbcp_state *us, u_char code, u_char *buf, int len));
+
+/* option processing */
+static int
+setcbcp(argv)
+ char **argv;
+{
+ lcp_wantoptions[0].neg_cbcp = 1;
+ cbcp_protent.enabled_flag = 1;
+ cbcp[0].us_number = strdup(*argv);
+ if (cbcp[0].us_number == 0)
+ novm("callback number");
+ cbcp[0].us_type |= (1 << CB_CONF_USER);
+ cbcp[0].us_type |= (1 << CB_CONF_ADMIN);
+ return (1);
+}
+
+/* init state */
+static void
+cbcp_init(iface)
+ int iface;
+{
+ cbcp_state *us;
+
+ us = &cbcp[iface];
+ memset(us, 0, sizeof(cbcp_state));
+ us->us_unit = iface;
+ us->us_type |= (1 << CB_CONF_NO);
+}
+
+/* lower layer is up */
+static void
+cbcp_lowerup(iface)
+ int iface;
+{
+ cbcp_state *us = &cbcp[iface];
+
+ dbglog("cbcp_lowerup");
+ dbglog("want: %d", us->us_type);
+
+ if (us->us_type == CB_CONF_USER)
+ dbglog("phone no: %s", us->us_number);
+}
+
+static void
+cbcp_open(unit)
+ int unit;
+{
+ dbglog("cbcp_open");
+}
+
+/* process an incomming packet */
+static void
+cbcp_input(unit, inpacket, pktlen)
+ int unit;
+ u_char *inpacket;
+ int pktlen;
+{
+ u_char *inp;
+ u_char code, id;
+ u_short len;
+
+ cbcp_state *us = &cbcp[unit];
+
+ inp = inpacket;
+
+ if (pktlen < CBCP_MINLEN) {
+ error("CBCP packet is too small");
+ return;
+ }
+
+ GETCHAR(code, inp);
+ GETCHAR(id, inp);
+ GETSHORT(len, inp);
+
+#if 0
+ if (len > pktlen) {
+ error("CBCP packet: invalid length");
+ return;
+ }
+#endif
+
+ len -= CBCP_MINLEN;
+
+ switch(code) {
+ case CBCP_REQ:
+ us->us_id = id;
+ cbcp_recvreq(us, inp, len);
+ break;
+
+ case CBCP_RESP:
+ dbglog("CBCP_RESP received");
+ break;
+
+ case CBCP_ACK:
+ if (id != us->us_id)
+ dbglog("id doesn't match: expected %d recv %d",
+ us->us_id, id);
+
+ cbcp_recvack(us, inp, len);
+ break;
+
+ default:
+ break;
+ }
+}
+
+/* protocol was rejected by foe */
+void cbcp_protrej(int iface)
+{
+}
+
+char *cbcp_codenames[] = {
+ "Request", "Response", "Ack"
+};
+
+char *cbcp_optionnames[] = {
+ "NoCallback",
+ "UserDefined",
+ "AdminDefined",
+ "List"
+};
+
+/* pretty print a packet */
+static int
+cbcp_printpkt(p, plen, printer, arg)
+ u_char *p;
+ int plen;
+ void (*printer) __P((void *, char *, ...));
+ void *arg;
+{
+ int code, opt, id, len, olen, delay;
+ u_char *pstart;
+
+ if (plen < HEADERLEN)
+ return 0;
+ pstart = p;
+ GETCHAR(code, p);
+ GETCHAR(id, p);
+ GETSHORT(len, p);
+ if (len < HEADERLEN || len > plen)
+ return 0;
+
+ if (code >= 1 && code <= sizeof(cbcp_codenames) / sizeof(char *))
+ printer(arg, " %s", cbcp_codenames[code-1]);
+ else
+ printer(arg, " code=0x%x", code);
+
+ printer(arg, " id=0x%x", id);
+ len -= HEADERLEN;
+
+ switch (code) {
+ case CBCP_REQ:
+ case CBCP_RESP:
+ case CBCP_ACK:
+ while(len >= 2) {
+ GETCHAR(opt, p);
+ GETCHAR(olen, p);
+
+ if (olen < 2 || olen > len) {
+ break;
+ }
+
+ printer(arg, " <");
+ len -= olen;
+
+ if (opt >= 1 && opt <= sizeof(cbcp_optionnames) / sizeof(char *))
+ printer(arg, " %s", cbcp_optionnames[opt-1]);
+ else
+ printer(arg, " option=0x%x", opt);
+
+ if (olen > 2) {
+ GETCHAR(delay, p);
+ printer(arg, " delay = %d", delay);
+ }
+
+ if (olen > 3) {
+ int addrt;
+ char str[256];
+
+ GETCHAR(addrt, p);
+ memcpy(str, p, olen - 4);
+ str[olen - 4] = 0;
+ printer(arg, " number = %s", str);
+ }
+ printer(arg, ">");
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ for (; len > 0; --len) {
+ GETCHAR(code, p);
+ printer(arg, " %.2x", code);
+ }
+
+ return p - pstart;
+}
+
+/* received CBCP request */
+static void
+cbcp_recvreq(us, pckt, pcktlen)
+ cbcp_state *us;
+ char *pckt;
+ int pcktlen;
+{
+ u_char type, opt_len, delay, addr_type;
+ char address[256];
+ int len = pcktlen;
+
+ address[0] = 0;
+
+ while (len) {
+ dbglog("length: %d", len);
+
+ GETCHAR(type, pckt);
+ GETCHAR(opt_len, pckt);
+
+ if (opt_len > 2)
+ GETCHAR(delay, pckt);
+
+ us->us_allowed |= (1 << type);
+
+ switch(type) {
+ case CB_CONF_NO:
+ dbglog("no callback allowed");
+ break;
+
+ case CB_CONF_USER:
+ dbglog("user callback allowed");
+ if (opt_len > 4) {
+ GETCHAR(addr_type, pckt);
+ memcpy(address, pckt, opt_len - 4);
+ address[opt_len - 4] = 0;
+ if (address[0])
+ dbglog("address: %s", address);
+ }
+ break;
+
+ case CB_CONF_ADMIN:
+ dbglog("user admin defined allowed");
+ break;
+
+ case CB_CONF_LIST:
+ break;
+ }
+ len -= opt_len;
+ }
+
+ cbcp_resp(us);
+}
+
+static void
+cbcp_resp(us)
+ cbcp_state *us;
+{
+ u_char cb_type;
+ u_char buf[256];
+ u_char *bufp = buf;
+ int len = 0;
+
+ cb_type = us->us_allowed & us->us_type;
+ dbglog("cbcp_resp cb_type=%d", cb_type);
+
+#if 0
+ if (!cb_type)
+ lcp_down(us->us_unit);
+#endif
+
+ if (cb_type & ( 1 << CB_CONF_USER ) ) {
+ dbglog("cbcp_resp CONF_USER");
+ PUTCHAR(CB_CONF_USER, bufp);
+ len = 3 + 1 + strlen(us->us_number) + 1;
+ PUTCHAR(len , bufp);
+ PUTCHAR(5, bufp); /* delay */
+ PUTCHAR(1, bufp);
+ BCOPY(us->us_number, bufp, strlen(us->us_number) + 1);
+ cbcp_send(us, CBCP_RESP, buf, len);
+ return;
+ }
+
+ if (cb_type & ( 1 << CB_CONF_ADMIN ) ) {
+ dbglog("cbcp_resp CONF_ADMIN");
+ PUTCHAR(CB_CONF_ADMIN, bufp);
+ len = 3;
+ PUTCHAR(len, bufp);
+ PUTCHAR(5, bufp); /* delay */
+ cbcp_send(us, CBCP_RESP, buf, len);
+ return;
+ }
+
+ if (cb_type & ( 1 << CB_CONF_NO ) ) {
+ dbglog("cbcp_resp CONF_NO");
+ PUTCHAR(CB_CONF_NO, bufp);
+ len = 3;
+ PUTCHAR(len , bufp);
+ PUTCHAR(0, bufp);
+ cbcp_send(us, CBCP_RESP, buf, len);
+ start_networks();
+ return;
+ }
+}
+
+static void
+cbcp_send(us, code, buf, len)
+ cbcp_state *us;
+ u_char code;
+ u_char *buf;
+ int len;
+{
+ u_char *outp;
+ int outlen;
+
+ outp = outpacket_buf;
+
+ outlen = 4 + len;
+
+ MAKEHEADER(outp, PPP_CBCP);
+
+ PUTCHAR(code, outp);
+ PUTCHAR(us->us_id, outp);
+ PUTSHORT(outlen, outp);
+
+ if (len)
+ BCOPY(buf, outp, len);
+
+ output(us->us_unit, outpacket_buf, outlen + PPP_HDRLEN);
+}
+
+static void
+cbcp_recvack(us, pckt, len)
+ cbcp_state *us;
+ char *pckt;
+ int len;
+{
+ u_char type, delay, addr_type;
+ int opt_len;
+ char address[256];
+
+ if (len) {
+ GETCHAR(type, pckt);
+ GETCHAR(opt_len, pckt);
+
+ if (opt_len > 2)
+ GETCHAR(delay, pckt);
+
+ if (opt_len > 4) {
+ GETCHAR(addr_type, pckt);
+ memcpy(address, pckt, opt_len - 4);
+ address[opt_len - 4] = 0;
+ if (address[0])
+ dbglog("peer will call: %s", address);
+ }
+ if (type == CB_CONF_NO)
+ return;
+ }
+
+ cbcp_up(us);
+}
+
+/* ok peer will do callback */
+static void
+cbcp_up(us)
+ cbcp_state *us;
+{
+ persist = 0;
+ lcp_close(0, "Call me back, please");
+ status = EXIT_CALLBACK;
+}
diff --git a/mdk-stage1/ppp/pppd/cbcp.h b/mdk-stage1/ppp/pppd/cbcp.h
new file mode 100644
index 000000000..c2ab3f689
--- /dev/null
+++ b/mdk-stage1/ppp/pppd/cbcp.h
@@ -0,0 +1,26 @@
+#ifndef CBCP_H
+#define CBCP_H
+
+typedef struct cbcp_state {
+ int us_unit; /* Interface unit number */
+ u_char us_id; /* Current id */
+ u_char us_allowed;
+ int us_type;
+ char *us_number; /* Telefone Number */
+} cbcp_state;
+
+extern cbcp_state cbcp[];
+
+extern struct protent cbcp_protent;
+
+#define CBCP_MINLEN 4
+
+#define CBCP_REQ 1
+#define CBCP_RESP 2
+#define CBCP_ACK 3
+
+#define CB_CONF_NO 1
+#define CB_CONF_USER 2
+#define CB_CONF_ADMIN 3
+#define CB_CONF_LIST 4
+#endif
diff --git a/mdk-stage1/ppp/pppd/ccp.c b/mdk-stage1/ppp/pppd/ccp.c
new file mode 100644
index 000000000..eaa6b4336
--- /dev/null
+++ b/mdk-stage1/ppp/pppd/ccp.c
@@ -0,0 +1,1257 @@
+/*
+ * ccp.c - PPP Compression Control Protocol.
+ *
+ * Copyright (c) 1994 The Australian National University.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation is hereby granted, provided that the above copyright
+ * notice appears in all copies. This software is provided without any
+ * warranty, express or implied. The Australian National University
+ * makes no representations about the suitability of this software for
+ * any purpose.
+ *
+ * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
+ * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
+ * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
+ * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
+ * OR MODIFICATIONS.
+ */
+
+#define RCSID "$Id: ccp.c 195720 2001-06-11 11:44:34Z gc $"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "pppd.h"
+#include "fsm.h"
+#include "ccp.h"
+#include <net/ppp-comp.h>
+
+static const char rcsid[] = RCSID;
+
+/*
+ * Unfortunately there is a bug in zlib which means that using a
+ * size of 8 (window size = 256) for Deflate compression will cause
+ * buffer overruns and kernel crashes in the deflate module.
+ * Until this is fixed we only accept sizes in the range 9 .. 15.
+ * Thanks to James Carlson for pointing this out.
+ */
+#define DEFLATE_MIN_WORKS 9
+
+/*
+ * Command-line options.
+ */
+static int setbsdcomp __P((char **));
+static int setdeflate __P((char **));
+static char bsd_value[8];
+static char deflate_value[8];
+
+static option_t ccp_option_list[] = {
+ { "noccp", o_bool, &ccp_protent.enabled_flag,
+ "Disable CCP negotiation" },
+ { "-ccp", o_bool, &ccp_protent.enabled_flag,
+ "Disable CCP negotiation", OPT_ALIAS },
+
+ { "bsdcomp", o_special, (void *)setbsdcomp,
+ "Request BSD-Compress packet compression",
+ OPT_PRIO | OPT_A2STRVAL | OPT_STATIC, bsd_value },
+ { "nobsdcomp", o_bool, &ccp_wantoptions[0].bsd_compress,
+ "don't allow BSD-Compress", OPT_PRIOSUB | OPT_A2CLR,
+ &ccp_allowoptions[0].bsd_compress },
+ { "-bsdcomp", o_bool, &ccp_wantoptions[0].bsd_compress,
+ "don't allow BSD-Compress", OPT_ALIAS | OPT_PRIOSUB | OPT_A2CLR,
+ &ccp_allowoptions[0].bsd_compress },
+
+ { "deflate", o_special, (void *)setdeflate,
+ "request Deflate compression",
+ OPT_PRIO | OPT_A2STRVAL | OPT_STATIC, deflate_value },
+ { "nodeflate", o_bool, &ccp_wantoptions[0].deflate,
+ "don't allow Deflate compression", OPT_PRIOSUB | OPT_A2CLR,
+ &ccp_allowoptions[0].deflate },
+ { "-deflate", o_bool, &ccp_wantoptions[0].deflate,
+ "don't allow Deflate compression", OPT_ALIAS | OPT_PRIOSUB | OPT_A2CLR,
+ &ccp_allowoptions[0].deflate },
+
+ { "nodeflatedraft", o_bool, &ccp_wantoptions[0].deflate_draft,
+ "don't use draft deflate #", OPT_A2COPY,
+ &ccp_allowoptions[0].deflate_draft },
+
+ { "predictor1", o_bool, &ccp_wantoptions[0].predictor_1,
+ "request Predictor-1", 1, &ccp_allowoptions[0].predictor_1, OPT_PRIO },
+ { "nopredictor1", o_bool, &ccp_wantoptions[0].predictor_1,
+ "don't allow Predictor-1", OPT_PRIOSUB | OPT_A2CLR,
+ &ccp_allowoptions[0].predictor_1 },
+ { "-predictor1", o_bool, &ccp_wantoptions[0].predictor_1,
+ "don't allow Predictor-1", OPT_ALIAS | OPT_PRIOSUB | OPT_A2CLR,
+ &ccp_allowoptions[0].predictor_1 },
+
+ { NULL }
+};
+
+/*
+ * Protocol entry points from main code.
+ */
+static void ccp_init __P((int unit));
+static void ccp_open __P((int unit));
+static void ccp_close __P((int unit, char *));
+static void ccp_lowerup __P((int unit));
+static void ccp_lowerdown __P((int));
+static void ccp_input __P((int unit, u_char *pkt, int len));
+static void ccp_protrej __P((int unit));
+static int ccp_printpkt __P((u_char *pkt, int len,
+ void (*printer) __P((void *, char *, ...)),
+ void *arg));
+static void ccp_datainput __P((int unit, u_char *pkt, int len));
+
+struct protent ccp_protent = {
+ PPP_CCP,
+ ccp_init,
+ ccp_input,
+ ccp_protrej,
+ ccp_lowerup,
+ ccp_lowerdown,
+ ccp_open,
+ ccp_close,
+ ccp_printpkt,
+ ccp_datainput,
+ 1,
+ "CCP",
+ "Compressed",
+ ccp_option_list,
+ NULL,
+ NULL,
+ NULL
+};
+
+fsm ccp_fsm[NUM_PPP];
+ccp_options ccp_wantoptions[NUM_PPP]; /* what to request the peer to use */
+ccp_options ccp_gotoptions[NUM_PPP]; /* what the peer agreed to do */
+ccp_options ccp_allowoptions[NUM_PPP]; /* what we'll agree to do */
+ccp_options ccp_hisoptions[NUM_PPP]; /* what we agreed to do */
+
+/*
+ * Callbacks for fsm code.
+ */
+static void ccp_resetci __P((fsm *));
+static int ccp_cilen __P((fsm *));
+static void ccp_addci __P((fsm *, u_char *, int *));
+static int ccp_ackci __P((fsm *, u_char *, int));
+static int ccp_nakci __P((fsm *, u_char *, int));
+static int ccp_rejci __P((fsm *, u_char *, int));
+static int ccp_reqci __P((fsm *, u_char *, int *, int));
+static void ccp_up __P((fsm *));
+static void ccp_down __P((fsm *));
+static int ccp_extcode __P((fsm *, int, int, u_char *, int));
+static void ccp_rack_timeout __P((void *));
+static char *method_name __P((ccp_options *, ccp_options *));
+
+static fsm_callbacks ccp_callbacks = {
+ ccp_resetci,
+ ccp_cilen,
+ ccp_addci,
+ ccp_ackci,
+ ccp_nakci,
+ ccp_rejci,
+ ccp_reqci,
+ ccp_up,
+ ccp_down,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ ccp_extcode,
+ "CCP"
+};
+
+/*
+ * Do we want / did we get any compression?
+ */
+#define ANY_COMPRESS(opt) ((opt).deflate || (opt).bsd_compress \
+ || (opt).predictor_1 || (opt).predictor_2)
+
+/*
+ * Local state (mainly for handling reset-reqs and reset-acks).
+ */
+static int ccp_localstate[NUM_PPP];
+#define RACK_PENDING 1 /* waiting for reset-ack */
+#define RREQ_REPEAT 2 /* send another reset-req if no reset-ack */
+
+#define RACKTIMEOUT 1 /* second */
+
+static int all_rejected[NUM_PPP]; /* we rejected all peer's options */
+
+/*
+ * Option parsing.
+ */
+static int
+setbsdcomp(argv)
+ char **argv;
+{
+ int rbits, abits;
+ char *str, *endp;
+
+ str = *argv;
+ abits = rbits = strtol(str, &endp, 0);
+ if (endp != str && *endp == ',') {
+ str = endp + 1;
+ abits = strtol(str, &endp, 0);
+ }
+ if (*endp != 0 || endp == str) {
+ option_error("invalid parameter '%s' for bsdcomp option", *argv);
+ return 0;
+ }
+ if ((rbits != 0 && (rbits < BSD_MIN_BITS || rbits > BSD_MAX_BITS))
+ || (abits != 0 && (abits < BSD_MIN_BITS || abits > BSD_MAX_BITS))) {
+ option_error("bsdcomp option values must be 0 or %d .. %d",
+ BSD_MIN_BITS, BSD_MAX_BITS);
+ return 0;
+ }
+ if (rbits > 0) {
+ ccp_wantoptions[0].bsd_compress = 1;
+ ccp_wantoptions[0].bsd_bits = rbits;
+ } else
+ ccp_wantoptions[0].bsd_compress = 0;
+ if (abits > 0) {
+ ccp_allowoptions[0].bsd_compress = 1;
+ ccp_allowoptions[0].bsd_bits = abits;
+ } else
+ ccp_allowoptions[0].bsd_compress = 0;
+ slprintf(bsd_value, sizeof(bsd_value),
+ rbits == abits? "%d": "%d,%d", rbits, abits);
+
+ return 1;
+}
+
+static int
+setdeflate(argv)
+ char **argv;
+{
+ int rbits, abits;
+ char *str, *endp;
+
+ str = *argv;
+ abits = rbits = strtol(str, &endp, 0);
+ if (endp != str && *endp == ',') {
+ str = endp + 1;
+ abits = strtol(str, &endp, 0);
+ }
+ if (*endp != 0 || endp == str) {
+ option_error("invalid parameter '%s' for deflate option", *argv);
+ return 0;
+ }
+ if ((rbits != 0 && (rbits < DEFLATE_MIN_SIZE || rbits > DEFLATE_MAX_SIZE))
+ || (abits != 0 && (abits < DEFLATE_MIN_SIZE
+ || abits > DEFLATE_MAX_SIZE))) {
+ option_error("deflate option values must be 0 or %d .. %d",
+ DEFLATE_MIN_SIZE, DEFLATE_MAX_SIZE);
+ return 0;
+ }
+ if (rbits == DEFLATE_MIN_SIZE || abits == DEFLATE_MIN_SIZE) {
+ if (rbits == DEFLATE_MIN_SIZE)
+ rbits = DEFLATE_MIN_WORKS;
+ if (abits == DEFLATE_MIN_SIZE)
+ abits = DEFLATE_MIN_WORKS;
+ warn("deflate option value of %d changed to %d to avoid zlib bug",
+ DEFLATE_MIN_SIZE, DEFLATE_MIN_WORKS);
+ }
+ if (rbits > 0) {
+ ccp_wantoptions[0].deflate = 1;
+ ccp_wantoptions[0].deflate_size = rbits;
+ } else
+ ccp_wantoptions[0].deflate = 0;
+ if (abits > 0) {
+ ccp_allowoptions[0].deflate = 1;
+ ccp_allowoptions[0].deflate_size = abits;
+ } else
+ ccp_allowoptions[0].deflate = 0;
+ slprintf(deflate_value, sizeof(deflate_value),
+ rbits == abits? "%d": "%d,%d", rbits, abits);
+
+ return 1;
+}
+
+/*
+ * ccp_init - initialize CCP.
+ */
+static void
+ccp_init(unit)
+ int unit;
+{
+ fsm *f = &ccp_fsm[unit];
+
+ f->unit = unit;
+ f->protocol = PPP_CCP;
+ f->callbacks = &ccp_callbacks;
+ fsm_init(f);
+
+ memset(&ccp_wantoptions[unit], 0, sizeof(ccp_options));
+ memset(&ccp_gotoptions[unit], 0, sizeof(ccp_options));
+ memset(&ccp_allowoptions[unit], 0, sizeof(ccp_options));
+ memset(&ccp_hisoptions[unit], 0, sizeof(ccp_options));
+
+ ccp_wantoptions[0].deflate = 1;
+ ccp_wantoptions[0].deflate_size = DEFLATE_MAX_SIZE;
+ ccp_wantoptions[0].deflate_correct = 1;
+ ccp_wantoptions[0].deflate_draft = 1;
+ ccp_allowoptions[0].deflate = 1;
+ ccp_allowoptions[0].deflate_size = DEFLATE_MAX_SIZE;
+ ccp_allowoptions[0].deflate_correct = 1;
+ ccp_allowoptions[0].deflate_draft = 1;
+
+ ccp_wantoptions[0].bsd_compress = 1;
+ ccp_wantoptions[0].bsd_bits = BSD_MAX_BITS;
+ ccp_allowoptions[0].bsd_compress = 1;
+ ccp_allowoptions[0].bsd_bits = BSD_MAX_BITS;
+
+ ccp_allowoptions[0].predictor_1 = 1;
+}
+
+/*
+ * ccp_open - CCP is allowed to come up.
+ */
+static void
+ccp_open(unit)
+ int unit;
+{
+ fsm *f = &ccp_fsm[unit];
+
+ if (f->state != OPENED)
+ ccp_flags_set(unit, 1, 0);
+
+ /*
+ * Find out which compressors the kernel supports before
+ * deciding whether to open in silent mode.
+ */
+ ccp_resetci(f);
+ if (!ANY_COMPRESS(ccp_gotoptions[unit]))
+ f->flags |= OPT_SILENT;
+
+ fsm_open(f);
+}
+
+/*
+ * ccp_close - Terminate CCP.
+ */
+static void
+ccp_close(unit, reason)
+ int unit;
+ char *reason;
+{
+ ccp_flags_set(unit, 0, 0);
+ fsm_close(&ccp_fsm[unit], reason);
+}
+
+/*
+ * ccp_lowerup - we may now transmit CCP packets.
+ */
+static void
+ccp_lowerup(unit)
+ int unit;
+{
+ fsm_lowerup(&ccp_fsm[unit]);
+}
+
+/*
+ * ccp_lowerdown - we may not transmit CCP packets.
+ */
+static void
+ccp_lowerdown(unit)
+ int unit;
+{
+ fsm_lowerdown(&ccp_fsm[unit]);
+}
+
+/*
+ * ccp_input - process a received CCP packet.
+ */
+static void
+ccp_input(unit, p, len)
+ int unit;
+ u_char *p;
+ int len;
+{
+ fsm *f = &ccp_fsm[unit];
+ int oldstate;
+
+ /*
+ * Check for a terminate-request so we can print a message.
+ */
+ oldstate = f->state;
+ fsm_input(f, p, len);
+ if (oldstate == OPENED && p[0] == TERMREQ && f->state != OPENED)
+ notice("Compression disabled by peer.");
+
+ /*
+ * If we get a terminate-ack and we're not asking for compression,
+ * close CCP.
+ */
+ if (oldstate == REQSENT && p[0] == TERMACK
+ && !ANY_COMPRESS(ccp_gotoptions[unit]))
+ ccp_close(unit, "No compression negotiated");
+}
+
+/*
+ * Handle a CCP-specific code.
+ */
+static int
+ccp_extcode(f, code, id, p, len)
+ fsm *f;
+ int code, id;
+ u_char *p;
+ int len;
+{
+ switch (code) {
+ case CCP_RESETREQ:
+ if (f->state != OPENED)
+ break;
+ /* send a reset-ack, which the transmitter will see and
+ reset its compression state. */
+ fsm_sdata(f, CCP_RESETACK, id, NULL, 0);
+ break;
+
+ case CCP_RESETACK:
+ if (ccp_localstate[f->unit] & RACK_PENDING && id == f->reqid) {
+ ccp_localstate[f->unit] &= ~(RACK_PENDING | RREQ_REPEAT);
+ UNTIMEOUT(ccp_rack_timeout, f);
+ }
+ break;
+
+ default:
+ return 0;
+ }
+
+ return 1;
+}
+
+/*
+ * ccp_protrej - peer doesn't talk CCP.
+ */
+static void
+ccp_protrej(unit)
+ int unit;
+{
+ ccp_flags_set(unit, 0, 0);
+ fsm_lowerdown(&ccp_fsm[unit]);
+}
+
+/*
+ * ccp_resetci - initialize at start of negotiation.
+ */
+static void
+ccp_resetci(f)
+ fsm *f;
+{
+ ccp_options *go = &ccp_gotoptions[f->unit];
+ u_char opt_buf[16];
+
+ *go = ccp_wantoptions[f->unit];
+ all_rejected[f->unit] = 0;
+
+ /*
+ * Check whether the kernel knows about the various
+ * compression methods we might request.
+ */
+ if (go->bsd_compress) {
+ opt_buf[0] = CI_BSD_COMPRESS;
+ opt_buf[1] = CILEN_BSD_COMPRESS;
+ opt_buf[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, BSD_MIN_BITS);
+ if (ccp_test(f->unit, opt_buf, CILEN_BSD_COMPRESS, 0) <= 0)
+ go->bsd_compress = 0;
+ }
+ if (go->deflate) {
+ if (go->deflate_correct) {
+ opt_buf[0] = CI_DEFLATE;
+ opt_buf[1] = CILEN_DEFLATE;
+ opt_buf[2] = DEFLATE_MAKE_OPT(DEFLATE_MIN_WORKS);
+ opt_buf[3] = DEFLATE_CHK_SEQUENCE;
+ if (ccp_test(f->unit, opt_buf, CILEN_DEFLATE, 0) <= 0)
+ go->deflate_correct = 0;
+ }
+ if (go->deflate_draft) {
+ opt_buf[0] = CI_DEFLATE_DRAFT;
+ opt_buf[1] = CILEN_DEFLATE;
+ opt_buf[2] = DEFLATE_MAKE_OPT(DEFLATE_MIN_WORKS);
+ opt_buf[3] = DEFLATE_CHK_SEQUENCE;
+ if (ccp_test(f->unit, opt_buf, CILEN_DEFLATE, 0) <= 0)
+ go->deflate_draft = 0;
+ }
+ if (!go->deflate_correct && !go->deflate_draft)
+ go->deflate = 0;
+ }
+ if (go->predictor_1) {
+ opt_buf[0] = CI_PREDICTOR_1;
+ opt_buf[1] = CILEN_PREDICTOR_1;
+ if (ccp_test(f->unit, opt_buf, CILEN_PREDICTOR_1, 0) <= 0)
+ go->predictor_1 = 0;
+ }
+ if (go->predictor_2) {
+ opt_buf[0] = CI_PREDICTOR_2;
+ opt_buf[1] = CILEN_PREDICTOR_2;
+ if (ccp_test(f->unit, opt_buf, CILEN_PREDICTOR_2, 0) <= 0)
+ go->predictor_2 = 0;
+ }
+}
+
+/*
+ * ccp_cilen - Return total length of our configuration info.
+ */
+static int
+ccp_cilen(f)
+ fsm *f;
+{
+ ccp_options *go = &ccp_gotoptions[f->unit];
+
+ return (go->bsd_compress? CILEN_BSD_COMPRESS: 0)
+ + (go->deflate? CILEN_DEFLATE: 0)
+ + (go->predictor_1? CILEN_PREDICTOR_1: 0)
+ + (go->predictor_2? CILEN_PREDICTOR_2: 0);
+}
+
+/*
+ * ccp_addci - put our requests in a packet.
+ */
+static void
+ccp_addci(f, p, lenp)
+ fsm *f;
+ u_char *p;
+ int *lenp;
+{
+ int res;
+ ccp_options *go = &ccp_gotoptions[f->unit];
+ u_char *p0 = p;
+
+ /*
+ * Add the compression types that we can receive, in decreasing
+ * preference order. Get the kernel to allocate the first one
+ * in case it gets Acked.
+ */
+ if (go->deflate) {
+ p[0] = go->deflate_correct? CI_DEFLATE: CI_DEFLATE_DRAFT;
+ p[1] = CILEN_DEFLATE;
+ p[2] = DEFLATE_MAKE_OPT(go->deflate_size);
+ p[3] = DEFLATE_CHK_SEQUENCE;
+ for (;;) {
+ res = ccp_test(f->unit, p, CILEN_DEFLATE, 0);
+ if (res > 0) {
+ p += CILEN_DEFLATE;
+ break;
+ }
+ if (res < 0 || go->deflate_size <= DEFLATE_MIN_WORKS) {
+ go->deflate = 0;
+ break;
+ }
+ --go->deflate_size;
+ p[2] = DEFLATE_MAKE_OPT(go->deflate_size);
+ }
+ if (p != p0 && go->deflate_correct && go->deflate_draft) {
+ p[0] = CI_DEFLATE_DRAFT;
+ p[1] = CILEN_DEFLATE;
+ p[2] = p[2 - CILEN_DEFLATE];
+ p[3] = DEFLATE_CHK_SEQUENCE;
+ p += CILEN_DEFLATE;
+ }
+ }
+ if (go->bsd_compress) {
+ p[0] = CI_BSD_COMPRESS;
+ p[1] = CILEN_BSD_COMPRESS;
+ p[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, go->bsd_bits);
+ if (p != p0) {
+ p += CILEN_BSD_COMPRESS; /* not the first option */
+ } else {
+ for (;;) {
+ res = ccp_test(f->unit, p, CILEN_BSD_COMPRESS, 0);
+ if (res > 0) {
+ p += CILEN_BSD_COMPRESS;
+ break;
+ }
+ if (res < 0 || go->bsd_bits <= BSD_MIN_BITS) {
+ go->bsd_compress = 0;
+ break;
+ }
+ --go->bsd_bits;
+ p[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, go->bsd_bits);
+ }
+ }
+ }
+ /* XXX Should Predictor 2 be preferable to Predictor 1? */
+ if (go->predictor_1) {
+ p[0] = CI_PREDICTOR_1;
+ p[1] = CILEN_PREDICTOR_1;
+ if (p == p0 && ccp_test(f->unit, p, CILEN_PREDICTOR_1, 0) <= 0) {
+ go->predictor_1 = 0;
+ } else {
+ p += CILEN_PREDICTOR_1;
+ }
+ }
+ if (go->predictor_2) {
+ p[0] = CI_PREDICTOR_2;
+ p[1] = CILEN_PREDICTOR_2;
+ if (p == p0 && ccp_test(f->unit, p, CILEN_PREDICTOR_2, 0) <= 0) {
+ go->predictor_2 = 0;
+ } else {
+ p += CILEN_PREDICTOR_2;
+ }
+ }
+
+ go->method = (p > p0)? p0[0]: -1;
+
+ *lenp = p - p0;
+}
+
+/*
+ * ccp_ackci - process a received configure-ack, and return
+ * 1 iff the packet was OK.
+ */
+static int
+ccp_ackci(f, p, len)
+ fsm *f;
+ u_char *p;
+ int len;
+{
+ ccp_options *go = &ccp_gotoptions[f->unit];
+ u_char *p0 = p;
+
+ if (go->deflate) {
+ if (len < CILEN_DEFLATE
+ || p[0] != (go->deflate_correct? CI_DEFLATE: CI_DEFLATE_DRAFT)
+ || p[1] != CILEN_DEFLATE
+ || p[2] != DEFLATE_MAKE_OPT(go->deflate_size)
+ || p[3] != DEFLATE_CHK_SEQUENCE)
+ return 0;
+ p += CILEN_DEFLATE;
+ len -= CILEN_DEFLATE;
+ /* XXX Cope with first/fast ack */
+ if (len == 0)
+ return 1;
+ if (go->deflate_correct && go->deflate_draft) {
+ if (len < CILEN_DEFLATE
+ || p[0] != CI_DEFLATE_DRAFT
+ || p[1] != CILEN_DEFLATE
+ || p[2] != DEFLATE_MAKE_OPT(go->deflate_size)
+ || p[3] != DEFLATE_CHK_SEQUENCE)
+ return 0;
+ p += CILEN_DEFLATE;
+ len -= CILEN_DEFLATE;
+ }
+ }
+ if (go->bsd_compress) {
+ if (len < CILEN_BSD_COMPRESS
+ || p[0] != CI_BSD_COMPRESS || p[1] != CILEN_BSD_COMPRESS
+ || p[2] != BSD_MAKE_OPT(BSD_CURRENT_VERSION, go->bsd_bits))
+ return 0;
+ p += CILEN_BSD_COMPRESS;
+ len -= CILEN_BSD_COMPRESS;
+ /* XXX Cope with first/fast ack */
+ if (p == p0 && len == 0)
+ return 1;
+ }
+ if (go->predictor_1) {
+ if (len < CILEN_PREDICTOR_1
+ || p[0] != CI_PREDICTOR_1 || p[1] != CILEN_PREDICTOR_1)
+ return 0;
+ p += CILEN_PREDICTOR_1;
+ len -= CILEN_PREDICTOR_1;
+ /* XXX Cope with first/fast ack */
+ if (p == p0 && len == 0)
+ return 1;
+ }
+ if (go->predictor_2) {
+ if (len < CILEN_PREDICTOR_2
+ || p[0] != CI_PREDICTOR_2 || p[1] != CILEN_PREDICTOR_2)
+ return 0;
+ p += CILEN_PREDICTOR_2;
+ len -= CILEN_PREDICTOR_2;
+ /* XXX Cope with first/fast ack */
+ if (p == p0 && len == 0)
+ return 1;
+ }
+
+ if (len != 0)
+ return 0;
+ return 1;
+}
+
+/*
+ * ccp_nakci - process received configure-nak.
+ * Returns 1 iff the nak was OK.
+ */
+static int
+ccp_nakci(f, p, len)
+ fsm *f;
+ u_char *p;
+ int len;
+{
+ ccp_options *go = &ccp_gotoptions[f->unit];
+ ccp_options no; /* options we've seen already */
+ ccp_options try; /* options to ask for next time */
+
+ memset(&no, 0, sizeof(no));
+ try = *go;
+
+ if (go->deflate && len >= CILEN_DEFLATE
+ && p[0] == (go->deflate_correct? CI_DEFLATE: CI_DEFLATE_DRAFT)
+ && p[1] == CILEN_DEFLATE) {
+ no.deflate = 1;
+ /*
+ * Peer wants us to use a different code size or something.
+ * Stop asking for Deflate if we don't understand his suggestion.
+ */
+ if (DEFLATE_METHOD(p[2]) != DEFLATE_METHOD_VAL
+ || DEFLATE_SIZE(p[2]) < DEFLATE_MIN_WORKS
+ || p[3] != DEFLATE_CHK_SEQUENCE)
+ try.deflate = 0;
+ else if (DEFLATE_SIZE(p[2]) < go->deflate_size)
+ try.deflate_size = DEFLATE_SIZE(p[2]);
+ p += CILEN_DEFLATE;
+ len -= CILEN_DEFLATE;
+ if (go->deflate_correct && go->deflate_draft
+ && len >= CILEN_DEFLATE && p[0] == CI_DEFLATE_DRAFT
+ && p[1] == CILEN_DEFLATE) {
+ p += CILEN_DEFLATE;
+ len -= CILEN_DEFLATE;
+ }
+ }
+
+ if (go->bsd_compress && len >= CILEN_BSD_COMPRESS
+ && p[0] == CI_BSD_COMPRESS && p[1] == CILEN_BSD_COMPRESS) {
+ no.bsd_compress = 1;
+ /*
+ * Peer wants us to use a different number of bits
+ * or a different version.
+ */
+ if (BSD_VERSION(p[2]) != BSD_CURRENT_VERSION)
+ try.bsd_compress = 0;
+ else if (BSD_NBITS(p[2]) < go->bsd_bits)
+ try.bsd_bits = BSD_NBITS(p[2]);
+ p += CILEN_BSD_COMPRESS;
+ len -= CILEN_BSD_COMPRESS;
+ }
+
+ /*
+ * Predictor-1 and 2 have no options, so they can't be Naked.
+ *
+ * There may be remaining options but we ignore them.
+ */
+
+ if (f->state != OPENED)
+ *go = try;
+ return 1;
+}
+
+/*
+ * ccp_rejci - reject some of our suggested compression methods.
+ */
+static int
+ccp_rejci(f, p, len)
+ fsm *f;
+ u_char *p;
+ int len;
+{
+ ccp_options *go = &ccp_gotoptions[f->unit];
+ ccp_options try; /* options to request next time */
+
+ try = *go;
+
+ /*
+ * Cope with empty configure-rejects by ceasing to send
+ * configure-requests.
+ */
+ if (len == 0 && all_rejected[f->unit])
+ return -1;
+
+ if (go->deflate && len >= CILEN_DEFLATE
+ && p[0] == (go->deflate_correct? CI_DEFLATE: CI_DEFLATE_DRAFT)
+ && p[1] == CILEN_DEFLATE) {
+ if (p[2] != DEFLATE_MAKE_OPT(go->deflate_size)
+ || p[3] != DEFLATE_CHK_SEQUENCE)
+ return 0; /* Rej is bad */
+ if (go->deflate_correct)
+ try.deflate_correct = 0;
+ else
+ try.deflate_draft = 0;
+ p += CILEN_DEFLATE;
+ len -= CILEN_DEFLATE;
+ if (go->deflate_correct && go->deflate_draft
+ && len >= CILEN_DEFLATE && p[0] == CI_DEFLATE_DRAFT
+ && p[1] == CILEN_DEFLATE) {
+ if (p[2] != DEFLATE_MAKE_OPT(go->deflate_size)
+ || p[3] != DEFLATE_CHK_SEQUENCE)
+ return 0; /* Rej is bad */
+ try.deflate_draft = 0;
+ p += CILEN_DEFLATE;
+ len -= CILEN_DEFLATE;
+ }
+ if (!try.deflate_correct && !try.deflate_draft)
+ try.deflate = 0;
+ }
+ if (go->bsd_compress && len >= CILEN_BSD_COMPRESS
+ && p[0] == CI_BSD_COMPRESS && p[1] == CILEN_BSD_COMPRESS) {
+ if (p[2] != BSD_MAKE_OPT(BSD_CURRENT_VERSION, go->bsd_bits))
+ return 0;
+ try.bsd_compress = 0;
+ p += CILEN_BSD_COMPRESS;
+ len -= CILEN_BSD_COMPRESS;
+ }
+ if (go->predictor_1 && len >= CILEN_PREDICTOR_1
+ && p[0] == CI_PREDICTOR_1 && p[1] == CILEN_PREDICTOR_1) {
+ try.predictor_1 = 0;
+ p += CILEN_PREDICTOR_1;
+ len -= CILEN_PREDICTOR_1;
+ }
+ if (go->predictor_2 && len >= CILEN_PREDICTOR_2
+ && p[0] == CI_PREDICTOR_2 && p[1] == CILEN_PREDICTOR_2) {
+ try.predictor_2 = 0;
+ p += CILEN_PREDICTOR_2;
+ len -= CILEN_PREDICTOR_2;
+ }
+
+ if (len != 0)
+ return 0;
+
+ if (f->state != OPENED)
+ *go = try;
+
+ return 1;
+}
+
+/*
+ * ccp_reqci - processed a received configure-request.
+ * Returns CONFACK, CONFNAK or CONFREJ and the packet modified
+ * appropriately.
+ */
+static int
+ccp_reqci(f, p, lenp, dont_nak)
+ fsm *f;
+ u_char *p;
+ int *lenp;
+ int dont_nak;
+{
+ int ret, newret, res;
+ u_char *p0, *retp;
+ int len, clen, type, nb;
+ ccp_options *ho = &ccp_hisoptions[f->unit];
+ ccp_options *ao = &ccp_allowoptions[f->unit];
+
+ ret = CONFACK;
+ retp = p0 = p;
+ len = *lenp;
+
+ memset(ho, 0, sizeof(ccp_options));
+ ho->method = (len > 0)? p[0]: -1;
+
+ while (len > 0) {
+ newret = CONFACK;
+ if (len < 2 || p[1] < 2 || p[1] > len) {
+ /* length is bad */
+ clen = len;
+ newret = CONFREJ;
+
+ } else {
+ type = p[0];
+ clen = p[1];
+
+ switch (type) {
+ case CI_DEFLATE:
+ case CI_DEFLATE_DRAFT:
+ if (!ao->deflate || clen != CILEN_DEFLATE
+ || (!ao->deflate_correct && type == CI_DEFLATE)
+ || (!ao->deflate_draft && type == CI_DEFLATE_DRAFT)) {
+ newret = CONFREJ;
+ break;
+ }
+
+ ho->deflate = 1;
+ ho->deflate_size = nb = DEFLATE_SIZE(p[2]);
+ if (DEFLATE_METHOD(p[2]) != DEFLATE_METHOD_VAL
+ || p[3] != DEFLATE_CHK_SEQUENCE
+ || nb > ao->deflate_size || nb < DEFLATE_MIN_WORKS) {
+ newret = CONFNAK;
+ if (!dont_nak) {
+ p[2] = DEFLATE_MAKE_OPT(ao->deflate_size);
+ p[3] = DEFLATE_CHK_SEQUENCE;
+ /* fall through to test this #bits below */
+ } else
+ break;
+ }
+
+ /*
+ * Check whether we can do Deflate with the window
+ * size they want. If the window is too big, reduce
+ * it until the kernel can cope and nak with that.
+ * We only check this for the first option.
+ */
+ if (p == p0) {
+ for (;;) {
+ res = ccp_test(f->unit, p, CILEN_DEFLATE, 1);
+ if (res > 0)
+ break; /* it's OK now */
+ if (res < 0 || nb == DEFLATE_MIN_WORKS || dont_nak) {
+ newret = CONFREJ;
+ p[2] = DEFLATE_MAKE_OPT(ho->deflate_size);
+ break;
+ }
+ newret = CONFNAK;
+ --nb;
+ p[2] = DEFLATE_MAKE_OPT(nb);
+ }
+ }
+ break;
+
+ case CI_BSD_COMPRESS:
+ if (!ao->bsd_compress || clen != CILEN_BSD_COMPRESS) {
+ newret = CONFREJ;
+ break;
+ }
+
+ ho->bsd_compress = 1;
+ ho->bsd_bits = nb = BSD_NBITS(p[2]);
+ if (BSD_VERSION(p[2]) != BSD_CURRENT_VERSION
+ || nb > ao->bsd_bits || nb < BSD_MIN_BITS) {
+ newret = CONFNAK;
+ if (!dont_nak) {
+ p[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, ao->bsd_bits);
+ /* fall through to test this #bits below */
+ } else
+ break;
+ }
+
+ /*
+ * Check whether we can do BSD-Compress with the code
+ * size they want. If the code size is too big, reduce
+ * it until the kernel can cope and nak with that.
+ * We only check this for the first option.
+ */
+ if (p == p0) {
+ for (;;) {
+ res = ccp_test(f->unit, p, CILEN_BSD_COMPRESS, 1);
+ if (res > 0)
+ break;
+ if (res < 0 || nb == BSD_MIN_BITS || dont_nak) {
+ newret = CONFREJ;
+ p[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION,
+ ho->bsd_bits);
+ break;
+ }
+ newret = CONFNAK;
+ --nb;
+ p[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, nb);
+ }
+ }
+ break;
+
+ case CI_PREDICTOR_1:
+ if (!ao->predictor_1 || clen != CILEN_PREDICTOR_1) {
+ newret = CONFREJ;
+ break;
+ }
+
+ ho->predictor_1 = 1;
+ if (p == p0
+ && ccp_test(f->unit, p, CILEN_PREDICTOR_1, 1) <= 0) {
+ newret = CONFREJ;
+ }
+ break;
+
+ case CI_PREDICTOR_2:
+ if (!ao->predictor_2 || clen != CILEN_PREDICTOR_2) {
+ newret = CONFREJ;
+ break;
+ }
+
+ ho->predictor_2 = 1;
+ if (p == p0
+ && ccp_test(f->unit, p, CILEN_PREDICTOR_2, 1) <= 0) {
+ newret = CONFREJ;
+ }
+ break;
+
+ default:
+ newret = CONFREJ;
+ }
+ }
+
+ if (newret == CONFNAK && dont_nak)
+ newret = CONFREJ;
+ if (!(newret == CONFACK || (newret == CONFNAK && ret == CONFREJ))) {
+ /* we're returning this option */
+ if (newret == CONFREJ && ret == CONFNAK)
+ retp = p0;
+ ret = newret;
+ if (p != retp)
+ BCOPY(p, retp, clen);
+ retp += clen;
+ }
+
+ p += clen;
+ len -= clen;
+ }
+
+ if (ret != CONFACK) {
+ if (ret == CONFREJ && *lenp == retp - p0)
+ all_rejected[f->unit] = 1;
+ else
+ *lenp = retp - p0;
+ }
+ return ret;
+}
+
+/*
+ * Make a string name for a compression method (or 2).
+ */
+static char *
+method_name(opt, opt2)
+ ccp_options *opt, *opt2;
+{
+ static char result[64];
+
+ if (!ANY_COMPRESS(*opt))
+ return "(none)";
+ switch (opt->method) {
+ case CI_DEFLATE:
+ case CI_DEFLATE_DRAFT:
+ if (opt2 != NULL && opt2->deflate_size != opt->deflate_size)
+ slprintf(result, sizeof(result), "Deflate%s (%d/%d)",
+ (opt->method == CI_DEFLATE_DRAFT? "(old#)": ""),
+ opt->deflate_size, opt2->deflate_size);
+ else
+ slprintf(result, sizeof(result), "Deflate%s (%d)",
+ (opt->method == CI_DEFLATE_DRAFT? "(old#)": ""),
+ opt->deflate_size);
+ break;
+ case CI_BSD_COMPRESS:
+ if (opt2 != NULL && opt2->bsd_bits != opt->bsd_bits)
+ slprintf(result, sizeof(result), "BSD-Compress (%d/%d)",
+ opt->bsd_bits, opt2->bsd_bits);
+ else
+ slprintf(result, sizeof(result), "BSD-Compress (%d)",
+ opt->bsd_bits);
+ break;
+ case CI_PREDICTOR_1:
+ return "Predictor 1";
+ case CI_PREDICTOR_2:
+ return "Predictor 2";
+ default:
+ slprintf(result, sizeof(result), "Method %d", opt->method);
+ }
+ return result;
+}
+
+/*
+ * CCP has come up - inform the kernel driver and log a message.
+ */
+static void
+ccp_up(f)
+ fsm *f;
+{
+ ccp_options *go = &ccp_gotoptions[f->unit];
+ ccp_options *ho = &ccp_hisoptions[f->unit];
+ char method1[64];
+
+ ccp_flags_set(f->unit, 1, 1);
+ if (ANY_COMPRESS(*go)) {
+ if (ANY_COMPRESS(*ho)) {
+ if (go->method == ho->method) {
+ notice("%s compression enabled", method_name(go, ho));
+ } else {
+ strlcpy(method1, method_name(go, NULL), sizeof(method1));
+ notice("%s / %s compression enabled",
+ method1, method_name(ho, NULL));
+ }
+ } else
+ notice("%s receive compression enabled", method_name(go, NULL));
+ } else if (ANY_COMPRESS(*ho))
+ notice("%s transmit compression enabled", method_name(ho, NULL));
+}
+
+/*
+ * CCP has gone down - inform the kernel driver.
+ */
+static void
+ccp_down(f)
+ fsm *f;
+{
+ if (ccp_localstate[f->unit] & RACK_PENDING)
+ UNTIMEOUT(ccp_rack_timeout, f);
+ ccp_localstate[f->unit] = 0;
+ ccp_flags_set(f->unit, 1, 0);
+}
+
+/*
+ * Print the contents of a CCP packet.
+ */
+static char *ccp_codenames[] = {
+ "ConfReq", "ConfAck", "ConfNak", "ConfRej",
+ "TermReq", "TermAck", "CodeRej",
+ NULL, NULL, NULL, NULL, NULL, NULL,
+ "ResetReq", "ResetAck",
+};
+
+static int
+ccp_printpkt(p, plen, printer, arg)
+ u_char *p;
+ int plen;
+ void (*printer) __P((void *, char *, ...));
+ void *arg;
+{
+ u_char *p0, *optend;
+ int code, id, len;
+ int optlen;
+
+ p0 = p;
+ if (plen < HEADERLEN)
+ return 0;
+ code = p[0];
+ id = p[1];
+ len = (p[2] << 8) + p[3];
+ if (len < HEADERLEN || len > plen)
+ return 0;
+
+ if (code >= 1 && code <= sizeof(ccp_codenames) / sizeof(char *)
+ && ccp_codenames[code-1] != NULL)
+ printer(arg, " %s", ccp_codenames[code-1]);
+ else
+ printer(arg, " code=0x%x", code);
+ printer(arg, " id=0x%x", id);
+ len -= HEADERLEN;
+ p += HEADERLEN;
+
+ switch (code) {
+ case CONFREQ:
+ case CONFACK:
+ case CONFNAK:
+ case CONFREJ:
+ /* print list of possible compression methods */
+ while (len >= 2) {
+ code = p[0];
+ optlen = p[1];
+ if (optlen < 2 || optlen > len)
+ break;
+ printer(arg, " <");
+ len -= optlen;
+ optend = p + optlen;
+ switch (code) {
+ case CI_DEFLATE:
+ case CI_DEFLATE_DRAFT:
+ if (optlen >= CILEN_DEFLATE) {
+ printer(arg, "deflate%s %d",
+ (code == CI_DEFLATE_DRAFT? "(old#)": ""),
+ DEFLATE_SIZE(p[2]));
+ if (DEFLATE_METHOD(p[2]) != DEFLATE_METHOD_VAL)
+ printer(arg, " method %d", DEFLATE_METHOD(p[2]));
+ if (p[3] != DEFLATE_CHK_SEQUENCE)
+ printer(arg, " check %d", p[3]);
+ p += CILEN_DEFLATE;
+ }
+ break;
+ case CI_BSD_COMPRESS:
+ if (optlen >= CILEN_BSD_COMPRESS) {
+ printer(arg, "bsd v%d %d", BSD_VERSION(p[2]),
+ BSD_NBITS(p[2]));
+ p += CILEN_BSD_COMPRESS;
+ }
+ break;
+ case CI_PREDICTOR_1:
+ if (optlen >= CILEN_PREDICTOR_1) {
+ printer(arg, "predictor 1");
+ p += CILEN_PREDICTOR_1;
+ }
+ break;
+ case CI_PREDICTOR_2:
+ if (optlen >= CILEN_PREDICTOR_2) {
+ printer(arg, "predictor 2");
+ p += CILEN_PREDICTOR_2;
+ }
+ break;
+ }
+ while (p < optend)
+ printer(arg, " %.2x", *p++);
+ printer(arg, ">");
+ }
+ break;
+
+ case TERMACK:
+ case TERMREQ:
+ if (len > 0 && *p >= ' ' && *p < 0x7f) {
+ print_string((char *)p, len, printer, arg);
+ p += len;
+ len = 0;
+ }
+ break;
+ }
+
+ /* dump out the rest of the packet in hex */
+ while (--len >= 0)
+ printer(arg, " %.2x", *p++);
+
+ return p - p0;
+}
+
+/*
+ * We have received a packet that the decompressor failed to
+ * decompress. Here we would expect to issue a reset-request, but
+ * Motorola has a patent on resetting the compressor as a result of
+ * detecting an error in the decompressed data after decompression.
+ * (See US patent 5,130,993; international patent publication number
+ * WO 91/10289; Australian patent 73296/91.)
+ *
+ * So we ask the kernel whether the error was detected after
+ * decompression; if it was, we take CCP down, thus disabling
+ * compression :-(, otherwise we issue the reset-request.
+ */
+static void
+ccp_datainput(unit, pkt, len)
+ int unit;
+ u_char *pkt;
+ int len;
+{
+ fsm *f;
+
+ f = &ccp_fsm[unit];
+ if (f->state == OPENED) {
+ if (ccp_fatal_error(unit)) {
+ /*
+ * Disable compression by taking CCP down.
+ */
+ error("Lost compression sync: disabling compression");
+ ccp_close(unit, "Lost compression sync");
+ } else {
+ /*
+ * Send a reset-request to reset the peer's compressor.
+ * We don't do that if we are still waiting for an
+ * acknowledgement to a previous reset-request.
+ */
+ if (!(ccp_localstate[f->unit] & RACK_PENDING)) {
+ fsm_sdata(f, CCP_RESETREQ, f->reqid = ++f->id, NULL, 0);
+ TIMEOUT(ccp_rack_timeout, f, RACKTIMEOUT);
+ ccp_localstate[f->unit] |= RACK_PENDING;
+ } else
+ ccp_localstate[f->unit] |= RREQ_REPEAT;
+ }
+ }
+}
+
+/*
+ * Timeout waiting for reset-ack.
+ */
+static void
+ccp_rack_timeout(arg)
+ void *arg;
+{
+ fsm *f = arg;
+
+ if (f->state == OPENED && ccp_localstate[f->unit] & RREQ_REPEAT) {
+ fsm_sdata(f, CCP_RESETREQ, f->reqid, NULL, 0);
+ TIMEOUT(ccp_rack_timeout, f, RACKTIMEOUT);
+ ccp_localstate[f->unit] &= ~RREQ_REPEAT;
+ } else
+ ccp_localstate[f->unit] &= ~RACK_PENDING;
+}
+
diff --git a/mdk-stage1/ppp/pppd/ccp.h b/mdk-stage1/ppp/pppd/ccp.h
new file mode 100644
index 000000000..406fe4d17
--- /dev/null
+++ b/mdk-stage1/ppp/pppd/ccp.h
@@ -0,0 +1,48 @@
+/*
+ * ccp.h - Definitions for PPP Compression Control Protocol.
+ *
+ * Copyright (c) 1994 The Australian National University.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation is hereby granted, provided that the above copyright
+ * notice appears in all copies. This software is provided without any
+ * warranty, express or implied. The Australian National University
+ * makes no representations about the suitability of this software for
+ * any purpose.
+ *
+ * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
+ * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
+ * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
+ * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
+ * OR MODIFICATIONS.
+ *
+ * $Id: ccp.h 195720 2001-06-11 11:44:34Z gc $
+ */
+
+typedef struct ccp_options {
+ bool bsd_compress; /* do BSD Compress? */
+ bool deflate; /* do Deflate? */
+ bool predictor_1; /* do Predictor-1? */
+ bool predictor_2; /* do Predictor-2? */
+ bool deflate_correct; /* use correct code for deflate? */
+ bool deflate_draft; /* use draft RFC code for deflate? */
+ u_short bsd_bits; /* # bits/code for BSD Compress */
+ u_short deflate_size; /* lg(window size) for Deflate */
+ short method; /* code for chosen compression method */
+} ccp_options;
+
+extern fsm ccp_fsm[];
+extern ccp_options ccp_wantoptions[];
+extern ccp_options ccp_gotoptions[];
+extern ccp_options ccp_allowoptions[];
+extern ccp_options ccp_hisoptions[];
+
+extern struct protent ccp_protent;
diff --git a/mdk-stage1/ppp/pppd/chap.c b/mdk-stage1/ppp/pppd/chap.c
new file mode 100644
index 000000000..76560dcf0
--- /dev/null
+++ b/mdk-stage1/ppp/pppd/chap.c
@@ -0,0 +1,860 @@
+/*
+ * chap.c - Challenge Handshake Authentication Protocol.
+ *
+ * Copyright (c) 1993 The Australian National University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the Australian National University. The name of the University
+ * may not be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Copyright (c) 1991 Gregory M. Christy.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Gregory M. Christy. The name of the author may not be used to
+ * endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#define RCSID "$Id: chap.c 195720 2001-06-11 11:44:34Z gc $"
+
+/*
+ * TODO:
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/time.h>
+
+#include "pppd.h"
+#include "chap.h"
+#include "md5.h"
+#ifdef CHAPMS
+#include "chap_ms.h"
+#endif
+
+static const char rcsid[] = RCSID;
+
+/*
+ * Command-line options.
+ */
+static option_t chap_option_list[] = {
+ { "chap-restart", o_int, &chap[0].timeouttime,
+ "Set timeout for CHAP", OPT_PRIO },
+ { "chap-max-challenge", o_int, &chap[0].max_transmits,
+ "Set max #xmits for challenge", OPT_PRIO },
+ { "chap-interval", o_int, &chap[0].chal_interval,
+ "Set interval for rechallenge", OPT_PRIO },
+#ifdef MSLANMAN
+ { "ms-lanman", o_bool, &ms_lanman,
+ "Use LanMan passwd when using MS-CHAP", 1 },
+#endif
+ { NULL }
+};
+
+/*
+ * Protocol entry points.
+ */
+static void ChapInit __P((int));
+static void ChapLowerUp __P((int));
+static void ChapLowerDown __P((int));
+static void ChapInput __P((int, u_char *, int));
+static void ChapProtocolReject __P((int));
+static int ChapPrintPkt __P((u_char *, int,
+ void (*) __P((void *, char *, ...)), void *));
+
+struct protent chap_protent = {
+ PPP_CHAP,
+ ChapInit,
+ ChapInput,
+ ChapProtocolReject,
+ ChapLowerUp,
+ ChapLowerDown,
+ NULL,
+ NULL,
+ ChapPrintPkt,
+ NULL,
+ 1,
+ "CHAP",
+ NULL,
+ chap_option_list,
+ NULL,
+ NULL,
+ NULL
+};
+
+chap_state chap[NUM_PPP]; /* CHAP state; one for each unit */
+
+static void ChapChallengeTimeout __P((void *));
+static void ChapResponseTimeout __P((void *));
+static void ChapReceiveChallenge __P((chap_state *, u_char *, int, int));
+static void ChapRechallenge __P((void *));
+static void ChapReceiveResponse __P((chap_state *, u_char *, int, int));
+static void ChapReceiveSuccess __P((chap_state *, u_char *, int, int));
+static void ChapReceiveFailure __P((chap_state *, u_char *, int, int));
+static void ChapSendStatus __P((chap_state *, int));
+static void ChapSendChallenge __P((chap_state *));
+static void ChapSendResponse __P((chap_state *));
+static void ChapGenChallenge __P((chap_state *));
+
+extern double drand48 __P((void));
+extern void srand48 __P((long));
+
+/*
+ * ChapInit - Initialize a CHAP unit.
+ */
+static void
+ChapInit(unit)
+ int unit;
+{
+ chap_state *cstate = &chap[unit];
+
+ BZERO(cstate, sizeof(*cstate));
+ cstate->unit = unit;
+ cstate->clientstate = CHAPCS_INITIAL;
+ cstate->serverstate = CHAPSS_INITIAL;
+ cstate->timeouttime = CHAP_DEFTIMEOUT;
+ cstate->max_transmits = CHAP_DEFTRANSMITS;
+ /* random number generator is initialized in magic_init */
+}
+
+
+/*
+ * ChapAuthWithPeer - Authenticate us with our peer (start client).
+ *
+ */
+void
+ChapAuthWithPeer(unit, our_name, digest)
+ int unit;
+ char *our_name;
+ int digest;
+{
+ chap_state *cstate = &chap[unit];
+
+ cstate->resp_name = our_name;
+ cstate->resp_type = digest;
+
+ if (cstate->clientstate == CHAPCS_INITIAL ||
+ cstate->clientstate == CHAPCS_PENDING) {
+ /* lower layer isn't up - wait until later */
+ cstate->clientstate = CHAPCS_PENDING;
+ return;
+ }
+
+ /*
+ * We get here as a result of LCP coming up.
+ * So even if CHAP was open before, we will
+ * have to re-authenticate ourselves.
+ */
+ cstate->clientstate = CHAPCS_LISTEN;
+}
+
+
+/*
+ * ChapAuthPeer - Authenticate our peer (start server).
+ */
+void
+ChapAuthPeer(unit, our_name, digest)
+ int unit;
+ char *our_name;
+ int digest;
+{
+ chap_state *cstate = &chap[unit];
+
+ cstate->chal_name = our_name;
+ cstate->chal_type = digest;
+
+ if (cstate->serverstate == CHAPSS_INITIAL ||
+ cstate->serverstate == CHAPSS_PENDING) {
+ /* lower layer isn't up - wait until later */
+ cstate->serverstate = CHAPSS_PENDING;
+ return;
+ }
+
+ ChapGenChallenge(cstate);
+ ChapSendChallenge(cstate); /* crank it up dude! */
+ cstate->serverstate = CHAPSS_INITIAL_CHAL;
+}
+
+
+/*
+ * ChapChallengeTimeout - Timeout expired on sending challenge.
+ */
+static void
+ChapChallengeTimeout(arg)
+ void *arg;
+{
+ chap_state *cstate = (chap_state *) arg;
+
+ /* if we aren't sending challenges, don't worry. then again we */
+ /* probably shouldn't be here either */
+ if (cstate->serverstate != CHAPSS_INITIAL_CHAL &&
+ cstate->serverstate != CHAPSS_RECHALLENGE)
+ return;
+
+ if (cstate->chal_transmits >= cstate->max_transmits) {
+ /* give up on peer */
+ error("Peer failed to respond to CHAP challenge");
+ cstate->serverstate = CHAPSS_BADAUTH;
+ auth_peer_fail(cstate->unit, PPP_CHAP);
+ return;
+ }
+
+ ChapSendChallenge(cstate); /* Re-send challenge */
+}
+
+
+/*
+ * ChapResponseTimeout - Timeout expired on sending response.
+ */
+static void
+ChapResponseTimeout(arg)
+ void *arg;
+{
+ chap_state *cstate = (chap_state *) arg;
+
+ /* if we aren't sending a response, don't worry. */
+ if (cstate->clientstate != CHAPCS_RESPONSE)
+ return;
+
+ ChapSendResponse(cstate); /* re-send response */
+}
+
+
+/*
+ * ChapRechallenge - Time to challenge the peer again.
+ */
+static void
+ChapRechallenge(arg)
+ void *arg;
+{
+ chap_state *cstate = (chap_state *) arg;
+
+ /* if we aren't sending a response, don't worry. */
+ if (cstate->serverstate != CHAPSS_OPEN)
+ return;
+
+ ChapGenChallenge(cstate);
+ ChapSendChallenge(cstate);
+ cstate->serverstate = CHAPSS_RECHALLENGE;
+}
+
+
+/*
+ * ChapLowerUp - The lower layer is up.
+ *
+ * Start up if we have pending requests.
+ */
+static void
+ChapLowerUp(unit)
+ int unit;
+{
+ chap_state *cstate = &chap[unit];
+
+ if (cstate->clientstate == CHAPCS_INITIAL)
+ cstate->clientstate = CHAPCS_CLOSED;
+ else if (cstate->clientstate == CHAPCS_PENDING)
+ cstate->clientstate = CHAPCS_LISTEN;
+
+ if (cstate->serverstate == CHAPSS_INITIAL)
+ cstate->serverstate = CHAPSS_CLOSED;
+ else if (cstate->serverstate == CHAPSS_PENDING) {
+ ChapGenChallenge(cstate);
+ ChapSendChallenge(cstate);
+ cstate->serverstate = CHAPSS_INITIAL_CHAL;
+ }
+}
+
+
+/*
+ * ChapLowerDown - The lower layer is down.
+ *
+ * Cancel all timeouts.
+ */
+static void
+ChapLowerDown(unit)
+ int unit;
+{
+ chap_state *cstate = &chap[unit];
+
+ /* Timeout(s) pending? Cancel if so. */
+ if (cstate->serverstate == CHAPSS_INITIAL_CHAL ||
+ cstate->serverstate == CHAPSS_RECHALLENGE)
+ UNTIMEOUT(ChapChallengeTimeout, cstate);
+ else if (cstate->serverstate == CHAPSS_OPEN
+ && cstate->chal_interval != 0)
+ UNTIMEOUT(ChapRechallenge, cstate);
+ if (cstate->clientstate == CHAPCS_RESPONSE)
+ UNTIMEOUT(ChapResponseTimeout, cstate);
+
+ cstate->clientstate = CHAPCS_INITIAL;
+ cstate->serverstate = CHAPSS_INITIAL;
+}
+
+
+/*
+ * ChapProtocolReject - Peer doesn't grok CHAP.
+ */
+static void
+ChapProtocolReject(unit)
+ int unit;
+{
+ chap_state *cstate = &chap[unit];
+
+ if (cstate->serverstate != CHAPSS_INITIAL &&
+ cstate->serverstate != CHAPSS_CLOSED)
+ auth_peer_fail(unit, PPP_CHAP);
+ if (cstate->clientstate != CHAPCS_INITIAL &&
+ cstate->clientstate != CHAPCS_CLOSED)
+ auth_withpeer_fail(unit, PPP_CHAP);
+ ChapLowerDown(unit); /* shutdown chap */
+}
+
+
+/*
+ * ChapInput - Input CHAP packet.
+ */
+static void
+ChapInput(unit, inpacket, packet_len)
+ int unit;
+ u_char *inpacket;
+ int packet_len;
+{
+ chap_state *cstate = &chap[unit];
+ u_char *inp;
+ u_char code, id;
+ int len;
+
+ /*
+ * Parse header (code, id and length).
+ * If packet too short, drop it.
+ */
+ inp = inpacket;
+ if (packet_len < CHAP_HEADERLEN) {
+ CHAPDEBUG(("ChapInput: rcvd short header."));
+ return;
+ }
+ GETCHAR(code, inp);
+ GETCHAR(id, inp);
+ GETSHORT(len, inp);
+ if (len < CHAP_HEADERLEN) {
+ CHAPDEBUG(("ChapInput: rcvd illegal length."));
+ return;
+ }
+ if (len > packet_len) {
+ CHAPDEBUG(("ChapInput: rcvd short packet."));
+ return;
+ }
+ len -= CHAP_HEADERLEN;
+
+ /*
+ * Action depends on code (as in fact it usually does :-).
+ */
+ switch (code) {
+ case CHAP_CHALLENGE:
+ ChapReceiveChallenge(cstate, inp, id, len);
+ break;
+
+ case CHAP_RESPONSE:
+ ChapReceiveResponse(cstate, inp, id, len);
+ break;
+
+ case CHAP_FAILURE:
+ ChapReceiveFailure(cstate, inp, id, len);
+ break;
+
+ case CHAP_SUCCESS:
+ ChapReceiveSuccess(cstate, inp, id, len);
+ break;
+
+ default: /* Need code reject? */
+ warn("Unknown CHAP code (%d) received.", code);
+ break;
+ }
+}
+
+
+/*
+ * ChapReceiveChallenge - Receive Challenge and send Response.
+ */
+static void
+ChapReceiveChallenge(cstate, inp, id, len)
+ chap_state *cstate;
+ u_char *inp;
+ int id;
+ int len;
+{
+ int rchallenge_len;
+ u_char *rchallenge;
+ int secret_len;
+ char secret[MAXSECRETLEN];
+ char rhostname[256];
+ MD5_CTX mdContext;
+ u_char hash[MD5_SIGNATURE_SIZE];
+
+ if (cstate->clientstate == CHAPCS_CLOSED ||
+ cstate->clientstate == CHAPCS_PENDING) {
+ CHAPDEBUG(("ChapReceiveChallenge: in state %d", cstate->clientstate));
+ return;
+ }
+
+ if (len < 2) {
+ CHAPDEBUG(("ChapReceiveChallenge: rcvd short packet."));
+ return;
+ }
+
+ GETCHAR(rchallenge_len, inp);
+ len -= sizeof (u_char) + rchallenge_len; /* now name field length */
+ if (len < 0) {
+ CHAPDEBUG(("ChapReceiveChallenge: rcvd short packet."));
+ return;
+ }
+ rchallenge = inp;
+ INCPTR(rchallenge_len, inp);
+
+ if (len >= sizeof(rhostname))
+ len = sizeof(rhostname) - 1;
+ BCOPY(inp, rhostname, len);
+ rhostname[len] = '\000';
+
+ /* Microsoft doesn't send their name back in the PPP packet */
+ if (explicit_remote || (remote_name[0] != 0 && rhostname[0] == 0)) {
+ strlcpy(rhostname, remote_name, sizeof(rhostname));
+ CHAPDEBUG(("ChapReceiveChallenge: using '%q' as remote name",
+ rhostname));
+ }
+
+ /* get secret for authenticating ourselves with the specified host */
+ if (!get_secret(cstate->unit, cstate->resp_name, rhostname,
+ secret, &secret_len, 0)) {
+ secret_len = 0; /* assume null secret if can't find one */
+ warn("No CHAP secret found for authenticating us to %q", rhostname);
+ }
+
+ /* cancel response send timeout if necessary */
+ if (cstate->clientstate == CHAPCS_RESPONSE)
+ UNTIMEOUT(ChapResponseTimeout, cstate);
+
+ cstate->resp_id = id;
+ cstate->resp_transmits = 0;
+
+ /* generate MD based on negotiated type */
+ switch (cstate->resp_type) {
+
+ case CHAP_DIGEST_MD5:
+ MD5Init(&mdContext);
+ MD5Update(&mdContext, &cstate->resp_id, 1);
+ MD5Update(&mdContext, secret, secret_len);
+ MD5Update(&mdContext, rchallenge, rchallenge_len);
+ MD5Final(hash, &mdContext);
+ BCOPY(hash, cstate->response, MD5_SIGNATURE_SIZE);
+ cstate->resp_length = MD5_SIGNATURE_SIZE;
+ break;
+
+#ifdef CHAPMS
+ case CHAP_MICROSOFT:
+ ChapMS(cstate, rchallenge, rchallenge_len, secret, secret_len);
+ break;
+#endif
+
+ default:
+ CHAPDEBUG(("unknown digest type %d", cstate->resp_type));
+ return;
+ }
+
+ BZERO(secret, sizeof(secret));
+ ChapSendResponse(cstate);
+}
+
+
+/*
+ * ChapReceiveResponse - Receive and process response.
+ */
+static void
+ChapReceiveResponse(cstate, inp, id, len)
+ chap_state *cstate;
+ u_char *inp;
+ int id;
+ int len;
+{
+ u_char *remmd, remmd_len;
+ int secret_len, old_state;
+ int code;
+ char rhostname[256];
+ MD5_CTX mdContext;
+ char secret[MAXSECRETLEN];
+ u_char hash[MD5_SIGNATURE_SIZE];
+
+ if (cstate->serverstate == CHAPSS_CLOSED ||
+ cstate->serverstate == CHAPSS_PENDING) {
+ CHAPDEBUG(("ChapReceiveResponse: in state %d", cstate->serverstate));
+ return;
+ }
+
+ if (id != cstate->chal_id)
+ return; /* doesn't match ID of last challenge */
+
+ /*
+ * If we have received a duplicate or bogus Response,
+ * we have to send the same answer (Success/Failure)
+ * as we did for the first Response we saw.
+ */
+ if (cstate->serverstate == CHAPSS_OPEN) {
+ ChapSendStatus(cstate, CHAP_SUCCESS);
+ return;
+ }
+ if (cstate->serverstate == CHAPSS_BADAUTH) {
+ ChapSendStatus(cstate, CHAP_FAILURE);
+ return;
+ }
+
+ if (len < 2) {
+ CHAPDEBUG(("ChapReceiveResponse: rcvd short packet."));
+ return;
+ }
+ GETCHAR(remmd_len, inp); /* get length of MD */
+ remmd = inp; /* get pointer to MD */
+ INCPTR(remmd_len, inp);
+
+ len -= sizeof (u_char) + remmd_len;
+ if (len < 0) {
+ CHAPDEBUG(("ChapReceiveResponse: rcvd short packet."));
+ return;
+ }
+
+ UNTIMEOUT(ChapChallengeTimeout, cstate);
+
+ if (len >= sizeof(rhostname))
+ len = sizeof(rhostname) - 1;
+ BCOPY(inp, rhostname, len);
+ rhostname[len] = '\000';
+
+ /*
+ * Get secret for authenticating them with us,
+ * do the hash ourselves, and compare the result.
+ */
+ code = CHAP_FAILURE;
+ if (!get_secret(cstate->unit, (explicit_remote? remote_name: rhostname),
+ cstate->chal_name, secret, &secret_len, 1)) {
+ warn("No CHAP secret found for authenticating %q", rhostname);
+ } else {
+
+ /* generate MD based on negotiated type */
+ switch (cstate->chal_type) {
+
+ case CHAP_DIGEST_MD5: /* only MD5 is defined for now */
+ if (remmd_len != MD5_SIGNATURE_SIZE)
+ break; /* it's not even the right length */
+ MD5Init(&mdContext);
+ MD5Update(&mdContext, &cstate->chal_id, 1);
+ MD5Update(&mdContext, secret, secret_len);
+ MD5Update(&mdContext, cstate->challenge, cstate->chal_len);
+ MD5Final(hash, &mdContext);
+
+ /* compare local and remote MDs and send the appropriate status */
+ if (memcmp (hash, remmd, MD5_SIGNATURE_SIZE) == 0)
+ code = CHAP_SUCCESS; /* they are the same! */
+ break;
+
+ default:
+ CHAPDEBUG(("unknown digest type %d", cstate->chal_type));
+ }
+ }
+
+ BZERO(secret, sizeof(secret));
+ ChapSendStatus(cstate, code);
+
+ if (code == CHAP_SUCCESS) {
+ old_state = cstate->serverstate;
+ cstate->serverstate = CHAPSS_OPEN;
+ if (old_state == CHAPSS_INITIAL_CHAL) {
+ auth_peer_success(cstate->unit, PPP_CHAP, rhostname, len);
+ }
+ if (cstate->chal_interval != 0)
+ TIMEOUT(ChapRechallenge, cstate, cstate->chal_interval);
+ notice("CHAP peer authentication succeeded for %q", rhostname);
+
+ } else {
+ error("CHAP peer authentication failed for remote host %q", rhostname);
+ cstate->serverstate = CHAPSS_BADAUTH;
+ auth_peer_fail(cstate->unit, PPP_CHAP);
+ }
+}
+
+/*
+ * ChapReceiveSuccess - Receive Success
+ */
+static void
+ChapReceiveSuccess(cstate, inp, id, len)
+ chap_state *cstate;
+ u_char *inp;
+ u_char id;
+ int len;
+{
+
+ if (cstate->clientstate == CHAPCS_OPEN)
+ /* presumably an answer to a duplicate response */
+ return;
+
+ if (cstate->clientstate != CHAPCS_RESPONSE) {
+ /* don't know what this is */
+ CHAPDEBUG(("ChapReceiveSuccess: in state %d\n", cstate->clientstate));
+ return;
+ }
+
+ UNTIMEOUT(ChapResponseTimeout, cstate);
+
+ /*
+ * Print message.
+ */
+ if (len > 0)
+ PRINTMSG(inp, len);
+
+ cstate->clientstate = CHAPCS_OPEN;
+
+ auth_withpeer_success(cstate->unit, PPP_CHAP);
+}
+
+
+/*
+ * ChapReceiveFailure - Receive failure.
+ */
+static void
+ChapReceiveFailure(cstate, inp, id, len)
+ chap_state *cstate;
+ u_char *inp;
+ u_char id;
+ int len;
+{
+ if (cstate->clientstate != CHAPCS_RESPONSE) {
+ /* don't know what this is */
+ CHAPDEBUG(("ChapReceiveFailure: in state %d\n", cstate->clientstate));
+ return;
+ }
+
+ UNTIMEOUT(ChapResponseTimeout, cstate);
+
+ /*
+ * Print message.
+ */
+ if (len > 0)
+ PRINTMSG(inp, len);
+
+ error("CHAP authentication failed");
+ auth_withpeer_fail(cstate->unit, PPP_CHAP);
+}
+
+
+/*
+ * ChapSendChallenge - Send an Authenticate challenge.
+ */
+static void
+ChapSendChallenge(cstate)
+ chap_state *cstate;
+{
+ u_char *outp;
+ int chal_len, name_len;
+ int outlen;
+
+ chal_len = cstate->chal_len;
+ name_len = strlen(cstate->chal_name);
+ outlen = CHAP_HEADERLEN + sizeof (u_char) + chal_len + name_len;
+ outp = outpacket_buf;
+
+ MAKEHEADER(outp, PPP_CHAP); /* paste in a CHAP header */
+
+ PUTCHAR(CHAP_CHALLENGE, outp);
+ PUTCHAR(cstate->chal_id, outp);
+ PUTSHORT(outlen, outp);
+
+ PUTCHAR(chal_len, outp); /* put length of challenge */
+ BCOPY(cstate->challenge, outp, chal_len);
+ INCPTR(chal_len, outp);
+
+ BCOPY(cstate->chal_name, outp, name_len); /* append hostname */
+
+ output(cstate->unit, outpacket_buf, outlen + PPP_HDRLEN);
+
+ TIMEOUT(ChapChallengeTimeout, cstate, cstate->timeouttime);
+ ++cstate->chal_transmits;
+}
+
+
+/*
+ * ChapSendStatus - Send a status response (ack or nak).
+ */
+static void
+ChapSendStatus(cstate, code)
+ chap_state *cstate;
+ int code;
+{
+ u_char *outp;
+ int outlen, msglen;
+ char msg[256];
+
+ if (code == CHAP_SUCCESS)
+ slprintf(msg, sizeof(msg), "Welcome to %s.", hostname);
+ else
+ slprintf(msg, sizeof(msg), "I don't like you. Go 'way.");
+ msglen = strlen(msg);
+
+ outlen = CHAP_HEADERLEN + msglen;
+ outp = outpacket_buf;
+
+ MAKEHEADER(outp, PPP_CHAP); /* paste in a header */
+
+ PUTCHAR(code, outp);
+ PUTCHAR(cstate->chal_id, outp);
+ PUTSHORT(outlen, outp);
+ BCOPY(msg, outp, msglen);
+ output(cstate->unit, outpacket_buf, outlen + PPP_HDRLEN);
+}
+
+/*
+ * ChapGenChallenge is used to generate a pseudo-random challenge string of
+ * a pseudo-random length between min_len and max_len. The challenge
+ * string and its length are stored in *cstate, and various other fields of
+ * *cstate are initialized.
+ */
+
+static void
+ChapGenChallenge(cstate)
+ chap_state *cstate;
+{
+ int chal_len;
+ u_char *ptr = cstate->challenge;
+ int i;
+
+ /* pick a random challenge length between MIN_CHALLENGE_LENGTH and
+ MAX_CHALLENGE_LENGTH */
+ chal_len = (unsigned) ((drand48() *
+ (MAX_CHALLENGE_LENGTH - MIN_CHALLENGE_LENGTH)) +
+ MIN_CHALLENGE_LENGTH);
+ cstate->chal_len = chal_len;
+ cstate->chal_id = ++cstate->id;
+ cstate->chal_transmits = 0;
+
+ /* generate a random string */
+ for (i = 0; i < chal_len; i++)
+ *ptr++ = (char) (drand48() * 0xff);
+}
+
+/*
+ * ChapSendResponse - send a response packet with values as specified
+ * in *cstate.
+ */
+/* ARGSUSED */
+static void
+ChapSendResponse(cstate)
+ chap_state *cstate;
+{
+ u_char *outp;
+ int outlen, md_len, name_len;
+
+ md_len = cstate->resp_length;
+ name_len = strlen(cstate->resp_name);
+ outlen = CHAP_HEADERLEN + sizeof (u_char) + md_len + name_len;
+ outp = outpacket_buf;
+
+ MAKEHEADER(outp, PPP_CHAP);
+
+ PUTCHAR(CHAP_RESPONSE, outp); /* we are a response */
+ PUTCHAR(cstate->resp_id, outp); /* copy id from challenge packet */
+ PUTSHORT(outlen, outp); /* packet length */
+
+ PUTCHAR(md_len, outp); /* length of MD */
+ BCOPY(cstate->response, outp, md_len); /* copy MD to buffer */
+ INCPTR(md_len, outp);
+
+ BCOPY(cstate->resp_name, outp, name_len); /* append our name */
+
+ /* send the packet */
+ output(cstate->unit, outpacket_buf, outlen + PPP_HDRLEN);
+
+ cstate->clientstate = CHAPCS_RESPONSE;
+ TIMEOUT(ChapResponseTimeout, cstate, cstate->timeouttime);
+ ++cstate->resp_transmits;
+}
+
+/*
+ * ChapPrintPkt - print the contents of a CHAP packet.
+ */
+static char *ChapCodenames[] = {
+ "Challenge", "Response", "Success", "Failure"
+};
+
+static int
+ChapPrintPkt(p, plen, printer, arg)
+ u_char *p;
+ int plen;
+ void (*printer) __P((void *, char *, ...));
+ void *arg;
+{
+ int code, id, len;
+ int clen, nlen;
+ u_char x;
+
+ if (plen < CHAP_HEADERLEN)
+ return 0;
+ GETCHAR(code, p);
+ GETCHAR(id, p);
+ GETSHORT(len, p);
+ if (len < CHAP_HEADERLEN || len > plen)
+ return 0;
+
+ if (code >= 1 && code <= sizeof(ChapCodenames) / sizeof(char *))
+ printer(arg, " %s", ChapCodenames[code-1]);
+ else
+ printer(arg, " code=0x%x", code);
+ printer(arg, " id=0x%x", id);
+ len -= CHAP_HEADERLEN;
+ switch (code) {
+ case CHAP_CHALLENGE:
+ case CHAP_RESPONSE:
+ if (len < 1)
+ break;
+ clen = p[0];
+ if (len < clen + 1)
+ break;
+ ++p;
+ nlen = len - clen - 1;
+ printer(arg, " <");
+ for (; clen > 0; --clen) {
+ GETCHAR(x, p);
+ printer(arg, "%.2x", x);
+ }
+ printer(arg, ">, name = ");
+ print_string((char *)p, nlen, printer, arg);
+ break;
+ case CHAP_FAILURE:
+ case CHAP_SUCCESS:
+ printer(arg, " ");
+ print_string((char *)p, len, printer, arg);
+ break;
+ default:
+ for (clen = len; clen > 0; --clen) {
+ GETCHAR(x, p);
+ printer(arg, " %.2x", x);
+ }
+ }
+
+ return len + CHAP_HEADERLEN;
+}
diff --git a/mdk-stage1/ppp/pppd/chap.h b/mdk-stage1/ppp/pppd/chap.h
new file mode 100644
index 000000000..1218c151b
--- /dev/null
+++ b/mdk-stage1/ppp/pppd/chap.h
@@ -0,0 +1,124 @@
+/*
+ * chap.h - Challenge Handshake Authentication Protocol definitions.
+ *
+ * Copyright (c) 1993 The Australian National University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the Australian National University. The name of the University
+ * may not be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Copyright (c) 1991 Gregory M. Christy
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the author.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id: chap.h 195720 2001-06-11 11:44:34Z gc $
+ */
+
+#ifndef __CHAP_INCLUDE__
+
+/* Code + ID + length */
+#define CHAP_HEADERLEN 4
+
+/*
+ * CHAP codes.
+ */
+
+#define CHAP_DIGEST_MD5 5 /* use MD5 algorithm */
+#define MD5_SIGNATURE_SIZE 16 /* 16 bytes in a MD5 message digest */
+#define CHAP_MICROSOFT 0x80 /* use Microsoft-compatible alg. */
+#define MS_CHAP_RESPONSE_LEN 49 /* Response length for MS-CHAP */
+
+#define CHAP_CHALLENGE 1
+#define CHAP_RESPONSE 2
+#define CHAP_SUCCESS 3
+#define CHAP_FAILURE 4
+
+/*
+ * Challenge lengths (for challenges we send) and other limits.
+ */
+#define MIN_CHALLENGE_LENGTH 16
+#define MAX_CHALLENGE_LENGTH 24
+#define MAX_RESPONSE_LENGTH 64 /* sufficient for MD5 or MS-CHAP */
+
+/*
+ * Each interface is described by a chap structure.
+ */
+
+typedef struct chap_state {
+ int unit; /* Interface unit number */
+ int clientstate; /* Client state */
+ int serverstate; /* Server state */
+ u_char challenge[MAX_CHALLENGE_LENGTH]; /* last challenge string sent */
+ u_char chal_len; /* challenge length */
+ u_char chal_id; /* ID of last challenge */
+ u_char chal_type; /* hash algorithm for challenges */
+ u_char id; /* Current id */
+ char *chal_name; /* Our name to use with challenge */
+ int chal_interval; /* Time until we challenge peer again */
+ int timeouttime; /* Timeout time in seconds */
+ int max_transmits; /* Maximum # of challenge transmissions */
+ int chal_transmits; /* Number of transmissions of challenge */
+ int resp_transmits; /* Number of transmissions of response */
+ u_char response[MAX_RESPONSE_LENGTH]; /* Response to send */
+ u_char resp_length; /* length of response */
+ u_char resp_id; /* ID for response messages */
+ u_char resp_type; /* hash algorithm for responses */
+ char *resp_name; /* Our name to send with response */
+} chap_state;
+
+
+/*
+ * Client (peer) states.
+ */
+#define CHAPCS_INITIAL 0 /* Lower layer down, not opened */
+#define CHAPCS_CLOSED 1 /* Lower layer up, not opened */
+#define CHAPCS_PENDING 2 /* Auth us to peer when lower up */
+#define CHAPCS_LISTEN 3 /* Listening for a challenge */
+#define CHAPCS_RESPONSE 4 /* Sent response, waiting for status */
+#define CHAPCS_OPEN 5 /* We've received Success */
+
+/*
+ * Server (authenticator) states.
+ */
+#define CHAPSS_INITIAL 0 /* Lower layer down, not opened */
+#define CHAPSS_CLOSED 1 /* Lower layer up, not opened */
+#define CHAPSS_PENDING 2 /* Auth peer when lower up */
+#define CHAPSS_INITIAL_CHAL 3 /* We've sent the first challenge */
+#define CHAPSS_OPEN 4 /* We've sent a Success msg */
+#define CHAPSS_RECHALLENGE 5 /* We've sent another challenge */
+#define CHAPSS_BADAUTH 6 /* We've sent a Failure msg */
+
+/*
+ * Timeouts.
+ */
+#define CHAP_DEFTIMEOUT 3 /* Timeout time in seconds */
+#define CHAP_DEFTRANSMITS 10 /* max # times to send challenge */
+
+extern chap_state chap[];
+
+void ChapAuthWithPeer __P((int, char *, int));
+void ChapAuthPeer __P((int, char *, int));
+
+extern struct protent chap_protent;
+
+#define __CHAP_INCLUDE__
+#endif /* __CHAP_INCLUDE__ */
diff --git a/mdk-stage1/ppp/pppd/chap_ms.c b/mdk-stage1/ppp/pppd/chap_ms.c
new file mode 100644
index 000000000..9cf9ada66
--- /dev/null
+++ b/mdk-stage1/ppp/pppd/chap_ms.c
@@ -0,0 +1,338 @@
+/*
+ * chap_ms.c - Microsoft MS-CHAP compatible implementation.
+ *
+ * Copyright (c) 1995 Eric Rosenquist, Strata Software Limited.
+ * http://www.strataware.com/
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Eric Rosenquist. The name of the author may not be used to
+ * endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/*
+ * Modifications by Lauri Pesonen / lpesonen@clinet.fi, april 1997
+ *
+ * Implemented LANManager type password response to MS-CHAP challenges.
+ * Now pppd provides both NT style and LANMan style blocks, and the
+ * prefered is set by option "ms-lanman". Default is to use NT.
+ * The hash text (StdText) was taken from Win95 RASAPI32.DLL.
+ *
+ * You should also use DOMAIN\\USERNAME as described in README.MSCHAP80
+ */
+
+#define RCSID "$Id: chap_ms.c 195720 2001-06-11 11:44:34Z gc $"
+
+#ifdef CHAPMS
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <unistd.h>
+#ifdef HAVE_CRYPT_H
+#include <crypt.h>
+#endif
+
+#include "pppd.h"
+#include "chap.h"
+#include "chap_ms.h"
+#include "md4.h"
+
+#ifndef USE_CRYPT
+#include <des.h>
+#endif
+
+static const char rcsid[] = RCSID;
+
+typedef struct {
+ u_char LANManResp[24];
+ u_char NTResp[24];
+ u_char UseNT; /* If 1, ignore the LANMan response field */
+} MS_ChapResponse;
+/* We use MS_CHAP_RESPONSE_LEN, rather than sizeof(MS_ChapResponse),
+ in case this struct gets padded. */
+
+
+static void ChallengeResponse __P((u_char *, u_char *, u_char *));
+static void DesEncrypt __P((u_char *, u_char *, u_char *));
+static void MakeKey __P((u_char *, u_char *));
+static u_char Get7Bits __P((u_char *, int));
+static void ChapMS_NT __P((char *, int, char *, int, MS_ChapResponse *));
+#ifdef MSLANMAN
+static void ChapMS_LANMan __P((char *, int, char *, int, MS_ChapResponse *));
+#endif
+
+#ifdef USE_CRYPT
+static void Expand __P((u_char *, u_char *));
+static void Collapse __P((u_char *, u_char *));
+#endif
+
+#ifdef MSLANMAN
+bool ms_lanman = 0; /* Use LanMan password instead of NT */
+ /* Has meaning only with MS-CHAP challenges */
+#endif
+
+static void
+ChallengeResponse(challenge, pwHash, response)
+ u_char *challenge; /* IN 8 octets */
+ u_char *pwHash; /* IN 16 octets */
+ u_char *response; /* OUT 24 octets */
+{
+ char ZPasswordHash[21];
+
+ BZERO(ZPasswordHash, sizeof(ZPasswordHash));
+ BCOPY(pwHash, ZPasswordHash, MD4_SIGNATURE_SIZE);
+
+#if 0
+ dbglog("ChallengeResponse - ZPasswordHash %.*B",
+ sizeof(ZPasswordHash), ZPasswordHash);
+#endif
+
+ DesEncrypt(challenge, ZPasswordHash + 0, response + 0);
+ DesEncrypt(challenge, ZPasswordHash + 7, response + 8);
+ DesEncrypt(challenge, ZPasswordHash + 14, response + 16);
+
+#if 0
+ dbglog("ChallengeResponse - response %.24B", response);
+#endif
+}
+
+
+#ifdef USE_CRYPT
+static void
+DesEncrypt(clear, key, cipher)
+ u_char *clear; /* IN 8 octets */
+ u_char *key; /* IN 7 octets */
+ u_char *cipher; /* OUT 8 octets */
+{
+ u_char des_key[8];
+ u_char crypt_key[66];
+ u_char des_input[66];
+
+ MakeKey(key, des_key);
+
+ Expand(des_key, crypt_key);
+ setkey(crypt_key);
+
+#if 0
+ CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet input : %.8B", clear));
+#endif
+
+ Expand(clear, des_input);
+ encrypt(des_input, 0);
+ Collapse(des_input, cipher);
+
+#if 0
+ CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet output: %.8B", cipher));
+#endif
+}
+
+#else /* USE_CRYPT */
+
+static void
+DesEncrypt(clear, key, cipher)
+ u_char *clear; /* IN 8 octets */
+ u_char *key; /* IN 7 octets */
+ u_char *cipher; /* OUT 8 octets */
+{
+ des_cblock des_key;
+ des_key_schedule key_schedule;
+
+ MakeKey(key, des_key);
+
+ des_set_key(&des_key, key_schedule);
+
+#if 0
+ CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet input : %.8B", clear));
+#endif
+
+ des_ecb_encrypt((des_cblock *)clear, (des_cblock *)cipher, key_schedule, 1);
+
+#if 0
+ CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet output: %.8B", cipher));
+#endif
+}
+
+#endif /* USE_CRYPT */
+
+
+static u_char Get7Bits(input, startBit)
+ u_char *input;
+ int startBit;
+{
+ register unsigned int word;
+
+ word = (unsigned)input[startBit / 8] << 8;
+ word |= (unsigned)input[startBit / 8 + 1];
+
+ word >>= 15 - (startBit % 8 + 7);
+
+ return word & 0xFE;
+}
+
+#ifdef USE_CRYPT
+
+/* in == 8-byte string (expanded version of the 56-bit key)
+ * out == 64-byte string where each byte is either 1 or 0
+ * Note that the low-order "bit" is always ignored by by setkey()
+ */
+static void Expand(in, out)
+ u_char *in;
+ u_char *out;
+{
+ int j, c;
+ int i;
+
+ for(i = 0; i < 64; in++){
+ c = *in;
+ for(j = 7; j >= 0; j--)
+ *out++ = (c >> j) & 01;
+ i += 8;
+ }
+}
+
+/* The inverse of Expand
+ */
+static void Collapse(in, out)
+ u_char *in;
+ u_char *out;
+{
+ int j;
+ int i;
+ unsigned int c;
+
+ for (i = 0; i < 64; i += 8, out++) {
+ c = 0;
+ for (j = 7; j >= 0; j--, in++)
+ c |= *in << j;
+ *out = c & 0xff;
+ }
+}
+#endif
+
+static void MakeKey(key, des_key)
+ u_char *key; /* IN 56 bit DES key missing parity bits */
+ u_char *des_key; /* OUT 64 bit DES key with parity bits added */
+{
+ des_key[0] = Get7Bits(key, 0);
+ des_key[1] = Get7Bits(key, 7);
+ des_key[2] = Get7Bits(key, 14);
+ des_key[3] = Get7Bits(key, 21);
+ des_key[4] = Get7Bits(key, 28);
+ des_key[5] = Get7Bits(key, 35);
+ des_key[6] = Get7Bits(key, 42);
+ des_key[7] = Get7Bits(key, 49);
+
+#ifndef USE_CRYPT
+ des_set_odd_parity((des_cblock *)des_key);
+#endif
+
+#if 0
+ CHAPDEBUG((LOG_INFO, "MakeKey: 56-bit input : %.7B", key));
+ CHAPDEBUG((LOG_INFO, "MakeKey: 64-bit output: %.8B", des_key));
+#endif
+}
+
+static void
+ChapMS_NT(rchallenge, rchallenge_len, secret, secret_len, response)
+ char *rchallenge;
+ int rchallenge_len;
+ char *secret;
+ int secret_len;
+ MS_ChapResponse *response;
+{
+ int i;
+#ifdef __NetBSD__
+ /* NetBSD uses the libc md4 routines which take bytes instead of bits */
+ int mdlen = secret_len * 2;
+#else
+ int mdlen = secret_len * 2 * 8;
+#endif
+ MD4_CTX md4Context;
+ u_char hash[MD4_SIGNATURE_SIZE];
+ u_char unicodePassword[MAX_NT_PASSWORD * 2];
+
+ /* Initialize the Unicode version of the secret (== password). */
+ /* This implicitly supports 8-bit ISO8859/1 characters. */
+ BZERO(unicodePassword, sizeof(unicodePassword));
+ for (i = 0; i < secret_len; i++)
+ unicodePassword[i * 2] = (u_char)secret[i];
+
+ MD4Init(&md4Context);
+ MD4Update(&md4Context, unicodePassword, mdlen);
+
+ MD4Final(hash, &md4Context); /* Tell MD4 we're done */
+
+ ChallengeResponse(rchallenge, hash, response->NTResp);
+}
+
+#ifdef MSLANMAN
+static u_char *StdText = (u_char *)"KGS!@#$%"; /* key from rasapi32.dll */
+
+static void
+ChapMS_LANMan(rchallenge, rchallenge_len, secret, secret_len, response)
+ char *rchallenge;
+ int rchallenge_len;
+ char *secret;
+ int secret_len;
+ MS_ChapResponse *response;
+{
+ int i;
+ u_char UcasePassword[MAX_NT_PASSWORD]; /* max is actually 14 */
+ u_char PasswordHash[MD4_SIGNATURE_SIZE];
+
+ /* LANMan password is case insensitive */
+ BZERO(UcasePassword, sizeof(UcasePassword));
+ for (i = 0; i < secret_len; i++)
+ UcasePassword[i] = (u_char)toupper(secret[i]);
+ DesEncrypt( StdText, UcasePassword + 0, PasswordHash + 0 );
+ DesEncrypt( StdText, UcasePassword + 7, PasswordHash + 8 );
+ ChallengeResponse(rchallenge, PasswordHash, response->LANManResp);
+}
+#endif
+
+void
+ChapMS(cstate, rchallenge, rchallenge_len, secret, secret_len)
+ chap_state *cstate;
+ char *rchallenge;
+ int rchallenge_len;
+ char *secret;
+ int secret_len;
+{
+ MS_ChapResponse response;
+
+#if 0
+ CHAPDEBUG((LOG_INFO, "ChapMS: secret is '%.*s'", secret_len, secret));
+#endif
+ BZERO(&response, sizeof(response));
+
+ /* Calculate both always */
+ ChapMS_NT(rchallenge, rchallenge_len, secret, secret_len, &response);
+
+#ifdef MSLANMAN
+ ChapMS_LANMan(rchallenge, rchallenge_len, secret, secret_len, &response);
+
+ /* prefered method is set by option */
+ response.UseNT = !ms_lanman;
+#else
+ response.UseNT = 1;
+#endif
+
+ BCOPY(&response, cstate->response, MS_CHAP_RESPONSE_LEN);
+ cstate->resp_length = MS_CHAP_RESPONSE_LEN;
+}
+
+#endif /* CHAPMS */
diff --git a/mdk-stage1/ppp/pppd/chap_ms.h b/mdk-stage1/ppp/pppd/chap_ms.h
new file mode 100644
index 000000000..ab2848a59
--- /dev/null
+++ b/mdk-stage1/ppp/pppd/chap_ms.h
@@ -0,0 +1,33 @@
+/*
+ * chap.h - Challenge Handshake Authentication Protocol definitions.
+ *
+ * Copyright (c) 1995 Eric Rosenquist, Strata Software Limited.
+ * http://www.strataware.com/
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Eric Rosenquist. The name of the author may not be used to
+ * endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id: chap_ms.h 195720 2001-06-11 11:44:34Z gc $
+ */
+
+#ifndef __CHAPMS_INCLUDE__
+
+#define MD4_SIGNATURE_SIZE 16 /* 16 bytes in a MD4 message digest */
+#define MAX_NT_PASSWORD 256 /* Maximum number of (Unicode) chars in an NT password */
+
+void ChapMS __P((chap_state *, char *, int, char *, int));
+
+#define __CHAPMS_INCLUDE__
+#endif /* __CHAPMS_INCLUDE__ */
diff --git a/mdk-stage1/ppp/pppd/demand.c b/mdk-stage1/ppp/pppd/demand.c
new file mode 100644
index 000000000..293c8957e
--- /dev/null
+++ b/mdk-stage1/ppp/pppd/demand.c
@@ -0,0 +1,351 @@
+/*
+ * demand.c - Support routines for demand-dialling.
+ *
+ * Copyright (c) 1993 The Australian National University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the Australian National University. The name of the University
+ * may not be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#define RCSID "$Id: demand.c 195720 2001-06-11 11:44:34Z gc $"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <netdb.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#ifdef PPP_FILTER
+#include <net/if.h>
+#include <net/bpf.h>
+#include <pcap.h>
+#endif
+
+#include "pppd.h"
+#include "fsm.h"
+#include "ipcp.h"
+#include "lcp.h"
+
+static const char rcsid[] = RCSID;
+
+char *frame;
+int framelen;
+int framemax;
+int escape_flag;
+int flush_flag;
+int fcs;
+
+struct packet {
+ int length;
+ struct packet *next;
+ unsigned char data[1];
+};
+
+struct packet *pend_q;
+struct packet *pend_qtail;
+
+static int active_packet __P((unsigned char *, int));
+
+/*
+ * demand_conf - configure the interface for doing dial-on-demand.
+ */
+void
+demand_conf()
+{
+ int i;
+ struct protent *protp;
+
+/* framemax = lcp_allowoptions[0].mru;
+ if (framemax < PPP_MRU) */
+ framemax = PPP_MRU;
+ framemax += PPP_HDRLEN + PPP_FCSLEN;
+ frame = malloc(framemax);
+ if (frame == NULL)
+ novm("demand frame");
+ framelen = 0;
+ pend_q = NULL;
+ escape_flag = 0;
+ flush_flag = 0;
+ fcs = PPP_INITFCS;
+
+ netif_set_mtu(0, MIN(lcp_allowoptions[0].mru, PPP_MRU));
+ ppp_send_config(0, PPP_MRU, (u_int32_t) 0, 0, 0);
+ ppp_recv_config(0, PPP_MRU, (u_int32_t) 0, 0, 0);
+
+#ifdef PPP_FILTER
+ set_filters(&pass_filter, &active_filter);
+#endif
+
+ /*
+ * Call the demand_conf procedure for each protocol that's got one.
+ */
+ for (i = 0; (protp = protocols[i]) != NULL; ++i)
+ if (protp->enabled_flag && protp->demand_conf != NULL)
+ if (!((*protp->demand_conf)(0)))
+ die(1);
+}
+
+
+/*
+ * demand_block - set each network protocol to block further packets.
+ */
+void
+demand_block()
+{
+ int i;
+ struct protent *protp;
+
+ for (i = 0; (protp = protocols[i]) != NULL; ++i)
+ if (protp->enabled_flag && protp->demand_conf != NULL)
+ sifnpmode(0, protp->protocol & ~0x8000, NPMODE_QUEUE);
+ get_loop_output();
+}
+
+/*
+ * demand_discard - set each network protocol to discard packets
+ * with an error.
+ */
+void
+demand_discard()
+{
+ struct packet *pkt, *nextpkt;
+ int i;
+ struct protent *protp;
+
+ for (i = 0; (protp = protocols[i]) != NULL; ++i)
+ if (protp->enabled_flag && protp->demand_conf != NULL)
+ sifnpmode(0, protp->protocol & ~0x8000, NPMODE_ERROR);
+ get_loop_output();
+
+ /* discard all saved packets */
+ for (pkt = pend_q; pkt != NULL; pkt = nextpkt) {
+ nextpkt = pkt->next;
+ free(pkt);
+ }
+ pend_q = NULL;
+ framelen = 0;
+ flush_flag = 0;
+ escape_flag = 0;
+ fcs = PPP_INITFCS;
+}
+
+/*
+ * demand_unblock - set each enabled network protocol to pass packets.
+ */
+void
+demand_unblock()
+{
+ int i;
+ struct protent *protp;
+
+ for (i = 0; (protp = protocols[i]) != NULL; ++i)
+ if (protp->enabled_flag && protp->demand_conf != NULL)
+ sifnpmode(0, protp->protocol & ~0x8000, NPMODE_PASS);
+}
+
+/*
+ * FCS lookup table as calculated by genfcstab.
+ */
+static u_short fcstab[256] = {
+ 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
+ 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
+ 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
+ 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
+ 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
+ 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
+ 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
+ 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
+ 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
+ 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
+ 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
+ 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
+ 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
+ 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
+ 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
+ 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
+ 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
+ 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
+ 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
+ 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
+ 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
+ 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
+ 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
+ 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
+ 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
+ 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
+ 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
+ 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
+ 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
+ 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
+ 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
+ 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
+};
+
+/*
+ * loop_chars - process characters received from the loopback.
+ * Calls loop_frame when a complete frame has been accumulated.
+ * Return value is 1 if we need to bring up the link, 0 otherwise.
+ */
+int
+loop_chars(p, n)
+ unsigned char *p;
+ int n;
+{
+ int c, rv;
+
+ rv = 0;
+ for (; n > 0; --n) {
+ c = *p++;
+ if (c == PPP_FLAG) {
+ if (!escape_flag && !flush_flag
+ && framelen > 2 && fcs == PPP_GOODFCS) {
+ framelen -= 2;
+ if (loop_frame((unsigned char *)frame, framelen))
+ rv = 1;
+ }
+ framelen = 0;
+ flush_flag = 0;
+ escape_flag = 0;
+ fcs = PPP_INITFCS;
+ continue;
+ }
+ if (flush_flag)
+ continue;
+ if (escape_flag) {
+ c ^= PPP_TRANS;
+ escape_flag = 0;
+ } else if (c == PPP_ESCAPE) {
+ escape_flag = 1;
+ continue;
+ }
+ if (framelen >= framemax) {
+ flush_flag = 1;
+ continue;
+ }
+ frame[framelen++] = c;
+ fcs = PPP_FCS(fcs, c);
+ }
+ return rv;
+}
+
+/*
+ * loop_frame - given a frame obtained from the loopback,
+ * decide whether to bring up the link or not, and, if we want
+ * to transmit this frame later, put it on the pending queue.
+ * Return value is 1 if we need to bring up the link, 0 otherwise.
+ * We assume that the kernel driver has already applied the
+ * pass_filter, so we won't get packets it rejected.
+ * We apply the active_filter to see if we want this packet to
+ * bring up the link.
+ */
+int
+loop_frame(frame, len)
+ unsigned char *frame;
+ int len;
+{
+ struct packet *pkt;
+
+ /* dbglog("from loop: %P", frame, len); */
+ if (len < PPP_HDRLEN)
+ return 0;
+ if ((PPP_PROTOCOL(frame) & 0x8000) != 0)
+ return 0; /* shouldn't get any of these anyway */
+ if (!active_packet(frame, len))
+ return 0;
+
+ pkt = (struct packet *) malloc(sizeof(struct packet) + len);
+ if (pkt != NULL) {
+ pkt->length = len;
+ pkt->next = NULL;
+ memcpy(pkt->data, frame, len);
+ if (pend_q == NULL)
+ pend_q = pkt;
+ else
+ pend_qtail->next = pkt;
+ pend_qtail = pkt;
+ }
+ return 1;
+}
+
+/*
+ * demand_rexmit - Resend all those frames which we got via the
+ * loopback, now that the real serial link is up.
+ */
+void
+demand_rexmit(proto)
+ int proto;
+{
+ struct packet *pkt, *prev, *nextpkt;
+
+ prev = NULL;
+ pkt = pend_q;
+ pend_q = NULL;
+ for (; pkt != NULL; pkt = nextpkt) {
+ nextpkt = pkt->next;
+ if (PPP_PROTOCOL(pkt->data) == proto) {
+ output(0, pkt->data, pkt->length);
+ free(pkt);
+ } else {
+ if (prev == NULL)
+ pend_q = pkt;
+ else
+ prev->next = pkt;
+ prev = pkt;
+ }
+ }
+ pend_qtail = prev;
+ if (prev != NULL)
+ prev->next = NULL;
+}
+
+/*
+ * Scan a packet to decide whether it is an "active" packet,
+ * that is, whether it is worth bringing up the link for.
+ */
+static int
+active_packet(p, len)
+ unsigned char *p;
+ int len;
+{
+ int proto, i;
+ struct protent *protp;
+
+ if (len < PPP_HDRLEN)
+ return 0;
+ proto = PPP_PROTOCOL(p);
+#ifdef PPP_FILTER
+ if (pass_filter.bf_len != 0
+ && bpf_filter(pass_filter.bf_insns, p, len, len) == 0)
+ return 0;
+ if (active_filter.bf_len != 0
+ && bpf_filter(active_filter.bf_insns, p, len, len) == 0)
+ return 0;
+#endif
+ for (i = 0; (protp = protocols[i]) != NULL; ++i) {
+ if (protp->protocol < 0xC000 && (protp->protocol & ~0x8000) == proto) {
+ if (!protp->enabled_flag)
+ return 0;
+ if (protp->active_pkt == NULL)
+ return 1;
+ return (*protp->active_pkt)(p, len);
+ }
+ }
+ return 0; /* not a supported protocol !!?? */
+}
diff --git a/mdk-stage1/ppp/pppd/eui64.c b/mdk-stage1/ppp/pppd/eui64.c
new file mode 100644
index 000000000..a18c43a27
--- /dev/null
+++ b/mdk-stage1/ppp/pppd/eui64.c
@@ -0,0 +1,40 @@
+/*
+ eui64.c - EUI64 routines for IPv6CP.
+ Copyright (C) 1999 Tommi Komulainen <Tommi.Komulainen@iki.fi>
+
+ Redistribution and use in source and binary forms are permitted
+ provided that the above copyright notice and this paragraph are
+ duplicated in all such forms and that any documentation,
+ advertising materials, and other materials related to such
+ distribution and use acknowledge that the software was developed
+ by Tommi Komulainen. The name of the author may not be used
+ to endorse or promote products derived from this software without
+ specific prior written permission.
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+
+
+ $Id: eui64.c 195720 2001-06-11 11:44:34Z gc $
+*/
+
+#define RCSID "$Id: eui64.c 195720 2001-06-11 11:44:34Z gc $"
+
+#include "pppd.h"
+
+static const char rcsid[] = RCSID;
+
+/*
+ * eui64_ntoa - Make an ascii representation of an interface identifier
+ */
+char *
+eui64_ntoa(e)
+ eui64_t e;
+{
+ static char buf[32];
+
+ snprintf(buf, 32, "%02x%02x:%02x%02x:%02x%02x:%02x%02x",
+ e.e8[0], e.e8[1], e.e8[2], e.e8[3],
+ e.e8[4], e.e8[5], e.e8[6], e.e8[7]);
+ return buf;
+}
diff --git a/mdk-stage1/ppp/pppd/eui64.h b/mdk-stage1/ppp/pppd/eui64.h
new file mode 100644
index 000000000..1398f08da
--- /dev/null
+++ b/mdk-stage1/ppp/pppd/eui64.h
@@ -0,0 +1,97 @@
+/*
+ eui64.h - EUI64 routines for IPv6CP.
+ Copyright (C) 1999 Tommi Komulainen <Tommi.Komulainen@iki.fi>
+
+ Redistribution and use in source and binary forms are permitted
+ provided that the above copyright notice and this paragraph are
+ duplicated in all such forms and that any documentation,
+ advertising materials, and other materials related to such
+ distribution and use acknowledge that the software was developed
+ by Tommi Komulainen. The name of the author may not be used
+ to endorse or promote products derived from this software without
+ specific prior written permission.
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+
+
+ $Id: eui64.h 195720 2001-06-11 11:44:34Z gc $
+*/
+
+#ifndef __EUI64_H__
+#define __EUI64_H__
+
+#if !defined(INET6)
+#error "this file should only be included when INET6 is defined"
+#endif /* not defined(INET6) */
+
+#if defined(SOL2)
+#include <netinet/in.h>
+
+typedef union {
+ uint8_t e8[8]; /* lower 64-bit IPv6 address */
+ uint32_t e32[2]; /* lower 64-bit IPv6 address */
+} eui64_t;
+
+/*
+ * Declare the two below, since in.h only defines them when _KERNEL
+ * is declared - which shouldn't be true when dealing with user-land programs
+ */
+#define s6_addr8 _S6_un._S6_u8
+#define s6_addr32 _S6_un._S6_u32
+
+#else /* else if not defined(SOL2) */
+
+/*
+ * TODO:
+ *
+ * Maybe this should be done by processing struct in6_addr directly...
+ */
+typedef union
+{
+ u_int8_t e8[8];
+ u_int16_t e16[4];
+ u_int32_t e32[2];
+} eui64_t;
+
+#endif /* defined(SOL2) */
+
+#define eui64_iszero(e) (((e).e32[0] | (e).e32[1]) == 0)
+#define eui64_equals(e, o) (((e).e32[0] == (o).e32[0]) && \
+ ((e).e32[1] == (o).e32[1]))
+#define eui64_zero(e) (e).e32[0] = (e).e32[1] = 0;
+
+#define eui64_copy(s, d) memcpy(&(d), &(s), sizeof(eui64_t))
+
+#define eui64_magic(e) do { \
+ (e).e32[0] = magic(); \
+ (e).e32[1] = magic(); \
+ (e).e8[0] &= ~2; \
+ } while (0)
+#define eui64_magic_nz(x) do { \
+ eui64_magic(x); \
+ } while (eui64_iszero(x))
+#define eui64_magic_ne(x, y) do { \
+ eui64_magic(x); \
+ } while (eui64_equals(x, y))
+
+#define eui64_get(ll, cp) do { \
+ eui64_copy((*cp), (ll)); \
+ (cp) += sizeof(eui64_t); \
+ } while (0)
+
+#define eui64_put(ll, cp) do { \
+ eui64_copy((ll), (*cp)); \
+ (cp) += sizeof(eui64_t); \
+ } while (0)
+
+#define eui64_set32(e, l) do { \
+ (e).e32[0] = 0; \
+ (e).e32[1] = htonl(l); \
+ } while (0)
+#define eui64_setlo32(e, l) eui64_set32(e, l)
+
+char *eui64_ntoa __P((eui64_t)); /* Returns ascii representation of id */
+
+#endif /* __EUI64_H__ */
+
diff --git a/mdk-stage1/ppp/pppd/fsm.c b/mdk-stage1/ppp/pppd/fsm.c
new file mode 100644
index 000000000..92661fc7a
--- /dev/null
+++ b/mdk-stage1/ppp/pppd/fsm.c
@@ -0,0 +1,762 @@
+/*
+ * fsm.c - {Link, IP} Control Protocol Finite State Machine.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#define RCSID "$Id: fsm.c 195720 2001-06-11 11:44:34Z gc $"
+
+/*
+ * TODO:
+ * Randomize fsm id on link/init.
+ * Deal with variable outgoing MTU.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+
+#include "pppd.h"
+#include "fsm.h"
+
+static const char rcsid[] = RCSID;
+
+static void fsm_timeout __P((void *));
+static void fsm_rconfreq __P((fsm *, int, u_char *, int));
+static void fsm_rconfack __P((fsm *, int, u_char *, int));
+static void fsm_rconfnakrej __P((fsm *, int, int, u_char *, int));
+static void fsm_rtermreq __P((fsm *, int, u_char *, int));
+static void fsm_rtermack __P((fsm *));
+static void fsm_rcoderej __P((fsm *, u_char *, int));
+static void fsm_sconfreq __P((fsm *, int));
+
+#define PROTO_NAME(f) ((f)->callbacks->proto_name)
+
+int peer_mru[NUM_PPP];
+
+
+/*
+ * fsm_init - Initialize fsm.
+ *
+ * Initialize fsm state.
+ */
+void
+fsm_init(f)
+ fsm *f;
+{
+ f->state = INITIAL;
+ f->flags = 0;
+ f->id = 0; /* XXX Start with random id? */
+ f->timeouttime = DEFTIMEOUT;
+ f->maxconfreqtransmits = DEFMAXCONFREQS;
+ f->maxtermtransmits = DEFMAXTERMREQS;
+ f->maxnakloops = DEFMAXNAKLOOPS;
+ f->term_reason_len = 0;
+}
+
+
+/*
+ * fsm_lowerup - The lower layer is up.
+ */
+void
+fsm_lowerup(f)
+ fsm *f;
+{
+ switch( f->state ){
+ case INITIAL:
+ f->state = CLOSED;
+ break;
+
+ case STARTING:
+ if( f->flags & OPT_SILENT )
+ f->state = STOPPED;
+ else {
+ /* Send an initial configure-request */
+ fsm_sconfreq(f, 0);
+ f->state = REQSENT;
+ }
+ break;
+
+ default:
+ FSMDEBUG(("%s: Up event in state %d!", PROTO_NAME(f), f->state));
+ }
+}
+
+
+/*
+ * fsm_lowerdown - The lower layer is down.
+ *
+ * Cancel all timeouts and inform upper layers.
+ */
+void
+fsm_lowerdown(f)
+ fsm *f;
+{
+ switch( f->state ){
+ case CLOSED:
+ f->state = INITIAL;
+ break;
+
+ case STOPPED:
+ f->state = STARTING;
+ if( f->callbacks->starting )
+ (*f->callbacks->starting)(f);
+ break;
+
+ case CLOSING:
+ f->state = INITIAL;
+ UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
+ break;
+
+ case STOPPING:
+ case REQSENT:
+ case ACKRCVD:
+ case ACKSENT:
+ f->state = STARTING;
+ UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
+ break;
+
+ case OPENED:
+ if( f->callbacks->down )
+ (*f->callbacks->down)(f);
+ f->state = STARTING;
+ break;
+
+ default:
+ FSMDEBUG(("%s: Down event in state %d!", PROTO_NAME(f), f->state));
+ }
+}
+
+
+/*
+ * fsm_open - Link is allowed to come up.
+ */
+void
+fsm_open(f)
+ fsm *f;
+{
+ switch( f->state ){
+ case INITIAL:
+ f->state = STARTING;
+ if( f->callbacks->starting )
+ (*f->callbacks->starting)(f);
+ break;
+
+ case CLOSED:
+ if( f->flags & OPT_SILENT )
+ f->state = STOPPED;
+ else {
+ /* Send an initial configure-request */
+ fsm_sconfreq(f, 0);
+ f->state = REQSENT;
+ }
+ break;
+
+ case CLOSING:
+ f->state = STOPPING;
+ /* fall through */
+ case STOPPED:
+ case OPENED:
+ if( f->flags & OPT_RESTART ){
+ fsm_lowerdown(f);
+ fsm_lowerup(f);
+ }
+ break;
+ }
+}
+
+
+/*
+ * fsm_close - Start closing connection.
+ *
+ * Cancel timeouts and either initiate close or possibly go directly to
+ * the CLOSED state.
+ */
+void
+fsm_close(f, reason)
+ fsm *f;
+ char *reason;
+{
+ f->term_reason = reason;
+ f->term_reason_len = (reason == NULL? 0: strlen(reason));
+ switch( f->state ){
+ case STARTING:
+ f->state = INITIAL;
+ break;
+ case STOPPED:
+ f->state = CLOSED;
+ break;
+ case STOPPING:
+ f->state = CLOSING;
+ break;
+
+ case REQSENT:
+ case ACKRCVD:
+ case ACKSENT:
+ case OPENED:
+ if( f->state != OPENED )
+ UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
+ else if( f->callbacks->down )
+ (*f->callbacks->down)(f); /* Inform upper layers we're down */
+
+ /* Init restart counter, send Terminate-Request */
+ f->retransmits = f->maxtermtransmits;
+ fsm_sdata(f, TERMREQ, f->reqid = ++f->id,
+ (u_char *) f->term_reason, f->term_reason_len);
+ TIMEOUT(fsm_timeout, f, f->timeouttime);
+ --f->retransmits;
+
+ f->state = CLOSING;
+ break;
+ }
+}
+
+
+/*
+ * fsm_timeout - Timeout expired.
+ */
+static void
+fsm_timeout(arg)
+ void *arg;
+{
+ fsm *f = (fsm *) arg;
+
+ switch (f->state) {
+ case CLOSING:
+ case STOPPING:
+ if( f->retransmits <= 0 ){
+ /*
+ * We've waited for an ack long enough. Peer probably heard us.
+ */
+ f->state = (f->state == CLOSING)? CLOSED: STOPPED;
+ if( f->callbacks->finished )
+ (*f->callbacks->finished)(f);
+ } else {
+ /* Send Terminate-Request */
+ fsm_sdata(f, TERMREQ, f->reqid = ++f->id,
+ (u_char *) f->term_reason, f->term_reason_len);
+ TIMEOUT(fsm_timeout, f, f->timeouttime);
+ --f->retransmits;
+ }
+ break;
+
+ case REQSENT:
+ case ACKRCVD:
+ case ACKSENT:
+ if (f->retransmits <= 0) {
+ warn("%s: timeout sending Config-Requests\n", PROTO_NAME(f));
+ f->state = STOPPED;
+ if( (f->flags & OPT_PASSIVE) == 0 && f->callbacks->finished )
+ (*f->callbacks->finished)(f);
+
+ } else {
+ /* Retransmit the configure-request */
+ if (f->callbacks->retransmit)
+ (*f->callbacks->retransmit)(f);
+ fsm_sconfreq(f, 1); /* Re-send Configure-Request */
+ if( f->state == ACKRCVD )
+ f->state = REQSENT;
+ }
+ break;
+
+ default:
+ FSMDEBUG(("%s: Timeout event in state %d!", PROTO_NAME(f), f->state));
+ }
+}
+
+
+/*
+ * fsm_input - Input packet.
+ */
+void
+fsm_input(f, inpacket, l)
+ fsm *f;
+ u_char *inpacket;
+ int l;
+{
+ u_char *inp;
+ u_char code, id;
+ int len;
+
+ /*
+ * Parse header (code, id and length).
+ * If packet too short, drop it.
+ */
+ inp = inpacket;
+ if (l < HEADERLEN) {
+ FSMDEBUG(("fsm_input(%x): Rcvd short header.", f->protocol));
+ return;
+ }
+ GETCHAR(code, inp);
+ GETCHAR(id, inp);
+ GETSHORT(len, inp);
+ if (len < HEADERLEN) {
+ FSMDEBUG(("fsm_input(%x): Rcvd illegal length.", f->protocol));
+ return;
+ }
+ if (len > l) {
+ FSMDEBUG(("fsm_input(%x): Rcvd short packet.", f->protocol));
+ return;
+ }
+ len -= HEADERLEN; /* subtract header length */
+
+ if( f->state == INITIAL || f->state == STARTING ){
+ FSMDEBUG(("fsm_input(%x): Rcvd packet in state %d.",
+ f->protocol, f->state));
+ return;
+ }
+
+ /*
+ * Action depends on code.
+ */
+ switch (code) {
+ case CONFREQ:
+ fsm_rconfreq(f, id, inp, len);
+ break;
+
+ case CONFACK:
+ fsm_rconfack(f, id, inp, len);
+ break;
+
+ case CONFNAK:
+ case CONFREJ:
+ fsm_rconfnakrej(f, code, id, inp, len);
+ break;
+
+ case TERMREQ:
+ fsm_rtermreq(f, id, inp, len);
+ break;
+
+ case TERMACK:
+ fsm_rtermack(f);
+ break;
+
+ case CODEREJ:
+ fsm_rcoderej(f, inp, len);
+ break;
+
+ default:
+ if( !f->callbacks->extcode
+ || !(*f->callbacks->extcode)(f, code, id, inp, len) )
+ fsm_sdata(f, CODEREJ, ++f->id, inpacket, len + HEADERLEN);
+ break;
+ }
+}
+
+
+/*
+ * fsm_rconfreq - Receive Configure-Request.
+ */
+static void
+fsm_rconfreq(f, id, inp, len)
+ fsm *f;
+ u_char id;
+ u_char *inp;
+ int len;
+{
+ int code, reject_if_disagree;
+
+ switch( f->state ){
+ case CLOSED:
+ /* Go away, we're closed */
+ fsm_sdata(f, TERMACK, id, NULL, 0);
+ return;
+ case CLOSING:
+ case STOPPING:
+ return;
+
+ case OPENED:
+ /* Go down and restart negotiation */
+ if( f->callbacks->down )
+ (*f->callbacks->down)(f); /* Inform upper layers */
+ fsm_sconfreq(f, 0); /* Send initial Configure-Request */
+ break;
+
+ case STOPPED:
+ /* Negotiation started by our peer */
+ fsm_sconfreq(f, 0); /* Send initial Configure-Request */
+ f->state = REQSENT;
+ break;
+ }
+
+ /*
+ * Pass the requested configuration options
+ * to protocol-specific code for checking.
+ */
+ if (f->callbacks->reqci){ /* Check CI */
+ reject_if_disagree = (f->nakloops >= f->maxnakloops);
+ code = (*f->callbacks->reqci)(f, inp, &len, reject_if_disagree);
+ } else if (len)
+ code = CONFREJ; /* Reject all CI */
+ else
+ code = CONFACK;
+
+ /* send the Ack, Nak or Rej to the peer */
+ fsm_sdata(f, code, id, inp, len);
+
+ if (code == CONFACK) {
+ if (f->state == ACKRCVD) {
+ UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
+ f->state = OPENED;
+ if (f->callbacks->up)
+ (*f->callbacks->up)(f); /* Inform upper layers */
+ } else
+ f->state = ACKSENT;
+ f->nakloops = 0;
+
+ } else {
+ /* we sent CONFACK or CONFREJ */
+ if (f->state != ACKRCVD)
+ f->state = REQSENT;
+ if( code == CONFNAK )
+ ++f->nakloops;
+ }
+}
+
+
+/*
+ * fsm_rconfack - Receive Configure-Ack.
+ */
+static void
+fsm_rconfack(f, id, inp, len)
+ fsm *f;
+ int id;
+ u_char *inp;
+ int len;
+{
+ if (id != f->reqid || f->seen_ack) /* Expected id? */
+ return; /* Nope, toss... */
+ if( !(f->callbacks->ackci? (*f->callbacks->ackci)(f, inp, len):
+ (len == 0)) ){
+ /* Ack is bad - ignore it */
+ error("Received bad configure-ack: %P", inp, len);
+ return;
+ }
+ f->seen_ack = 1;
+
+ switch (f->state) {
+ case CLOSED:
+ case STOPPED:
+ fsm_sdata(f, TERMACK, id, NULL, 0);
+ break;
+
+ case REQSENT:
+ f->state = ACKRCVD;
+ f->retransmits = f->maxconfreqtransmits;
+ break;
+
+ case ACKRCVD:
+ /* Huh? an extra valid Ack? oh well... */
+ UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
+ fsm_sconfreq(f, 0);
+ f->state = REQSENT;
+ break;
+
+ case ACKSENT:
+ UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
+ f->state = OPENED;
+ f->retransmits = f->maxconfreqtransmits;
+ if (f->callbacks->up)
+ (*f->callbacks->up)(f); /* Inform upper layers */
+ break;
+
+ case OPENED:
+ /* Go down and restart negotiation */
+ if (f->callbacks->down)
+ (*f->callbacks->down)(f); /* Inform upper layers */
+ fsm_sconfreq(f, 0); /* Send initial Configure-Request */
+ f->state = REQSENT;
+ break;
+ }
+}
+
+
+/*
+ * fsm_rconfnakrej - Receive Configure-Nak or Configure-Reject.
+ */
+static void
+fsm_rconfnakrej(f, code, id, inp, len)
+ fsm *f;
+ int code, id;
+ u_char *inp;
+ int len;
+{
+ int (*proc) __P((fsm *, u_char *, int));
+ int ret;
+
+ if (id != f->reqid || f->seen_ack) /* Expected id? */
+ return; /* Nope, toss... */
+ proc = (code == CONFNAK)? f->callbacks->nakci: f->callbacks->rejci;
+ if (!proc || !(ret = proc(f, inp, len))) {
+ /* Nak/reject is bad - ignore it */
+ error("Received bad configure-nak/rej: %P", inp, len);
+ return;
+ }
+ f->seen_ack = 1;
+
+ switch (f->state) {
+ case CLOSED:
+ case STOPPED:
+ fsm_sdata(f, TERMACK, id, NULL, 0);
+ break;
+
+ case REQSENT:
+ case ACKSENT:
+ /* They didn't agree to what we wanted - try another request */
+ UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
+ if (ret < 0)
+ f->state = STOPPED; /* kludge for stopping CCP */
+ else
+ fsm_sconfreq(f, 0); /* Send Configure-Request */
+ break;
+
+ case ACKRCVD:
+ /* Got a Nak/reject when we had already had an Ack?? oh well... */
+ UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
+ fsm_sconfreq(f, 0);
+ f->state = REQSENT;
+ break;
+
+ case OPENED:
+ /* Go down and restart negotiation */
+ if (f->callbacks->down)
+ (*f->callbacks->down)(f); /* Inform upper layers */
+ fsm_sconfreq(f, 0); /* Send initial Configure-Request */
+ f->state = REQSENT;
+ break;
+ }
+}
+
+
+/*
+ * fsm_rtermreq - Receive Terminate-Req.
+ */
+static void
+fsm_rtermreq(f, id, p, len)
+ fsm *f;
+ int id;
+ u_char *p;
+ int len;
+{
+ switch (f->state) {
+ case ACKRCVD:
+ case ACKSENT:
+ f->state = REQSENT; /* Start over but keep trying */
+ break;
+
+ case OPENED:
+ if (len > 0) {
+ info("%s terminated by peer (%0.*v)", PROTO_NAME(f), len, p);
+ } else
+ info("%s terminated by peer", PROTO_NAME(f));
+ if (f->callbacks->down)
+ (*f->callbacks->down)(f); /* Inform upper layers */
+ f->retransmits = 0;
+ f->state = STOPPING;
+ TIMEOUT(fsm_timeout, f, f->timeouttime);
+ break;
+ }
+
+ fsm_sdata(f, TERMACK, id, NULL, 0);
+}
+
+
+/*
+ * fsm_rtermack - Receive Terminate-Ack.
+ */
+static void
+fsm_rtermack(f)
+ fsm *f;
+{
+ switch (f->state) {
+ case CLOSING:
+ UNTIMEOUT(fsm_timeout, f);
+ f->state = CLOSED;
+ if( f->callbacks->finished )
+ (*f->callbacks->finished)(f);
+ break;
+ case STOPPING:
+ UNTIMEOUT(fsm_timeout, f);
+ f->state = STOPPED;
+ if( f->callbacks->finished )
+ (*f->callbacks->finished)(f);
+ break;
+
+ case ACKRCVD:
+ f->state = REQSENT;
+ break;
+
+ case OPENED:
+ if (f->callbacks->down)
+ (*f->callbacks->down)(f); /* Inform upper layers */
+ fsm_sconfreq(f, 0);
+ break;
+ }
+}
+
+
+/*
+ * fsm_rcoderej - Receive an Code-Reject.
+ */
+static void
+fsm_rcoderej(f, inp, len)
+ fsm *f;
+ u_char *inp;
+ int len;
+{
+ u_char code, id;
+
+ if (len < HEADERLEN) {
+ FSMDEBUG(("fsm_rcoderej: Rcvd short Code-Reject packet!"));
+ return;
+ }
+ GETCHAR(code, inp);
+ GETCHAR(id, inp);
+ warn("%s: Rcvd Code-Reject for code %d, id %d", PROTO_NAME(f), code, id);
+
+ if( f->state == ACKRCVD )
+ f->state = REQSENT;
+}
+
+
+/*
+ * fsm_protreject - Peer doesn't speak this protocol.
+ *
+ * Treat this as a catastrophic error (RXJ-).
+ */
+void
+fsm_protreject(f)
+ fsm *f;
+{
+ switch( f->state ){
+ case CLOSING:
+ UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
+ /* fall through */
+ case CLOSED:
+ f->state = CLOSED;
+ if( f->callbacks->finished )
+ (*f->callbacks->finished)(f);
+ break;
+
+ case STOPPING:
+ case REQSENT:
+ case ACKRCVD:
+ case ACKSENT:
+ UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
+ /* fall through */
+ case STOPPED:
+ f->state = STOPPED;
+ if( f->callbacks->finished )
+ (*f->callbacks->finished)(f);
+ break;
+
+ case OPENED:
+ if( f->callbacks->down )
+ (*f->callbacks->down)(f);
+
+ /* Init restart counter, send Terminate-Request */
+ f->retransmits = f->maxtermtransmits;
+ fsm_sdata(f, TERMREQ, f->reqid = ++f->id,
+ (u_char *) f->term_reason, f->term_reason_len);
+ TIMEOUT(fsm_timeout, f, f->timeouttime);
+ --f->retransmits;
+
+ f->state = STOPPING;
+ break;
+
+ default:
+ FSMDEBUG(("%s: Protocol-reject event in state %d!",
+ PROTO_NAME(f), f->state));
+ }
+}
+
+
+/*
+ * fsm_sconfreq - Send a Configure-Request.
+ */
+static void
+fsm_sconfreq(f, retransmit)
+ fsm *f;
+ int retransmit;
+{
+ u_char *outp;
+ int cilen;
+
+ if( f->state != REQSENT && f->state != ACKRCVD && f->state != ACKSENT ){
+ /* Not currently negotiating - reset options */
+ if( f->callbacks->resetci )
+ (*f->callbacks->resetci)(f);
+ f->nakloops = 0;
+ }
+
+ if( !retransmit ){
+ /* New request - reset retransmission counter, use new ID */
+ f->retransmits = f->maxconfreqtransmits;
+ f->reqid = ++f->id;
+ }
+
+ f->seen_ack = 0;
+
+ /*
+ * Make up the request packet
+ */
+ outp = outpacket_buf + PPP_HDRLEN + HEADERLEN;
+ if( f->callbacks->cilen && f->callbacks->addci ){
+ cilen = (*f->callbacks->cilen)(f);
+ if( cilen > peer_mru[f->unit] - HEADERLEN )
+ cilen = peer_mru[f->unit] - HEADERLEN;
+ if (f->callbacks->addci)
+ (*f->callbacks->addci)(f, outp, &cilen);
+ } else
+ cilen = 0;
+
+ /* send the request to our peer */
+ fsm_sdata(f, CONFREQ, f->reqid, outp, cilen);
+
+ /* start the retransmit timer */
+ --f->retransmits;
+ TIMEOUT(fsm_timeout, f, f->timeouttime);
+}
+
+
+/*
+ * fsm_sdata - Send some data.
+ *
+ * Used for all packets sent to our peer by this module.
+ */
+void
+fsm_sdata(f, code, id, data, datalen)
+ fsm *f;
+ u_char code, id;
+ u_char *data;
+ int datalen;
+{
+ u_char *outp;
+ int outlen;
+
+ /* Adjust length to be smaller than MTU */
+ outp = outpacket_buf;
+ if (datalen > peer_mru[f->unit] - HEADERLEN)
+ datalen = peer_mru[f->unit] - HEADERLEN;
+ if (datalen && data != outp + PPP_HDRLEN + HEADERLEN)
+ BCOPY(data, outp + PPP_HDRLEN + HEADERLEN, datalen);
+ outlen = datalen + HEADERLEN;
+ MAKEHEADER(outp, f->protocol);
+ PUTCHAR(code, outp);
+ PUTCHAR(id, outp);
+ PUTSHORT(outlen, outp);
+ output(f->unit, outpacket_buf, outlen + PPP_HDRLEN);
+}
diff --git a/mdk-stage1/ppp/pppd/fsm.h b/mdk-stage1/ppp/pppd/fsm.h
new file mode 100644
index 000000000..7f20202d8
--- /dev/null
+++ b/mdk-stage1/ppp/pppd/fsm.h
@@ -0,0 +1,144 @@
+/*
+ * fsm.h - {Link, IP} Control Protocol Finite State Machine definitions.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id: fsm.h 195720 2001-06-11 11:44:34Z gc $
+ */
+
+/*
+ * Packet header = Code, id, length.
+ */
+#define HEADERLEN 4
+
+
+/*
+ * CP (LCP, IPCP, etc.) codes.
+ */
+#define CONFREQ 1 /* Configuration Request */
+#define CONFACK 2 /* Configuration Ack */
+#define CONFNAK 3 /* Configuration Nak */
+#define CONFREJ 4 /* Configuration Reject */
+#define TERMREQ 5 /* Termination Request */
+#define TERMACK 6 /* Termination Ack */
+#define CODEREJ 7 /* Code Reject */
+
+
+/*
+ * Each FSM is described by an fsm structure and fsm callbacks.
+ */
+typedef struct fsm {
+ int unit; /* Interface unit number */
+ int protocol; /* Data Link Layer Protocol field value */
+ int state; /* State */
+ int flags; /* Contains option bits */
+ u_char id; /* Current id */
+ u_char reqid; /* Current request id */
+ u_char seen_ack; /* Have received valid Ack/Nak/Rej to Req */
+ int timeouttime; /* Timeout time in milliseconds */
+ int maxconfreqtransmits; /* Maximum Configure-Request transmissions */
+ int retransmits; /* Number of retransmissions left */
+ int maxtermtransmits; /* Maximum Terminate-Request transmissions */
+ int nakloops; /* Number of nak loops since last ack */
+ int maxnakloops; /* Maximum number of nak loops tolerated */
+ struct fsm_callbacks *callbacks; /* Callback routines */
+ char *term_reason; /* Reason for closing protocol */
+ int term_reason_len; /* Length of term_reason */
+} fsm;
+
+
+typedef struct fsm_callbacks {
+ void (*resetci) /* Reset our Configuration Information */
+ __P((fsm *));
+ int (*cilen) /* Length of our Configuration Information */
+ __P((fsm *));
+ void (*addci) /* Add our Configuration Information */
+ __P((fsm *, u_char *, int *));
+ int (*ackci) /* ACK our Configuration Information */
+ __P((fsm *, u_char *, int));
+ int (*nakci) /* NAK our Configuration Information */
+ __P((fsm *, u_char *, int));
+ int (*rejci) /* Reject our Configuration Information */
+ __P((fsm *, u_char *, int));
+ int (*reqci) /* Request peer's Configuration Information */
+ __P((fsm *, u_char *, int *, int));
+ void (*up) /* Called when fsm reaches OPENED state */
+ __P((fsm *));
+ void (*down) /* Called when fsm leaves OPENED state */
+ __P((fsm *));
+ void (*starting) /* Called when we want the lower layer */
+ __P((fsm *));
+ void (*finished) /* Called when we don't want the lower layer */
+ __P((fsm *));
+ void (*protreject) /* Called when Protocol-Reject received */
+ __P((int));
+ void (*retransmit) /* Retransmission is necessary */
+ __P((fsm *));
+ int (*extcode) /* Called when unknown code received */
+ __P((fsm *, int, int, u_char *, int));
+ char *proto_name; /* String name for protocol (for messages) */
+} fsm_callbacks;
+
+
+/*
+ * Link states.
+ */
+#define INITIAL 0 /* Down, hasn't been opened */
+#define STARTING 1 /* Down, been opened */
+#define CLOSED 2 /* Up, hasn't been opened */
+#define STOPPED 3 /* Open, waiting for down event */
+#define CLOSING 4 /* Terminating the connection, not open */
+#define STOPPING 5 /* Terminating, but open */
+#define REQSENT 6 /* We've sent a Config Request */
+#define ACKRCVD 7 /* We've received a Config Ack */
+#define ACKSENT 8 /* We've sent a Config Ack */
+#define OPENED 9 /* Connection available */
+
+
+/*
+ * Flags - indicate options controlling FSM operation
+ */
+#define OPT_PASSIVE 1 /* Don't die if we don't get a response */
+#define OPT_RESTART 2 /* Treat 2nd OPEN as DOWN, UP */
+#define OPT_SILENT 4 /* Wait for peer to speak first */
+
+
+/*
+ * Timeouts.
+ */
+#define DEFTIMEOUT 3 /* Timeout time in seconds */
+#define DEFMAXTERMREQS 2 /* Maximum Terminate-Request transmissions */
+#define DEFMAXCONFREQS 10 /* Maximum Configure-Request transmissions */
+#define DEFMAXNAKLOOPS 5 /* Maximum number of nak loops */
+
+
+/*
+ * Prototypes
+ */
+void fsm_init __P((fsm *));
+void fsm_lowerup __P((fsm *));
+void fsm_lowerdown __P((fsm *));
+void fsm_open __P((fsm *));
+void fsm_close __P((fsm *, char *));
+void fsm_input __P((fsm *, u_char *, int));
+void fsm_protreject __P((fsm *));
+void fsm_sdata __P((fsm *, int, int, u_char *, int));
+
+
+/*
+ * Variables
+ */
+extern int peer_mru[]; /* currently negotiated peer MRU (per unit) */
diff --git a/mdk-stage1/ppp/pppd/ipcp.c b/mdk-stage1/ppp/pppd/ipcp.c
new file mode 100644
index 000000000..63dd2540a
--- /dev/null
+++ b/mdk-stage1/ppp/pppd/ipcp.c
@@ -0,0 +1,2054 @@
+/*
+ * ipcp.c - PPP IP Control Protocol.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#define RCSID "$Id: ipcp.c 198597 2002-05-13 15:34:06Z gc $"
+
+/*
+ * TODO:
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <netdb.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include "pppd.h"
+#include "fsm.h"
+#include "ipcp.h"
+#include "pathnames.h"
+
+static const char rcsid[] = RCSID;
+
+/* global vars */
+ipcp_options ipcp_wantoptions[NUM_PPP]; /* Options that we want to request */
+ipcp_options ipcp_gotoptions[NUM_PPP]; /* Options that peer ack'd */
+ipcp_options ipcp_allowoptions[NUM_PPP]; /* Options we allow peer to request */
+ipcp_options ipcp_hisoptions[NUM_PPP]; /* Options that we ack'd */
+
+u_int32_t netmask = 0; /* IP netmask to set on interface */
+
+bool disable_defaultip = 0; /* Don't use hostname for default IP adrs */
+
+/* Hook for a plugin to know when IP protocol has come up */
+void (*ip_up_hook) __P((void)) = NULL;
+
+/* Hook for a plugin to know when IP protocol has come down */
+void (*ip_down_hook) __P((void)) = NULL;
+
+/* Hook for a plugin to choose the remote IP address */
+void (*ip_choose_hook) __P((u_int32_t *)) = NULL;
+
+/* local vars */
+static int default_route_set[NUM_PPP]; /* Have set up a default route */
+static int proxy_arp_set[NUM_PPP]; /* Have created proxy arp entry */
+static bool usepeerdns; /* Ask peer for DNS addrs */
+static int ipcp_is_up; /* have called np_up() */
+static bool ask_for_local; /* request our address from peer */
+static char vj_value[8]; /* string form of vj option value */
+static char netmask_str[20]; /* string form of netmask value */
+
+/*
+ * Callbacks for fsm code. (CI = Configuration Information)
+ */
+static void ipcp_resetci __P((fsm *)); /* Reset our CI */
+static int ipcp_cilen __P((fsm *)); /* Return length of our CI */
+static void ipcp_addci __P((fsm *, u_char *, int *)); /* Add our CI */
+static int ipcp_ackci __P((fsm *, u_char *, int)); /* Peer ack'd our CI */
+static int ipcp_nakci __P((fsm *, u_char *, int)); /* Peer nak'd our CI */
+static int ipcp_rejci __P((fsm *, u_char *, int)); /* Peer rej'd our CI */
+static int ipcp_reqci __P((fsm *, u_char *, int *, int)); /* Rcv CI */
+static void ipcp_up __P((fsm *)); /* We're UP */
+static void ipcp_down __P((fsm *)); /* We're DOWN */
+static void ipcp_finished __P((fsm *)); /* Don't need lower layer */
+
+fsm ipcp_fsm[NUM_PPP]; /* IPCP fsm structure */
+
+static fsm_callbacks ipcp_callbacks = { /* IPCP callback routines */
+ ipcp_resetci, /* Reset our Configuration Information */
+ ipcp_cilen, /* Length of our Configuration Information */
+ ipcp_addci, /* Add our Configuration Information */
+ ipcp_ackci, /* ACK our Configuration Information */
+ ipcp_nakci, /* NAK our Configuration Information */
+ ipcp_rejci, /* Reject our Configuration Information */
+ ipcp_reqci, /* Request peer's Configuration Information */
+ ipcp_up, /* Called when fsm reaches OPENED state */
+ ipcp_down, /* Called when fsm leaves OPENED state */
+ NULL, /* Called when we want the lower layer up */
+ ipcp_finished, /* Called when we want the lower layer down */
+ NULL, /* Called when Protocol-Reject received */
+ NULL, /* Retransmission is necessary */
+ NULL, /* Called to handle protocol-specific codes */
+ "IPCP" /* String name of protocol */
+};
+
+/*
+ * Command-line options.
+ */
+static int setvjslots __P((char **));
+static int setdnsaddr __P((char **));
+static int setwinsaddr __P((char **));
+static int setnetmask __P((char **));
+static int setipaddr __P((char *, char **, int));
+static void printipaddr __P((option_t *, void (*)(void *, char *,...),void *));
+
+static option_t ipcp_option_list[] = {
+ { "noip", o_bool, &ipcp_protent.enabled_flag,
+ "Disable IP and IPCP" },
+ { "-ip", o_bool, &ipcp_protent.enabled_flag,
+ "Disable IP and IPCP", OPT_ALIAS },
+
+ { "novj", o_bool, &ipcp_wantoptions[0].neg_vj,
+ "Disable VJ compression", OPT_A2CLR, &ipcp_allowoptions[0].neg_vj },
+ { "-vj", o_bool, &ipcp_wantoptions[0].neg_vj,
+ "Disable VJ compression", OPT_ALIAS | OPT_A2CLR,
+ &ipcp_allowoptions[0].neg_vj },
+
+ { "novjccomp", o_bool, &ipcp_wantoptions[0].cflag,
+ "Disable VJ connection-ID compression", OPT_A2CLR,
+ &ipcp_allowoptions[0].cflag },
+ { "-vjccomp", o_bool, &ipcp_wantoptions[0].cflag,
+ "Disable VJ connection-ID compression", OPT_ALIAS | OPT_A2CLR,
+ &ipcp_allowoptions[0].cflag },
+
+ { "vj-max-slots", o_special, (void *)setvjslots,
+ "Set maximum VJ header slots",
+ OPT_PRIO | OPT_A2STRVAL | OPT_STATIC, vj_value },
+
+ { "ipcp-accept-local", o_bool, &ipcp_wantoptions[0].accept_local,
+ "Accept peer's address for us", 1 },
+ { "ipcp-accept-remote", o_bool, &ipcp_wantoptions[0].accept_remote,
+ "Accept peer's address for it", 1 },
+
+ { "ipparam", o_string, &ipparam,
+ "Set ip script parameter", OPT_PRIO },
+
+ { "noipdefault", o_bool, &disable_defaultip,
+ "Don't use name for default IP adrs", 1 },
+
+ { "ms-dns", 1, (void *)setdnsaddr,
+ "DNS address for the peer's use" },
+ { "ms-wins", 1, (void *)setwinsaddr,
+ "Nameserver for SMB over TCP/IP for peer" },
+
+ { "ipcp-restart", o_int, &ipcp_fsm[0].timeouttime,
+ "Set timeout for IPCP", OPT_PRIO },
+ { "ipcp-max-terminate", o_int, &ipcp_fsm[0].maxtermtransmits,
+ "Set max #xmits for term-reqs", OPT_PRIO },
+ { "ipcp-max-configure", o_int, &ipcp_fsm[0].maxconfreqtransmits,
+ "Set max #xmits for conf-reqs", OPT_PRIO },
+ { "ipcp-max-failure", o_int, &ipcp_fsm[0].maxnakloops,
+ "Set max #conf-naks for IPCP", OPT_PRIO },
+
+ { "defaultroute", o_bool, &ipcp_wantoptions[0].default_route,
+ "Add default route", OPT_ENABLE|1, &ipcp_allowoptions[0].default_route },
+ { "nodefaultroute", o_bool, &ipcp_allowoptions[0].default_route,
+ "disable defaultroute option", OPT_A2CLR,
+ &ipcp_wantoptions[0].default_route },
+ { "-defaultroute", o_bool, &ipcp_allowoptions[0].default_route,
+ "disable defaultroute option", OPT_ALIAS | OPT_A2CLR,
+ &ipcp_wantoptions[0].default_route },
+
+ { "proxyarp", o_bool, &ipcp_wantoptions[0].proxy_arp,
+ "Add proxy ARP entry", OPT_ENABLE|1, &ipcp_allowoptions[0].proxy_arp },
+ { "noproxyarp", o_bool, &ipcp_allowoptions[0].proxy_arp,
+ "disable proxyarp option", OPT_A2CLR,
+ &ipcp_wantoptions[0].proxy_arp },
+ { "-proxyarp", o_bool, &ipcp_allowoptions[0].proxy_arp,
+ "disable proxyarp option", OPT_ALIAS | OPT_A2CLR,
+ &ipcp_wantoptions[0].proxy_arp },
+
+ { "usepeerdns", o_bool, &usepeerdns,
+ "Ask peer for DNS address(es)", 1 },
+
+ { "netmask", o_special, (void *)setnetmask,
+ "set netmask", OPT_PRIO | OPT_A2STRVAL | OPT_STATIC, netmask_str },
+
+ { "IP addresses", o_wild, (void *) &setipaddr,
+ "set local and remote IP addresses",
+ OPT_NOARG | OPT_A2PRINTER, (void *) &printipaddr },
+
+ { NULL }
+};
+
+/*
+ * Protocol entry points from main code.
+ */
+static void ipcp_init __P((int));
+static void ipcp_open __P((int));
+static void ipcp_close __P((int, char *));
+static void ipcp_lowerup __P((int));
+static void ipcp_lowerdown __P((int));
+static void ipcp_input __P((int, u_char *, int));
+static void ipcp_protrej __P((int));
+static int ipcp_printpkt __P((u_char *, int,
+ void (*) __P((void *, char *, ...)), void *));
+static void ip_check_options __P((void));
+static int ip_demand_conf __P((int));
+static int ip_active_pkt __P((u_char *, int));
+static void create_resolv __P((u_int32_t, u_int32_t));
+
+struct protent ipcp_protent = {
+ PPP_IPCP,
+ ipcp_init,
+ ipcp_input,
+ ipcp_protrej,
+ ipcp_lowerup,
+ ipcp_lowerdown,
+ ipcp_open,
+ ipcp_close,
+ ipcp_printpkt,
+ NULL,
+ 1,
+ "IPCP",
+ "IP",
+ ipcp_option_list,
+ ip_check_options,
+ ip_demand_conf,
+ ip_active_pkt
+};
+
+static void ipcp_clear_addrs __P((int, u_int32_t, u_int32_t));
+static void ipcp_script __P((char *)); /* Run an up/down script */
+static void ipcp_script_done __P((void *));
+
+/*
+ * Lengths of configuration options.
+ */
+#define CILEN_VOID 2
+#define CILEN_COMPRESS 4 /* min length for compression protocol opt. */
+#define CILEN_VJ 6 /* length for RFC1332 Van-Jacobson opt. */
+#define CILEN_ADDR 6 /* new-style single address option */
+#define CILEN_ADDRS 10 /* old-style dual address option */
+
+
+#define CODENAME(x) ((x) == CONFACK ? "ACK" : \
+ (x) == CONFNAK ? "NAK" : "REJ")
+
+/*
+ * This state variable is used to ensure that we don't
+ * run an ipcp-up/down script while one is already running.
+ */
+static enum script_state {
+ s_down,
+ s_up,
+} ipcp_script_state;
+static pid_t ipcp_script_pid;
+
+/*
+ * Make a string representation of a network IP address.
+ */
+char *
+ip_ntoa(ipaddr)
+u_int32_t ipaddr;
+{
+ static char b[64];
+
+ slprintf(b, sizeof(b), "%I", ipaddr);
+ return b;
+}
+
+/*
+ * Option parsing.
+ */
+
+/*
+ * setvjslots - set maximum number of connection slots for VJ compression
+ */
+static int
+setvjslots(argv)
+ char **argv;
+{
+ int value;
+
+ if (!int_option(*argv, &value))
+ return 0;
+ if (value < 2 || value > 16) {
+ option_error("vj-max-slots value must be between 2 and 16");
+ return 0;
+ }
+ ipcp_wantoptions [0].maxslotindex =
+ ipcp_allowoptions[0].maxslotindex = value - 1;
+ slprintf(vj_value, sizeof(vj_value), "%d", value);
+ return 1;
+}
+
+/*
+ * setdnsaddr - set the dns address(es)
+ */
+static int
+setdnsaddr(argv)
+ char **argv;
+{
+ u_int32_t dns;
+ struct hostent *hp;
+
+ dns = inet_addr(*argv);
+ if (dns == (u_int32_t) -1) {
+ if ((hp = gethostbyname(*argv)) == NULL) {
+ option_error("invalid address parameter '%s' for ms-dns option",
+ *argv);
+ return 0;
+ }
+ dns = *(u_int32_t *)hp->h_addr;
+ }
+
+ /* We take the last 2 values given, the 2nd-last as the primary
+ and the last as the secondary. If only one is given it
+ becomes both primary and secondary. */
+ if (ipcp_allowoptions[0].dnsaddr[1] == 0)
+ ipcp_allowoptions[0].dnsaddr[0] = dns;
+ else
+ ipcp_allowoptions[0].dnsaddr[0] = ipcp_allowoptions[0].dnsaddr[1];
+
+ /* always set the secondary address value. */
+ ipcp_allowoptions[0].dnsaddr[1] = dns;
+
+ return (1);
+}
+
+/*
+ * setwinsaddr - set the wins address(es)
+ * This is primrarly used with the Samba package under UNIX or for pointing
+ * the caller to the existing WINS server on a Windows NT platform.
+ */
+static int
+setwinsaddr(argv)
+ char **argv;
+{
+ u_int32_t wins;
+ struct hostent *hp;
+
+ wins = inet_addr(*argv);
+ if (wins == (u_int32_t) -1) {
+ if ((hp = gethostbyname(*argv)) == NULL) {
+ option_error("invalid address parameter '%s' for ms-wins option",
+ *argv);
+ return 0;
+ }
+ wins = *(u_int32_t *)hp->h_addr;
+ }
+
+ /* We take the last 2 values given, the 2nd-last as the primary
+ and the last as the secondary. If only one is given it
+ becomes both primary and secondary. */
+ if (ipcp_allowoptions[0].winsaddr[1] == 0)
+ ipcp_allowoptions[0].winsaddr[0] = wins;
+ else
+ ipcp_allowoptions[0].winsaddr[0] = ipcp_allowoptions[0].winsaddr[1];
+
+ /* always set the secondary address value. */
+ ipcp_allowoptions[0].winsaddr[1] = wins;
+
+ return (1);
+}
+
+/*
+ * setipaddr - Set the IP address
+ * If doit is 0, the call is to check whether this option is
+ * potentially an IP address specification.
+ */
+static int
+setipaddr(arg, argv, doit)
+ char *arg;
+ char **argv;
+ int doit;
+{
+ struct hostent *hp;
+ char *colon;
+ u_int32_t local, remote;
+ ipcp_options *wo = &ipcp_wantoptions[0];
+ static int prio_local = 0, prio_remote = 0;
+
+ /*
+ * IP address pair separated by ":".
+ */
+ if ((colon = strchr(arg, ':')) == NULL)
+ return 0;
+ if (!doit)
+ return 1;
+
+ /*
+ * If colon first character, then no local addr.
+ */
+ if (colon != arg && option_priority >= prio_local) {
+ *colon = '\0';
+ if ((local = inet_addr(arg)) == (u_int32_t) -1) {
+ if ((hp = gethostbyname(arg)) == NULL) {
+ option_error("unknown host: %s", arg);
+ return 0;
+ }
+ local = *(u_int32_t *)hp->h_addr;
+ }
+ if (bad_ip_adrs(local)) {
+ option_error("bad local IP address %s", ip_ntoa(local));
+ return 0;
+ }
+ if (local != 0)
+ wo->ouraddr = local;
+ *colon = ':';
+ prio_local = option_priority;
+ }
+
+ /*
+ * If colon last character, then no remote addr.
+ */
+ if (*++colon != '\0' && option_priority >= prio_remote) {
+ if ((remote = inet_addr(colon)) == (u_int32_t) -1) {
+ if ((hp = gethostbyname(colon)) == NULL) {
+ option_error("unknown host: %s", colon);
+ return 0;
+ }
+ remote = *(u_int32_t *)hp->h_addr;
+ if (remote_name[0] == 0)
+ strlcpy(remote_name, colon, sizeof(remote_name));
+ }
+ if (bad_ip_adrs(remote)) {
+ option_error("bad remote IP address %s", ip_ntoa(remote));
+ return 0;
+ }
+ if (remote != 0)
+ wo->hisaddr = remote;
+ prio_remote = option_priority;
+ }
+
+ return 1;
+}
+
+static void
+printipaddr(opt, printer, arg)
+ option_t *opt;
+ void (*printer) __P((void *, char *, ...));
+ void *arg;
+{
+ ipcp_options *wo = &ipcp_wantoptions[0];
+
+ if (wo->ouraddr != 0)
+ printer(arg, "%I", wo->ouraddr);
+ printer(arg, ":");
+ if (wo->hisaddr != 0)
+ printer(arg, "%I", wo->hisaddr);
+}
+
+/*
+ * setnetmask - set the netmask to be used on the interface.
+ */
+static int
+setnetmask(argv)
+ char **argv;
+{
+ u_int32_t mask;
+ int n;
+ char *p;
+
+ /*
+ * Unfortunately, if we use inet_addr, we can't tell whether
+ * a result of all 1s is an error or a valid 255.255.255.255.
+ */
+ p = *argv;
+ n = parse_dotted_ip(p, &mask);
+
+ mask = htonl(mask);
+
+ if (n == 0 || p[n] != 0 || (netmask & ~mask) != 0) {
+ option_error("invalid netmask value '%s'", *argv);
+ return 0;
+ }
+
+ netmask = mask;
+ slprintf(netmask_str, sizeof(netmask_str), "%I", mask);
+
+ return (1);
+}
+
+int
+parse_dotted_ip(p, vp)
+ char *p;
+ u_int32_t *vp;
+{
+ int n;
+ u_int32_t v, b;
+ char *endp, *p0 = p;
+
+ v = 0;
+ for (n = 3;; --n) {
+ b = strtoul(p, &endp, 0);
+ if (endp == p)
+ return 0;
+ if (b > 255) {
+ if (n < 3)
+ return 0;
+ /* accept e.g. 0xffffff00 */
+ *vp = b;
+ return endp - p0;
+ }
+ v |= b << (n * 8);
+ p = endp;
+ if (n == 0)
+ break;
+ if (*p != '.')
+ return 0;
+ ++p;
+ }
+ *vp = v;
+ return p - p0;
+}
+
+
+/*
+ * ipcp_init - Initialize IPCP.
+ */
+static void
+ipcp_init(unit)
+ int unit;
+{
+ fsm *f = &ipcp_fsm[unit];
+ ipcp_options *wo = &ipcp_wantoptions[unit];
+ ipcp_options *ao = &ipcp_allowoptions[unit];
+
+ f->unit = unit;
+ f->protocol = PPP_IPCP;
+ f->callbacks = &ipcp_callbacks;
+ fsm_init(&ipcp_fsm[unit]);
+
+ memset(wo, 0, sizeof(*wo));
+ memset(ao, 0, sizeof(*ao));
+
+ wo->neg_addr = 1;
+ wo->neg_vj = 1;
+ wo->vj_protocol = IPCP_VJ_COMP;
+ wo->maxslotindex = MAX_STATES - 1; /* really max index */
+ wo->cflag = 1;
+
+
+ /* max slots and slot-id compression are currently hardwired in */
+ /* ppp_if.c to 16 and 1, this needs to be changed (among other */
+ /* things) gmc */
+
+ ao->neg_addr = 1;
+ ao->neg_vj = 1;
+ ao->maxslotindex = MAX_STATES - 1;
+ ao->cflag = 1;
+
+ /*
+ * XXX These control whether the user may use the proxyarp
+ * and defaultroute options.
+ */
+ ao->proxy_arp = 1;
+ ao->default_route = 1;
+}
+
+
+/*
+ * ipcp_open - IPCP is allowed to come up.
+ */
+static void
+ipcp_open(unit)
+ int unit;
+{
+ fsm_open(&ipcp_fsm[unit]);
+}
+
+
+/*
+ * ipcp_close - Take IPCP down.
+ */
+static void
+ipcp_close(unit, reason)
+ int unit;
+ char *reason;
+{
+ fsm_close(&ipcp_fsm[unit], reason);
+}
+
+
+/*
+ * ipcp_lowerup - The lower layer is up.
+ */
+static void
+ipcp_lowerup(unit)
+ int unit;
+{
+ fsm_lowerup(&ipcp_fsm[unit]);
+}
+
+
+/*
+ * ipcp_lowerdown - The lower layer is down.
+ */
+static void
+ipcp_lowerdown(unit)
+ int unit;
+{
+ fsm_lowerdown(&ipcp_fsm[unit]);
+}
+
+
+/*
+ * ipcp_input - Input IPCP packet.
+ */
+static void
+ipcp_input(unit, p, len)
+ int unit;
+ u_char *p;
+ int len;
+{
+ fsm_input(&ipcp_fsm[unit], p, len);
+}
+
+
+/*
+ * ipcp_protrej - A Protocol-Reject was received for IPCP.
+ *
+ * Pretend the lower layer went down, so we shut up.
+ */
+static void
+ipcp_protrej(unit)
+ int unit;
+{
+ fsm_lowerdown(&ipcp_fsm[unit]);
+}
+
+
+/*
+ * ipcp_resetci - Reset our CI.
+ * Called by fsm_sconfreq, Send Configure Request.
+ */
+static void
+ipcp_resetci(f)
+ fsm *f;
+{
+ ipcp_options *wo = &ipcp_wantoptions[f->unit];
+ ipcp_options *go = &ipcp_gotoptions[f->unit];
+
+ wo->req_addr = wo->neg_addr && ipcp_allowoptions[f->unit].neg_addr;
+ if (wo->ouraddr == 0)
+ wo->accept_local = 1;
+ if (wo->hisaddr == 0)
+ wo->accept_remote = 1;
+ wo->req_dns1 = usepeerdns; /* Request DNS addresses from the peer */
+ wo->req_dns2 = usepeerdns;
+ *go = *wo;
+ if (!ask_for_local)
+ go->ouraddr = 0;
+ if (ip_choose_hook)
+ ip_choose_hook(&wo->hisaddr);
+}
+
+
+/*
+ * ipcp_cilen - Return length of our CI.
+ * Called by fsm_sconfreq, Send Configure Request.
+ */
+static int
+ipcp_cilen(f)
+ fsm *f;
+{
+ ipcp_options *go = &ipcp_gotoptions[f->unit];
+ ipcp_options *wo = &ipcp_wantoptions[f->unit];
+ ipcp_options *ho = &ipcp_hisoptions[f->unit];
+
+#define LENCIVJ(neg, old) (neg ? (old? CILEN_COMPRESS : CILEN_VJ) : 0)
+#define LENCIADDR(neg, old) (neg ? (old? CILEN_ADDRS : CILEN_ADDR) : 0)
+#define LENCIDNS(neg) (neg ? (CILEN_ADDR) : 0)
+
+ /*
+ * First see if we want to change our options to the old
+ * forms because we have received old forms from the peer.
+ */
+ if (wo->neg_addr && !go->neg_addr && !go->old_addrs) {
+ /* use the old style of address negotiation */
+ go->neg_addr = 1;
+ go->old_addrs = 1;
+ }
+ if (wo->neg_vj && !go->neg_vj && !go->old_vj) {
+ /* try an older style of VJ negotiation */
+ /* use the old style only if the peer did */
+ if (ho->neg_vj && ho->old_vj) {
+ go->neg_vj = 1;
+ go->old_vj = 1;
+ go->vj_protocol = ho->vj_protocol;
+ }
+ }
+
+ return (LENCIADDR(go->neg_addr, go->old_addrs) +
+ LENCIVJ(go->neg_vj, go->old_vj) +
+ LENCIDNS(go->req_dns1) +
+ LENCIDNS(go->req_dns2)) ;
+}
+
+
+/*
+ * ipcp_addci - Add our desired CIs to a packet.
+ * Called by fsm_sconfreq, Send Configure Request.
+ */
+static void
+ipcp_addci(f, ucp, lenp)
+ fsm *f;
+ u_char *ucp;
+ int *lenp;
+{
+ ipcp_options *go = &ipcp_gotoptions[f->unit];
+ int len = *lenp;
+
+#define ADDCIVJ(opt, neg, val, old, maxslotindex, cflag) \
+ if (neg) { \
+ int vjlen = old? CILEN_COMPRESS : CILEN_VJ; \
+ if (len >= vjlen) { \
+ PUTCHAR(opt, ucp); \
+ PUTCHAR(vjlen, ucp); \
+ PUTSHORT(val, ucp); \
+ if (!old) { \
+ PUTCHAR(maxslotindex, ucp); \
+ PUTCHAR(cflag, ucp); \
+ } \
+ len -= vjlen; \
+ } else \
+ neg = 0; \
+ }
+
+#define ADDCIADDR(opt, neg, old, val1, val2) \
+ if (neg) { \
+ int addrlen = (old? CILEN_ADDRS: CILEN_ADDR); \
+ if (len >= addrlen) { \
+ u_int32_t l; \
+ PUTCHAR(opt, ucp); \
+ PUTCHAR(addrlen, ucp); \
+ l = ntohl(val1); \
+ PUTLONG(l, ucp); \
+ if (old) { \
+ l = ntohl(val2); \
+ PUTLONG(l, ucp); \
+ } \
+ len -= addrlen; \
+ } else \
+ neg = 0; \
+ }
+
+#define ADDCIDNS(opt, neg, addr) \
+ if (neg) { \
+ if (len >= CILEN_ADDR) { \
+ u_int32_t l; \
+ PUTCHAR(opt, ucp); \
+ PUTCHAR(CILEN_ADDR, ucp); \
+ l = ntohl(addr); \
+ PUTLONG(l, ucp); \
+ len -= CILEN_ADDR; \
+ } else \
+ neg = 0; \
+ }
+
+ ADDCIADDR((go->old_addrs? CI_ADDRS: CI_ADDR), go->neg_addr,
+ go->old_addrs, go->ouraddr, go->hisaddr);
+
+ ADDCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol, go->old_vj,
+ go->maxslotindex, go->cflag);
+
+ ADDCIDNS(CI_MS_DNS1, go->req_dns1, go->dnsaddr[0]);
+
+ ADDCIDNS(CI_MS_DNS2, go->req_dns2, go->dnsaddr[1]);
+
+ *lenp -= len;
+}
+
+
+/*
+ * ipcp_ackci - Ack our CIs.
+ * Called by fsm_rconfack, Receive Configure ACK.
+ *
+ * Returns:
+ * 0 - Ack was bad.
+ * 1 - Ack was good.
+ */
+static int
+ipcp_ackci(f, p, len)
+ fsm *f;
+ u_char *p;
+ int len;
+{
+ ipcp_options *go = &ipcp_gotoptions[f->unit];
+ u_short cilen, citype, cishort;
+ u_int32_t cilong;
+ u_char cimaxslotindex, cicflag;
+
+ /*
+ * CIs must be in exactly the same order that we sent...
+ * Check packet length and CI length at each step.
+ * If we find any deviations, then this packet is bad.
+ */
+
+#define ACKCIVJ(opt, neg, val, old, maxslotindex, cflag) \
+ if (neg) { \
+ int vjlen = old? CILEN_COMPRESS : CILEN_VJ; \
+ if ((len -= vjlen) < 0) \
+ goto bad; \
+ GETCHAR(citype, p); \
+ GETCHAR(cilen, p); \
+ if (cilen != vjlen || \
+ citype != opt) \
+ goto bad; \
+ GETSHORT(cishort, p); \
+ if (cishort != val) \
+ goto bad; \
+ if (!old) { \
+ GETCHAR(cimaxslotindex, p); \
+ if (cimaxslotindex != maxslotindex) \
+ goto bad; \
+ GETCHAR(cicflag, p); \
+ if (cicflag != cflag) \
+ goto bad; \
+ } \
+ }
+
+#define ACKCIADDR(opt, neg, old, val1, val2) \
+ if (neg) { \
+ int addrlen = (old? CILEN_ADDRS: CILEN_ADDR); \
+ u_int32_t l; \
+ if ((len -= addrlen) < 0) \
+ goto bad; \
+ GETCHAR(citype, p); \
+ GETCHAR(cilen, p); \
+ if (cilen != addrlen || \
+ citype != opt) \
+ goto bad; \
+ GETLONG(l, p); \
+ cilong = htonl(l); \
+ if (val1 != cilong) \
+ goto bad; \
+ if (old) { \
+ GETLONG(l, p); \
+ cilong = htonl(l); \
+ if (val2 != cilong) \
+ goto bad; \
+ } \
+ }
+
+#define ACKCIDNS(opt, neg, addr) \
+ if (neg) { \
+ u_int32_t l; \
+ if ((len -= CILEN_ADDR) < 0) \
+ goto bad; \
+ GETCHAR(citype, p); \
+ GETCHAR(cilen, p); \
+ if (cilen != CILEN_ADDR || citype != opt) \
+ goto bad; \
+ GETLONG(l, p); \
+ cilong = htonl(l); \
+ if (addr != cilong) \
+ goto bad; \
+ }
+
+ ACKCIADDR((go->old_addrs? CI_ADDRS: CI_ADDR), go->neg_addr,
+ go->old_addrs, go->ouraddr, go->hisaddr);
+
+ ACKCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol, go->old_vj,
+ go->maxslotindex, go->cflag);
+
+ ACKCIDNS(CI_MS_DNS1, go->req_dns1, go->dnsaddr[0]);
+
+ ACKCIDNS(CI_MS_DNS2, go->req_dns2, go->dnsaddr[1]);
+
+ /*
+ * If there are any remaining CIs, then this packet is bad.
+ */
+ if (len != 0)
+ goto bad;
+ return (1);
+
+bad:
+ IPCPDEBUG(("ipcp_ackci: received bad Ack!"));
+ return (0);
+}
+
+/*
+ * ipcp_nakci - Peer has sent a NAK for some of our CIs.
+ * This should not modify any state if the Nak is bad
+ * or if IPCP is in the OPENED state.
+ * Calback from fsm_rconfnakrej - Receive Configure-Nak or Configure-Reject.
+ *
+ * Returns:
+ * 0 - Nak was bad.
+ * 1 - Nak was good.
+ */
+static int
+ipcp_nakci(f, p, len)
+ fsm *f;
+ u_char *p;
+ int len;
+{
+ ipcp_options *go = &ipcp_gotoptions[f->unit];
+ u_char cimaxslotindex, cicflag;
+ u_char citype, cilen, *next;
+ u_short cishort;
+ u_int32_t ciaddr1, ciaddr2, l, cidnsaddr;
+ ipcp_options no; /* options we've seen Naks for */
+ ipcp_options try; /* options to request next time */
+
+ BZERO(&no, sizeof(no));
+ try = *go;
+
+ /*
+ * Any Nak'd CIs must be in exactly the same order that we sent.
+ * Check packet length and CI length at each step.
+ * If we find any deviations, then this packet is bad.
+ */
+#define NAKCIADDR(opt, neg, old, code) \
+ if (go->neg && \
+ len >= (cilen = (old? CILEN_ADDRS: CILEN_ADDR)) && \
+ p[1] == cilen && \
+ p[0] == opt) { \
+ len -= cilen; \
+ INCPTR(2, p); \
+ GETLONG(l, p); \
+ ciaddr1 = htonl(l); \
+ if (old) { \
+ GETLONG(l, p); \
+ ciaddr2 = htonl(l); \
+ no.old_addrs = 1; \
+ } else \
+ ciaddr2 = 0; \
+ no.neg = 1; \
+ code \
+ }
+
+#define NAKCIVJ(opt, neg, code) \
+ if (go->neg && \
+ ((cilen = p[1]) == CILEN_COMPRESS || cilen == CILEN_VJ) && \
+ len >= cilen && \
+ p[0] == opt) { \
+ len -= cilen; \
+ INCPTR(2, p); \
+ GETSHORT(cishort, p); \
+ no.neg = 1; \
+ code \
+ }
+
+#define NAKCIDNS(opt, neg, code) \
+ if (go->neg && \
+ ((cilen = p[1]) == CILEN_ADDR) && \
+ len >= cilen && \
+ p[0] == opt) { \
+ len -= cilen; \
+ INCPTR(2, p); \
+ GETLONG(l, p); \
+ cidnsaddr = htonl(l); \
+ no.neg = 1; \
+ code \
+ }
+
+ /*
+ * Accept the peer's idea of {our,his} address, if different
+ * from our idea, only if the accept_{local,remote} flag is set.
+ */
+ NAKCIADDR((go->old_addrs? CI_ADDRS: CI_ADDR), neg_addr, go->old_addrs,
+ if (go->accept_local && ciaddr1) { /* Do we know our address? */
+ try.ouraddr = ciaddr1;
+ }
+ if (go->accept_remote && ciaddr2) { /* Does he know his? */
+ try.hisaddr = ciaddr2;
+ }
+ );
+
+ /*
+ * Accept the peer's value of maxslotindex provided that it
+ * is less than what we asked for. Turn off slot-ID compression
+ * if the peer wants. Send old-style compress-type option if
+ * the peer wants.
+ */
+ NAKCIVJ(CI_COMPRESSTYPE, neg_vj,
+ if (cilen == CILEN_VJ) {
+ GETCHAR(cimaxslotindex, p);
+ GETCHAR(cicflag, p);
+ if (cishort == IPCP_VJ_COMP) {
+ try.old_vj = 0;
+ if (cimaxslotindex < go->maxslotindex)
+ try.maxslotindex = cimaxslotindex;
+ if (!cicflag)
+ try.cflag = 0;
+ } else {
+ try.neg_vj = 0;
+ }
+ } else {
+ if (cishort == IPCP_VJ_COMP || cishort == IPCP_VJ_COMP_OLD) {
+ try.old_vj = 1;
+ try.vj_protocol = cishort;
+ } else {
+ try.neg_vj = 0;
+ }
+ }
+ );
+
+ NAKCIDNS(CI_MS_DNS1, req_dns1,
+ try.dnsaddr[0] = cidnsaddr;
+ );
+
+ NAKCIDNS(CI_MS_DNS2, req_dns2,
+ try.dnsaddr[1] = cidnsaddr;
+ );
+
+ /*
+ * There may be remaining CIs, if the peer is requesting negotiation
+ * on an option that we didn't include in our request packet.
+ * If they want to negotiate about IP addresses, we comply.
+ * If they want us to ask for compression, we refuse.
+ */
+ while (len > CILEN_VOID) {
+ GETCHAR(citype, p);
+ GETCHAR(cilen, p);
+ if( (len -= cilen) < 0 )
+ goto bad;
+ next = p + cilen - 2;
+
+ switch (citype) {
+ case CI_COMPRESSTYPE:
+ if (go->neg_vj || no.neg_vj ||
+ (cilen != CILEN_VJ && cilen != CILEN_COMPRESS))
+ goto bad;
+ no.neg_vj = 1;
+ break;
+ case CI_ADDRS:
+ if ((go->neg_addr && go->old_addrs) || no.old_addrs
+ || cilen != CILEN_ADDRS)
+ goto bad;
+ try.neg_addr = 1;
+ try.old_addrs = 1;
+ GETLONG(l, p);
+ ciaddr1 = htonl(l);
+ if (ciaddr1 && go->accept_local)
+ try.ouraddr = ciaddr1;
+ GETLONG(l, p);
+ ciaddr2 = htonl(l);
+ if (ciaddr2 && go->accept_remote)
+ try.hisaddr = ciaddr2;
+ no.old_addrs = 1;
+ break;
+ case CI_ADDR:
+ if (go->neg_addr || no.neg_addr || cilen != CILEN_ADDR)
+ goto bad;
+ try.old_addrs = 0;
+ GETLONG(l, p);
+ ciaddr1 = htonl(l);
+ if (ciaddr1 && go->accept_local)
+ try.ouraddr = ciaddr1;
+ if (try.ouraddr != 0)
+ try.neg_addr = 1;
+ no.neg_addr = 1;
+ break;
+ }
+ p = next;
+ }
+
+ /*
+ * OK, the Nak is good. Now we can update state.
+ * If there are any remaining options, we ignore them.
+ */
+ if (f->state != OPENED)
+ *go = try;
+
+ return 1;
+
+bad:
+ IPCPDEBUG(("ipcp_nakci: received bad Nak!"));
+ return 0;
+}
+
+
+/*
+ * ipcp_rejci - Reject some of our CIs.
+ * Callback from fsm_rconfnakrej.
+ */
+static int
+ipcp_rejci(f, p, len)
+ fsm *f;
+ u_char *p;
+ int len;
+{
+ ipcp_options *go = &ipcp_gotoptions[f->unit];
+ u_char cimaxslotindex, ciflag, cilen;
+ u_short cishort;
+ u_int32_t cilong;
+ ipcp_options try; /* options to request next time */
+
+ try = *go;
+ /*
+ * Any Rejected CIs must be in exactly the same order that we sent.
+ * Check packet length and CI length at each step.
+ * If we find any deviations, then this packet is bad.
+ */
+#define REJCIADDR(opt, neg, old, val1, val2) \
+ if (go->neg && \
+ len >= (cilen = old? CILEN_ADDRS: CILEN_ADDR) && \
+ p[1] == cilen && \
+ p[0] == opt) { \
+ u_int32_t l; \
+ len -= cilen; \
+ INCPTR(2, p); \
+ GETLONG(l, p); \
+ cilong = htonl(l); \
+ /* Check rejected value. */ \
+ if (cilong != val1) \
+ goto bad; \
+ if (old) { \
+ GETLONG(l, p); \
+ cilong = htonl(l); \
+ /* Check rejected value. */ \
+ if (cilong != val2) \
+ goto bad; \
+ } \
+ try.neg = 0; \
+ }
+
+#define REJCIVJ(opt, neg, val, old, maxslot, cflag) \
+ if (go->neg && \
+ p[1] == (old? CILEN_COMPRESS : CILEN_VJ) && \
+ len >= p[1] && \
+ p[0] == opt) { \
+ len -= p[1]; \
+ INCPTR(2, p); \
+ GETSHORT(cishort, p); \
+ /* Check rejected value. */ \
+ if (cishort != val) \
+ goto bad; \
+ if (!old) { \
+ GETCHAR(cimaxslotindex, p); \
+ if (cimaxslotindex != maxslot) \
+ goto bad; \
+ GETCHAR(ciflag, p); \
+ if (ciflag != cflag) \
+ goto bad; \
+ } \
+ try.neg = 0; \
+ }
+
+#define REJCIDNS(opt, neg, dnsaddr) \
+ if (go->neg && \
+ ((cilen = p[1]) == CILEN_ADDR) && \
+ len >= cilen && \
+ p[0] == opt) { \
+ u_int32_t l; \
+ len -= cilen; \
+ INCPTR(2, p); \
+ GETLONG(l, p); \
+ cilong = htonl(l); \
+ /* Check rejected value. */ \
+ if (cilong != dnsaddr) \
+ goto bad; \
+ try.neg = 0; \
+ }
+
+
+ REJCIADDR((go->old_addrs? CI_ADDRS: CI_ADDR), neg_addr,
+ go->old_addrs, go->ouraddr, go->hisaddr);
+
+ REJCIVJ(CI_COMPRESSTYPE, neg_vj, go->vj_protocol, go->old_vj,
+ go->maxslotindex, go->cflag);
+
+ REJCIDNS(CI_MS_DNS1, req_dns1, go->dnsaddr[0]);
+
+ REJCIDNS(CI_MS_DNS2, req_dns2, go->dnsaddr[1]);
+
+ /*
+ * If there are any remaining CIs, then this packet is bad.
+ */
+ if (len != 0)
+ goto bad;
+ /*
+ * Now we can update state.
+ */
+ if (f->state != OPENED)
+ *go = try;
+ return 1;
+
+bad:
+ IPCPDEBUG(("ipcp_rejci: received bad Reject!"));
+ return 0;
+}
+
+
+/*
+ * ipcp_reqci - Check the peer's requested CIs and send appropriate response.
+ * Callback from fsm_rconfreq, Receive Configure Request
+ *
+ * Returns: CONFACK, CONFNAK or CONFREJ and input packet modified
+ * appropriately. If reject_if_disagree is non-zero, doesn't return
+ * CONFNAK; returns CONFREJ if it can't return CONFACK.
+ */
+static int
+ipcp_reqci(f, inp, len, reject_if_disagree)
+ fsm *f;
+ u_char *inp; /* Requested CIs */
+ int *len; /* Length of requested CIs */
+ int reject_if_disagree;
+{
+ ipcp_options *wo = &ipcp_wantoptions[f->unit];
+ ipcp_options *ho = &ipcp_hisoptions[f->unit];
+ ipcp_options *ao = &ipcp_allowoptions[f->unit];
+ ipcp_options *go = &ipcp_gotoptions[f->unit];
+ u_char *cip, *next; /* Pointer to current and next CIs */
+ u_short cilen, citype; /* Parsed len, type */
+ u_short cishort; /* Parsed short value */
+ u_int32_t tl, ciaddr1, ciaddr2;/* Parsed address values */
+ int rc = CONFACK; /* Final packet return code */
+ int orc; /* Individual option return code */
+ u_char *p; /* Pointer to next char to parse */
+ u_char *ucp = inp; /* Pointer to current output char */
+ int l = *len; /* Length left */
+ u_char maxslotindex, cflag;
+ int d;
+
+ /*
+ * Reset all his options.
+ */
+ BZERO(ho, sizeof(*ho));
+
+ /*
+ * Process all his options.
+ */
+ next = inp;
+ while (l) {
+ orc = CONFACK; /* Assume success */
+ cip = p = next; /* Remember begining of CI */
+ if (l < 2 || /* Not enough data for CI header or */
+ p[1] < 2 || /* CI length too small or */
+ p[1] > l) { /* CI length too big? */
+ IPCPDEBUG(("ipcp_reqci: bad CI length!"));
+ orc = CONFREJ; /* Reject bad CI */
+ cilen = l; /* Reject till end of packet */
+ l = 0; /* Don't loop again */
+ goto endswitch;
+ }
+ GETCHAR(citype, p); /* Parse CI type */
+ GETCHAR(cilen, p); /* Parse CI length */
+ l -= cilen; /* Adjust remaining length */
+ next += cilen; /* Step to next CI */
+
+ switch (citype) { /* Check CI type */
+ case CI_ADDRS:
+ if (!ao->neg_addr ||
+ cilen != CILEN_ADDRS) { /* Check CI length */
+ orc = CONFREJ; /* Reject CI */
+ break;
+ }
+
+ /*
+ * If he has no address, or if we both have his address but
+ * disagree about it, then NAK it with our idea.
+ * In particular, if we don't know his address, but he does,
+ * then accept it.
+ */
+ GETLONG(tl, p); /* Parse source address (his) */
+ ciaddr1 = htonl(tl);
+ if (ciaddr1 != wo->hisaddr
+ && (ciaddr1 == 0 || !wo->accept_remote)) {
+ orc = CONFNAK;
+ if (!reject_if_disagree) {
+ DECPTR(sizeof(u_int32_t), p);
+ tl = ntohl(wo->hisaddr);
+ PUTLONG(tl, p);
+ }
+ } else if (ciaddr1 == 0 && wo->hisaddr == 0) {
+ /*
+ * If neither we nor he knows his address, reject the option.
+ */
+ orc = CONFREJ;
+ wo->req_addr = 0; /* don't NAK with 0.0.0.0 later */
+ break;
+ }
+
+ /*
+ * If he doesn't know our address, or if we both have our address
+ * but disagree about it, then NAK it with our idea.
+ */
+ GETLONG(tl, p); /* Parse desination address (ours) */
+ ciaddr2 = htonl(tl);
+ if (ciaddr2 != wo->ouraddr) {
+ if (ciaddr2 == 0 || !wo->accept_local) {
+ orc = CONFNAK;
+ if (!reject_if_disagree) {
+ DECPTR(sizeof(u_int32_t), p);
+ tl = ntohl(wo->ouraddr);
+ PUTLONG(tl, p);
+ }
+ } else {
+ go->ouraddr = ciaddr2; /* accept peer's idea */
+ }
+ }
+
+ ho->neg_addr = 1;
+ ho->old_addrs = 1;
+ ho->hisaddr = ciaddr1;
+ ho->ouraddr = ciaddr2;
+ break;
+
+ case CI_ADDR:
+ if (!ao->neg_addr ||
+ cilen != CILEN_ADDR) { /* Check CI length */
+ orc = CONFREJ; /* Reject CI */
+ break;
+ }
+
+ /*
+ * If he has no address, or if we both have his address but
+ * disagree about it, then NAK it with our idea.
+ * In particular, if we don't know his address, but he does,
+ * then accept it.
+ */
+ GETLONG(tl, p); /* Parse source address (his) */
+ ciaddr1 = htonl(tl);
+ if (ciaddr1 != wo->hisaddr
+ && (ciaddr1 == 0 || !wo->accept_remote)) {
+ orc = CONFNAK;
+ if (!reject_if_disagree) {
+ DECPTR(sizeof(u_int32_t), p);
+ tl = ntohl(wo->hisaddr);
+ PUTLONG(tl, p);
+ }
+ } else if (ciaddr1 == 0 && wo->hisaddr == 0) {
+ /*
+ * Don't ACK an address of 0.0.0.0 - reject it instead.
+ */
+ orc = CONFREJ;
+ wo->req_addr = 0; /* don't NAK with 0.0.0.0 later */
+ break;
+ }
+
+ ho->neg_addr = 1;
+ ho->hisaddr = ciaddr1;
+ break;
+
+ case CI_MS_DNS1:
+ case CI_MS_DNS2:
+ /* Microsoft primary or secondary DNS request */
+ d = citype == CI_MS_DNS2;
+
+ /* If we do not have a DNS address then we cannot send it */
+ if (ao->dnsaddr[d] == 0 ||
+ cilen != CILEN_ADDR) { /* Check CI length */
+ orc = CONFREJ; /* Reject CI */
+ break;
+ }
+ GETLONG(tl, p);
+ if (htonl(tl) != ao->dnsaddr[d]) {
+ DECPTR(sizeof(u_int32_t), p);
+ tl = ntohl(ao->dnsaddr[d]);
+ PUTLONG(tl, p);
+ orc = CONFNAK;
+ }
+ break;
+
+ case CI_MS_WINS1:
+ case CI_MS_WINS2:
+ /* Microsoft primary or secondary WINS request */
+ d = citype == CI_MS_WINS2;
+
+ /* If we do not have a DNS address then we cannot send it */
+ if (ao->winsaddr[d] == 0 ||
+ cilen != CILEN_ADDR) { /* Check CI length */
+ orc = CONFREJ; /* Reject CI */
+ break;
+ }
+ GETLONG(tl, p);
+ if (htonl(tl) != ao->winsaddr[d]) {
+ DECPTR(sizeof(u_int32_t), p);
+ tl = ntohl(ao->winsaddr[d]);
+ PUTLONG(tl, p);
+ orc = CONFNAK;
+ }
+ break;
+
+ case CI_COMPRESSTYPE:
+ if (!ao->neg_vj ||
+ (cilen != CILEN_VJ && cilen != CILEN_COMPRESS)) {
+ orc = CONFREJ;
+ break;
+ }
+ GETSHORT(cishort, p);
+
+ if (!(cishort == IPCP_VJ_COMP ||
+ (cishort == IPCP_VJ_COMP_OLD && cilen == CILEN_COMPRESS))) {
+ orc = CONFREJ;
+ break;
+ }
+
+ ho->neg_vj = 1;
+ ho->vj_protocol = cishort;
+ if (cilen == CILEN_VJ) {
+ GETCHAR(maxslotindex, p);
+ if (maxslotindex > ao->maxslotindex) {
+ orc = CONFNAK;
+ if (!reject_if_disagree){
+ DECPTR(1, p);
+ PUTCHAR(ao->maxslotindex, p);
+ }
+ }
+ GETCHAR(cflag, p);
+ if (cflag && !ao->cflag) {
+ orc = CONFNAK;
+ if (!reject_if_disagree){
+ DECPTR(1, p);
+ PUTCHAR(wo->cflag, p);
+ }
+ }
+ ho->maxslotindex = maxslotindex;
+ ho->cflag = cflag;
+ } else {
+ ho->old_vj = 1;
+ ho->maxslotindex = MAX_STATES - 1;
+ ho->cflag = 1;
+ }
+ break;
+
+ default:
+ orc = CONFREJ;
+ break;
+ }
+endswitch:
+ if (orc == CONFACK && /* Good CI */
+ rc != CONFACK) /* but prior CI wasnt? */
+ continue; /* Don't send this one */
+
+ if (orc == CONFNAK) { /* Nak this CI? */
+ if (reject_if_disagree) /* Getting fed up with sending NAKs? */
+ orc = CONFREJ; /* Get tough if so */
+ else {
+ if (rc == CONFREJ) /* Rejecting prior CI? */
+ continue; /* Don't send this one */
+ if (rc == CONFACK) { /* Ack'd all prior CIs? */
+ rc = CONFNAK; /* Not anymore... */
+ ucp = inp; /* Backup */
+ }
+ }
+ }
+
+ if (orc == CONFREJ && /* Reject this CI */
+ rc != CONFREJ) { /* but no prior ones? */
+ rc = CONFREJ;
+ ucp = inp; /* Backup */
+ }
+
+ /* Need to move CI? */
+ if (ucp != cip)
+ BCOPY(cip, ucp, cilen); /* Move it */
+
+ /* Update output pointer */
+ INCPTR(cilen, ucp);
+ }
+
+ /*
+ * If we aren't rejecting this packet, and we want to negotiate
+ * their address, and they didn't send their address, then we
+ * send a NAK with a CI_ADDR option appended. We assume the
+ * input buffer is long enough that we can append the extra
+ * option safely.
+ */
+ if (rc != CONFREJ && !ho->neg_addr &&
+ wo->req_addr && !reject_if_disagree) {
+ if (rc == CONFACK) {
+ rc = CONFNAK;
+ ucp = inp; /* reset pointer */
+ wo->req_addr = 0; /* don't ask again */
+ }
+ PUTCHAR(CI_ADDR, ucp);
+ PUTCHAR(CILEN_ADDR, ucp);
+ tl = ntohl(wo->hisaddr);
+ PUTLONG(tl, ucp);
+ }
+
+ *len = ucp - inp; /* Compute output length */
+ IPCPDEBUG(("ipcp: returning Configure-%s", CODENAME(rc)));
+ return (rc); /* Return final code */
+}
+
+
+/*
+ * ip_check_options - check that any IP-related options are OK,
+ * and assign appropriate defaults.
+ */
+static void
+ip_check_options()
+{
+ struct hostent *hp;
+ u_int32_t local;
+ ipcp_options *wo = &ipcp_wantoptions[0];
+
+ /*
+ * Default our local IP address based on our hostname.
+ * If local IP address already given, don't bother.
+ */
+ if (wo->ouraddr == 0 && !disable_defaultip) {
+ /*
+ * Look up our hostname (possibly with domain name appended)
+ * and take the first IP address as our local IP address.
+ * If there isn't an IP address for our hostname, too bad.
+ */
+ wo->accept_local = 1; /* don't insist on this default value */
+ if ((hp = gethostbyname(hostname)) != NULL) {
+ local = *(u_int32_t *)hp->h_addr;
+ if (local != 0 && !bad_ip_adrs(local))
+ wo->ouraddr = local;
+ }
+ }
+ ask_for_local = wo->ouraddr != 0 || !disable_defaultip;
+}
+
+
+/*
+ * ip_demand_conf - configure the interface as though
+ * IPCP were up, for use with dial-on-demand.
+ */
+static int
+ip_demand_conf(u)
+ int u;
+{
+ ipcp_options *wo = &ipcp_wantoptions[u];
+
+ if (wo->hisaddr == 0) {
+ /* make up an arbitrary address for the peer */
+ wo->hisaddr = htonl(0x0a707070 + ifunit);
+ wo->accept_remote = 1;
+ }
+ if (wo->ouraddr == 0) {
+ /* make up an arbitrary address for us */
+ wo->ouraddr = htonl(0x0a404040 + ifunit);
+ wo->accept_local = 1;
+ ask_for_local = 0; /* don't tell the peer this address */
+ }
+ if (!sifaddr(u, wo->ouraddr, wo->hisaddr, GetMask(wo->ouraddr)))
+ return 0;
+ if (!sifup(u))
+ return 0;
+ if (!sifnpmode(u, PPP_IP, NPMODE_QUEUE))
+ return 0;
+ if (wo->default_route)
+ if (sifdefaultroute(u, wo->ouraddr, wo->hisaddr))
+ default_route_set[u] = 1;
+ if (wo->proxy_arp)
+ if (sifproxyarp(u, wo->hisaddr))
+ proxy_arp_set[u] = 1;
+
+ notice("local IP address %I", wo->ouraddr);
+ notice("remote IP address %I", wo->hisaddr);
+
+ return 1;
+}
+
+
+/*
+ * ipcp_up - IPCP has come UP.
+ *
+ * Configure the IP network interface appropriately and bring it up.
+ */
+static void
+ipcp_up(f)
+ fsm *f;
+{
+ u_int32_t mask;
+ ipcp_options *ho = &ipcp_hisoptions[f->unit];
+ ipcp_options *go = &ipcp_gotoptions[f->unit];
+ ipcp_options *wo = &ipcp_wantoptions[f->unit];
+
+ IPCPDEBUG(("ipcp: up"));
+
+ /*
+ * We must have a non-zero IP address for both ends of the link.
+ */
+ if (!ho->neg_addr)
+ ho->hisaddr = wo->hisaddr;
+
+ if (go->ouraddr == 0) {
+ error("Could not determine local IP address");
+ ipcp_close(f->unit, "Could not determine local IP address");
+ return;
+ }
+ if (ho->hisaddr == 0) {
+ ho->hisaddr = htonl(0x0a404040 + ifunit);
+ warn("Could not determine remote IP address: defaulting to %I",
+ ho->hisaddr);
+ }
+ script_setenv("IPLOCAL", ip_ntoa(go->ouraddr), 0);
+ script_setenv("IPREMOTE", ip_ntoa(ho->hisaddr), 1);
+
+ if (usepeerdns && (go->dnsaddr[0] || go->dnsaddr[1])) {
+ script_setenv("USEPEERDNS", "1", 0);
+ if (go->dnsaddr[0])
+ script_setenv("DNS1", ip_ntoa(go->dnsaddr[0]), 0);
+ if (go->dnsaddr[1])
+ script_setenv("DNS2", ip_ntoa(go->dnsaddr[1]), 0);
+ create_resolv(go->dnsaddr[0], go->dnsaddr[1]);
+ }
+
+ /*
+ * Check that the peer is allowed to use the IP address it wants.
+ */
+ if (!auth_ip_addr(f->unit, ho->hisaddr)) {
+ error("Peer is not authorized to use remote address %I", ho->hisaddr);
+ ipcp_close(f->unit, "Unauthorized remote IP address");
+ return;
+ }
+
+ /* set tcp compression */
+ sifvjcomp(f->unit, ho->neg_vj, ho->cflag, ho->maxslotindex);
+
+ /*
+ * If we are doing dial-on-demand, the interface is already
+ * configured, so we put out any saved-up packets, then set the
+ * interface to pass IP packets.
+ */
+ if (demand) {
+ if (go->ouraddr != wo->ouraddr || ho->hisaddr != wo->hisaddr) {
+ ipcp_clear_addrs(f->unit, wo->ouraddr, wo->hisaddr);
+ if (go->ouraddr != wo->ouraddr) {
+ warn("Local IP address changed to %I", go->ouraddr);
+ script_setenv("OLDIPLOCAL", ip_ntoa(wo->ouraddr), 0);
+ wo->ouraddr = go->ouraddr;
+ } else
+ script_unsetenv("OLDIPLOCAL");
+ if (ho->hisaddr != wo->hisaddr) {
+ warn("Remote IP address changed to %I", ho->hisaddr);
+ script_setenv("OLDIPREMOTE", ip_ntoa(wo->hisaddr), 0);
+ wo->hisaddr = ho->hisaddr;
+ } else
+ script_unsetenv("OLDIPREMOTE");
+
+ /* Set the interface to the new addresses */
+ mask = GetMask(go->ouraddr);
+ if (!sifaddr(f->unit, go->ouraddr, ho->hisaddr, mask)) {
+ if (debug)
+ warn("Interface configuration failed");
+ ipcp_close(f->unit, "Interface configuration failed");
+ return;
+ }
+
+ /* assign a default route through the interface if required */
+ if (ipcp_wantoptions[f->unit].default_route)
+ if (sifdefaultroute(f->unit, go->ouraddr, ho->hisaddr))
+ default_route_set[f->unit] = 1;
+
+ /* Make a proxy ARP entry if requested. */
+ if (ipcp_wantoptions[f->unit].proxy_arp)
+ if (sifproxyarp(f->unit, ho->hisaddr))
+ proxy_arp_set[f->unit] = 1;
+
+ }
+ demand_rexmit(PPP_IP);
+ sifnpmode(f->unit, PPP_IP, NPMODE_PASS);
+
+ } else {
+ /*
+ * Set IP addresses and (if specified) netmask.
+ */
+ mask = GetMask(go->ouraddr);
+
+#if !(defined(SVR4) && (defined(SNI) || defined(__USLC__)))
+ if (!sifaddr(f->unit, go->ouraddr, ho->hisaddr, mask)) {
+ if (debug)
+ warn("Interface configuration failed");
+ ipcp_close(f->unit, "Interface configuration failed");
+ return;
+ }
+#endif
+
+ /* bring the interface up for IP */
+ if (!sifup(f->unit)) {
+ if (debug)
+ warn("Interface failed to come up");
+ ipcp_close(f->unit, "Interface configuration failed");
+ return;
+ }
+
+#if (defined(SVR4) && (defined(SNI) || defined(__USLC__)))
+ if (!sifaddr(f->unit, go->ouraddr, ho->hisaddr, mask)) {
+ if (debug)
+ warn("Interface configuration failed");
+ ipcp_close(f->unit, "Interface configuration failed");
+ return;
+ }
+#endif
+ sifnpmode(f->unit, PPP_IP, NPMODE_PASS);
+
+ /* assign a default route through the interface if required */
+ if (ipcp_wantoptions[f->unit].default_route)
+ if (sifdefaultroute(f->unit, go->ouraddr, ho->hisaddr))
+ default_route_set[f->unit] = 1;
+
+ /* Make a proxy ARP entry if requested. */
+ if (ipcp_wantoptions[f->unit].proxy_arp)
+ if (sifproxyarp(f->unit, ho->hisaddr))
+ proxy_arp_set[f->unit] = 1;
+
+ ipcp_wantoptions[0].ouraddr = go->ouraddr;
+
+ notice("local IP address %I", go->ouraddr);
+ notice("remote IP address %I", ho->hisaddr);
+ if (go->dnsaddr[0])
+ notice("primary DNS address %I", go->dnsaddr[0]);
+ if (go->dnsaddr[1])
+ notice("secondary DNS address %I", go->dnsaddr[1]);
+ }
+
+ np_up(f->unit, PPP_IP);
+ ipcp_is_up = 1;
+
+ if (ip_up_hook)
+ ip_up_hook();
+
+ /*
+ * Execute the ip-up script, like this:
+ * /etc/ppp/ip-up interface tty speed local-IP remote-IP
+ */
+ if (ipcp_script_state == s_down && ipcp_script_pid == 0) {
+ ipcp_script_state = s_up;
+ ipcp_script(_PATH_IPUP);
+ }
+}
+
+
+/*
+ * ipcp_down - IPCP has gone DOWN.
+ *
+ * Take the IP network interface down, clear its addresses
+ * and delete routes through it.
+ */
+static void
+ipcp_down(f)
+ fsm *f;
+{
+ IPCPDEBUG(("ipcp: down"));
+ /* XXX a bit IPv4-centric here, we only need to get the stats
+ * before the interface is marked down. */
+ update_link_stats(f->unit);
+ if (ip_down_hook)
+ ip_down_hook();
+ if (ipcp_is_up) {
+ ipcp_is_up = 0;
+ np_down(f->unit, PPP_IP);
+ }
+ sifvjcomp(f->unit, 0, 0, 0);
+
+ /*
+ * If we are doing dial-on-demand, set the interface
+ * to queue up outgoing packets (for now).
+ */
+ if (demand) {
+ sifnpmode(f->unit, PPP_IP, NPMODE_QUEUE);
+ } else {
+ sifnpmode(f->unit, PPP_IP, NPMODE_DROP);
+ sifdown(f->unit);
+ ipcp_clear_addrs(f->unit, ipcp_gotoptions[f->unit].ouraddr,
+ ipcp_hisoptions[f->unit].hisaddr);
+ }
+
+ /* Execute the ip-down script */
+ if (ipcp_script_state == s_up && ipcp_script_pid == 0) {
+ ipcp_script_state = s_down;
+ ipcp_script(_PATH_IPDOWN);
+ }
+}
+
+
+/*
+ * ipcp_clear_addrs() - clear the interface addresses, routes,
+ * proxy arp entries, etc.
+ */
+static void
+ipcp_clear_addrs(unit, ouraddr, hisaddr)
+ int unit;
+ u_int32_t ouraddr; /* local address */
+ u_int32_t hisaddr; /* remote address */
+{
+ if (proxy_arp_set[unit]) {
+ cifproxyarp(unit, hisaddr);
+ proxy_arp_set[unit] = 0;
+ }
+ if (default_route_set[unit]) {
+ cifdefaultroute(unit, ouraddr, hisaddr);
+ default_route_set[unit] = 0;
+ }
+ cifaddr(unit, ouraddr, hisaddr);
+}
+
+
+/*
+ * ipcp_finished - possibly shut down the lower layers.
+ */
+static void
+ipcp_finished(f)
+ fsm *f;
+{
+ np_finished(f->unit, PPP_IP);
+}
+
+
+/*
+ * ipcp_script_done - called when the ip-up or ip-down script
+ * has finished.
+ */
+static void
+ipcp_script_done(arg)
+ void *arg;
+{
+ ipcp_script_pid = 0;
+ switch (ipcp_script_state) {
+ case s_up:
+ if (ipcp_fsm[0].state != OPENED) {
+ ipcp_script_state = s_down;
+ ipcp_script(_PATH_IPDOWN);
+ }
+ break;
+ case s_down:
+ if (ipcp_fsm[0].state == OPENED) {
+ ipcp_script_state = s_up;
+ ipcp_script(_PATH_IPUP);
+ }
+ break;
+ }
+}
+
+
+/*
+ * ipcp_script - Execute a script with arguments
+ * interface-name tty-name speed local-IP remote-IP.
+ */
+static void
+ipcp_script(script)
+ char *script;
+{
+ char strspeed[32], strlocal[32], strremote[32];
+ char *argv[8];
+
+ slprintf(strspeed, sizeof(strspeed), "%d", baud_rate);
+ slprintf(strlocal, sizeof(strlocal), "%I", ipcp_gotoptions[0].ouraddr);
+ slprintf(strremote, sizeof(strremote), "%I", ipcp_hisoptions[0].hisaddr);
+
+ argv[0] = script;
+ argv[1] = ifname;
+ argv[2] = devnam;
+ argv[3] = strspeed;
+ argv[4] = strlocal;
+ argv[5] = strremote;
+ argv[6] = ipparam;
+ argv[7] = NULL;
+ ipcp_script_pid = run_program(script, argv, 0, ipcp_script_done, NULL);
+}
+
+/*
+ * create_resolv - create the replacement resolv.conf file
+ */
+static void
+create_resolv(peerdns1, peerdns2)
+ u_int32_t peerdns1, peerdns2;
+{
+ FILE *f;
+
+ f = fopen(_PATH_RESOLV, "w");
+ if (f == NULL) {
+ error("Failed to create %s: %m", _PATH_RESOLV);
+ return;
+ }
+
+ if (peerdns1)
+ fprintf(f, "nameserver %s\n", ip_ntoa(peerdns1));
+
+ if (peerdns2)
+ fprintf(f, "nameserver %s\n", ip_ntoa(peerdns2));
+
+ if (ferror(f))
+ error("Write failed to %s: %m", _PATH_RESOLV);
+
+ fclose(f);
+}
+
+/*
+ * ipcp_printpkt - print the contents of an IPCP packet.
+ */
+static char *ipcp_codenames[] = {
+ "ConfReq", "ConfAck", "ConfNak", "ConfRej",
+ "TermReq", "TermAck", "CodeRej"
+};
+
+static int
+ipcp_printpkt(p, plen, printer, arg)
+ u_char *p;
+ int plen;
+ void (*printer) __P((void *, char *, ...));
+ void *arg;
+{
+ int code, id, len, olen;
+ u_char *pstart, *optend;
+ u_short cishort;
+ u_int32_t cilong;
+
+ if (plen < HEADERLEN)
+ return 0;
+ pstart = p;
+ GETCHAR(code, p);
+ GETCHAR(id, p);
+ GETSHORT(len, p);
+ if (len < HEADERLEN || len > plen)
+ return 0;
+
+ if (code >= 1 && code <= sizeof(ipcp_codenames) / sizeof(char *))
+ printer(arg, " %s", ipcp_codenames[code-1]);
+ else
+ printer(arg, " code=0x%x", code);
+ printer(arg, " id=0x%x", id);
+ len -= HEADERLEN;
+ switch (code) {
+ case CONFREQ:
+ case CONFACK:
+ case CONFNAK:
+ case CONFREJ:
+ /* print option list */
+ while (len >= 2) {
+ GETCHAR(code, p);
+ GETCHAR(olen, p);
+ p -= 2;
+ if (olen < 2 || olen > len) {
+ break;
+ }
+ printer(arg, " <");
+ len -= olen;
+ optend = p + olen;
+ switch (code) {
+ case CI_ADDRS:
+ if (olen == CILEN_ADDRS) {
+ p += 2;
+ GETLONG(cilong, p);
+ printer(arg, "addrs %I", htonl(cilong));
+ GETLONG(cilong, p);
+ printer(arg, " %I", htonl(cilong));
+ }
+ break;
+ case CI_COMPRESSTYPE:
+ if (olen >= CILEN_COMPRESS) {
+ p += 2;
+ GETSHORT(cishort, p);
+ printer(arg, "compress ");
+ switch (cishort) {
+ case IPCP_VJ_COMP:
+ printer(arg, "VJ");
+ break;
+ case IPCP_VJ_COMP_OLD:
+ printer(arg, "old-VJ");
+ break;
+ default:
+ printer(arg, "0x%x", cishort);
+ }
+ }
+ break;
+ case CI_ADDR:
+ if (olen == CILEN_ADDR) {
+ p += 2;
+ GETLONG(cilong, p);
+ printer(arg, "addr %I", htonl(cilong));
+ }
+ break;
+ case CI_MS_DNS1:
+ case CI_MS_DNS2:
+ p += 2;
+ GETLONG(cilong, p);
+ printer(arg, "ms-dns%d %I", code - CI_MS_DNS1 + 1,
+ htonl(cilong));
+ break;
+ case CI_MS_WINS1:
+ case CI_MS_WINS2:
+ p += 2;
+ GETLONG(cilong, p);
+ printer(arg, "ms-wins %I", htonl(cilong));
+ break;
+ }
+ while (p < optend) {
+ GETCHAR(code, p);
+ printer(arg, " %.2x", code);
+ }
+ printer(arg, ">");
+ }
+ break;
+
+ case TERMACK:
+ case TERMREQ:
+ if (len > 0 && *p >= ' ' && *p < 0x7f) {
+ printer(arg, " ");
+ print_string((char *)p, len, printer, arg);
+ p += len;
+ len = 0;
+ }
+ break;
+ }
+
+ /* print the rest of the bytes in the packet */
+ for (; len > 0; --len) {
+ GETCHAR(code, p);
+ printer(arg, " %.2x", code);
+ }
+
+ return p - pstart;
+}
+
+/*
+ * ip_active_pkt - see if this IP packet is worth bringing the link up for.
+ * We don't bring the link up for IP fragments or for TCP FIN packets
+ * with no data.
+ */
+#define IP_HDRLEN 20 /* bytes */
+#define IP_OFFMASK 0x1fff
+// #define IPPROTO_TCP 6
+#define TCP_HDRLEN 20
+#define TH_FIN 0x01
+
+/*
+ * We use these macros because the IP header may be at an odd address,
+ * and some compilers might use word loads to get th_off or ip_hl.
+ */
+
+#define net_short(x) (((x)[0] << 8) + (x)[1])
+#define get_iphl(x) (((unsigned char *)(x))[0] & 0xF)
+#define get_ipoff(x) net_short((unsigned char *)(x) + 6)
+#define get_ipproto(x) (((unsigned char *)(x))[9])
+#define get_tcpoff(x) (((unsigned char *)(x))[12] >> 4)
+#define get_tcpflags(x) (((unsigned char *)(x))[13])
+
+static int
+ip_active_pkt(pkt, len)
+ u_char *pkt;
+ int len;
+{
+ u_char *tcp;
+ int hlen;
+
+ len -= PPP_HDRLEN;
+ pkt += PPP_HDRLEN;
+ if (len < IP_HDRLEN)
+ return 0;
+ if ((get_ipoff(pkt) & IP_OFFMASK) != 0)
+ return 0;
+ if (get_ipproto(pkt) != IPPROTO_TCP)
+ return 1;
+ hlen = get_iphl(pkt) * 4;
+ if (len < hlen + TCP_HDRLEN)
+ return 0;
+ tcp = pkt + hlen;
+ if ((get_tcpflags(tcp) & TH_FIN) != 0 && len == hlen + get_tcpoff(tcp) * 4)
+ return 0;
+ return 1;
+}
diff --git a/mdk-stage1/ppp/pppd/ipcp.h b/mdk-stage1/ppp/pppd/ipcp.h
new file mode 100644
index 000000000..ca180b98a
--- /dev/null
+++ b/mdk-stage1/ppp/pppd/ipcp.h
@@ -0,0 +1,73 @@
+/*
+ * ipcp.h - IP Control Protocol definitions.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id: ipcp.h 195720 2001-06-11 11:44:34Z gc $
+ */
+
+/*
+ * Options.
+ */
+#define CI_ADDRS 1 /* IP Addresses */
+#define CI_COMPRESSTYPE 2 /* Compression Type */
+#define CI_ADDR 3
+
+#define CI_MS_DNS1 129 /* Primary DNS value */
+#define CI_MS_WINS1 130 /* Primary WINS value */
+#define CI_MS_DNS2 131 /* Secondary DNS value */
+#define CI_MS_WINS2 132 /* Secondary WINS value */
+
+#define MAX_STATES 16 /* from slcompress.h */
+
+#define IPCP_VJMODE_OLD 1 /* "old" mode (option # = 0x0037) */
+#define IPCP_VJMODE_RFC1172 2 /* "old-rfc"mode (option # = 0x002d) */
+#define IPCP_VJMODE_RFC1332 3 /* "new-rfc"mode (option # = 0x002d, */
+ /* maxslot and slot number compression) */
+
+#define IPCP_VJ_COMP 0x002d /* current value for VJ compression option*/
+#define IPCP_VJ_COMP_OLD 0x0037 /* "old" (i.e, broken) value for VJ */
+ /* compression option*/
+
+typedef struct ipcp_options {
+ bool neg_addr; /* Negotiate IP Address? */
+ bool old_addrs; /* Use old (IP-Addresses) option? */
+ bool req_addr; /* Ask peer to send IP address? */
+ bool default_route; /* Assign default route through interface? */
+ bool proxy_arp; /* Make proxy ARP entry for peer? */
+ bool neg_vj; /* Van Jacobson Compression? */
+ bool old_vj; /* use old (short) form of VJ option? */
+ bool accept_local; /* accept peer's value for ouraddr */
+ bool accept_remote; /* accept peer's value for hisaddr */
+ bool req_dns1; /* Ask peer to send primary DNS address? */
+ bool req_dns2; /* Ask peer to send secondary DNS address? */
+ int vj_protocol; /* protocol value to use in VJ option */
+ int maxslotindex; /* values for RFC1332 VJ compression neg. */
+ bool cflag;
+ u_int32_t ouraddr, hisaddr; /* Addresses in NETWORK BYTE ORDER */
+ u_int32_t dnsaddr[2]; /* Primary and secondary MS DNS entries */
+ u_int32_t winsaddr[2]; /* Primary and secondary MS WINS entries */
+} ipcp_options;
+
+extern fsm ipcp_fsm[];
+extern ipcp_options ipcp_wantoptions[];
+extern ipcp_options ipcp_gotoptions[];
+extern ipcp_options ipcp_allowoptions[];
+extern ipcp_options ipcp_hisoptions[];
+
+char *ip_ntoa __P((u_int32_t));
+
+extern struct protent ipcp_protent;
diff --git a/mdk-stage1/ppp/pppd/ipv6cp.c b/mdk-stage1/ppp/pppd/ipv6cp.c
new file mode 100644
index 000000000..01f963990
--- /dev/null
+++ b/mdk-stage1/ppp/pppd/ipv6cp.c
@@ -0,0 +1,1512 @@
+/*
+ ipv6cp.c - PPP IPV6 Control Protocol.
+ Copyright (C) 1999 Tommi Komulainen <Tommi.Komulainen@iki.fi>
+
+ Redistribution and use in source and binary forms are permitted
+ provided that the above copyright notice and this paragraph are
+ duplicated in all such forms. The name of the author may not be
+ used to endorse or promote products derived from this software
+ without specific prior written permission.
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+*/
+
+/* Original version, based on RFC2023 :
+
+ Copyright (c) 1995, 1996, 1997 Francis.Dupont@inria.fr, INRIA Rocquencourt,
+ Alain.Durand@imag.fr, IMAG,
+ Jean-Luc.Richier@imag.fr, IMAG-LSR.
+
+ Copyright (c) 1998, 1999 Francis.Dupont@inria.fr, GIE DYADE,
+ Alain.Durand@imag.fr, IMAG,
+ Jean-Luc.Richier@imag.fr, IMAG-LSR.
+
+ Ce travail a été fait au sein du GIE DYADE (Groupement d'Intérêt
+ Économique ayant pour membres BULL S.A. et l'INRIA).
+
+ Ce logiciel informatique est disponible aux conditions
+ usuelles dans la recherche, c'est-à-dire qu'il peut
+ être utilisé, copié, modifié, distribué à l'unique
+ condition que ce texte soit conservé afin que
+ l'origine de ce logiciel soit reconnue.
+
+ Le nom de l'Institut National de Recherche en Informatique
+ et en Automatique (INRIA), de l'IMAG, ou d'une personne morale
+ ou physique ayant participé à l'élaboration de ce logiciel ne peut
+ être utilisé sans son accord préalable explicite.
+
+ Ce logiciel est fourni tel quel sans aucune garantie,
+ support ou responsabilité d'aucune sorte.
+ Ce logiciel est dérivé de sources d'origine
+ "University of California at Berkeley" et
+ "Digital Equipment Corporation" couvertes par des copyrights.
+
+ L'Institut d'Informatique et de Mathématiques Appliquées de Grenoble (IMAG)
+ est une fédération d'unités mixtes de recherche du CNRS, de l'Institut National
+ Polytechnique de Grenoble et de l'Université Joseph Fourier regroupant
+ sept laboratoires dont le laboratoire Logiciels, Systèmes, Réseaux (LSR).
+
+ This work has been done in the context of GIE DYADE (joint R & D venture
+ between BULL S.A. and INRIA).
+
+ This software is available with usual "research" terms
+ with the aim of retain credits of the software.
+ Permission to use, copy, modify and distribute this software for any
+ purpose and without fee is hereby granted, provided that the above
+ copyright notice and this permission notice appear in all copies,
+ and the name of INRIA, IMAG, or any contributor not be used in advertising
+ or publicity pertaining to this material without the prior explicit
+ permission. The software is provided "as is" without any
+ warranties, support or liabilities of any kind.
+ This software is derived from source code from
+ "University of California at Berkeley" and
+ "Digital Equipment Corporation" protected by copyrights.
+
+ Grenoble's Institute of Computer Science and Applied Mathematics (IMAG)
+ is a federation of seven research units funded by the CNRS, National
+ Polytechnic Institute of Grenoble and University Joseph Fourier.
+ The research unit in Software, Systems, Networks (LSR) is member of IMAG.
+*/
+
+/*
+ * Derived from :
+ *
+ *
+ * ipcp.c - PPP IP Control Protocol.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id: ipv6cp.c 215411 2007-04-25 12:26:16Z pixel $
+ */
+
+#define RCSID "$Id: ipv6cp.c 215411 2007-04-25 12:26:16Z pixel $"
+
+/*
+ * TODO:
+ *
+ * Proxy Neighbour Discovery.
+ *
+ * Better defines for selecting the ordering of
+ * interface up / set address. (currently checks for __linux__,
+ * since SVR4 && (SNI || __USLC__) didn't work properly)
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <netdb.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include "pppd.h"
+#include "fsm.h"
+#include "ipcp.h"
+#include "ipv6cp.h"
+#include "magic.h"
+#include "pathnames.h"
+
+static const char rcsid[] = RCSID;
+
+/* global vars */
+ipv6cp_options ipv6cp_wantoptions[NUM_PPP]; /* Options that we want to request */
+ipv6cp_options ipv6cp_gotoptions[NUM_PPP]; /* Options that peer ack'd */
+ipv6cp_options ipv6cp_allowoptions[NUM_PPP]; /* Options we allow peer to request */
+ipv6cp_options ipv6cp_hisoptions[NUM_PPP]; /* Options that we ack'd */
+int no_ifaceid_neg = 0;
+
+/* local vars */
+static int ipv6cp_is_up;
+
+/*
+ * Callbacks for fsm code. (CI = Configuration Information)
+ */
+static void ipv6cp_resetci __P((fsm *)); /* Reset our CI */
+static int ipv6cp_cilen __P((fsm *)); /* Return length of our CI */
+static void ipv6cp_addci __P((fsm *, u_char *, int *)); /* Add our CI */
+static int ipv6cp_ackci __P((fsm *, u_char *, int)); /* Peer ack'd our CI */
+static int ipv6cp_nakci __P((fsm *, u_char *, int)); /* Peer nak'd our CI */
+static int ipv6cp_rejci __P((fsm *, u_char *, int)); /* Peer rej'd our CI */
+static int ipv6cp_reqci __P((fsm *, u_char *, int *, int)); /* Rcv CI */
+static void ipv6cp_up __P((fsm *)); /* We're UP */
+static void ipv6cp_down __P((fsm *)); /* We're DOWN */
+static void ipv6cp_finished __P((fsm *)); /* Don't need lower layer */
+
+fsm ipv6cp_fsm[NUM_PPP]; /* IPV6CP fsm structure */
+
+static fsm_callbacks ipv6cp_callbacks = { /* IPV6CP callback routines */
+ ipv6cp_resetci, /* Reset our Configuration Information */
+ ipv6cp_cilen, /* Length of our Configuration Information */
+ ipv6cp_addci, /* Add our Configuration Information */
+ ipv6cp_ackci, /* ACK our Configuration Information */
+ ipv6cp_nakci, /* NAK our Configuration Information */
+ ipv6cp_rejci, /* Reject our Configuration Information */
+ ipv6cp_reqci, /* Request peer's Configuration Information */
+ ipv6cp_up, /* Called when fsm reaches OPENED state */
+ ipv6cp_down, /* Called when fsm leaves OPENED state */
+ NULL, /* Called when we want the lower layer up */
+ ipv6cp_finished, /* Called when we want the lower layer down */
+ NULL, /* Called when Protocol-Reject received */
+ NULL, /* Retransmission is necessary */
+ NULL, /* Called to handle protocol-specific codes */
+ "IPV6CP" /* String name of protocol */
+};
+
+/*
+ * Command-line options.
+ */
+static int setifaceid __P((char **arg));
+static void printifaceid __P((option_t *,
+ void (*)(void *, char *, ...), void *));
+
+static option_t ipv6cp_option_list[] = {
+ { "ipv6", o_special, (void *)setifaceid,
+ "Set interface identifiers for IPV6",
+ OPT_A2PRINTER, (void *)printifaceid },
+
+ { "+ipv6", o_bool, &ipv6cp_protent.enabled_flag,
+ "Enable IPv6 and IPv6CP", OPT_PRIO | 1 },
+ { "noipv6", o_bool, &ipv6cp_protent.enabled_flag,
+ "Disable IPv6 and IPv6CP", OPT_PRIOSUB },
+ { "-ipv6", o_bool, &ipv6cp_protent.enabled_flag,
+ "Disable IPv6 and IPv6CP", OPT_PRIOSUB | OPT_ALIAS },
+
+ { "ipv6cp-accept-local", o_bool, &ipv6cp_allowoptions[0].accept_local,
+ "Accept peer's interface identifier for us", 1 },
+
+ { "ipv6cp-use-ipaddr", o_bool, &ipv6cp_allowoptions[0].use_ip,
+ "Use (default) IPv4 address as interface identifier", 1 },
+
+#if defined(SOL2)
+ { "ipv6cp-use-persistent", o_bool, &ipv6cp_wantoptions[0].use_persistent,
+ "Use uniquely-available persistent value for link local address", 1 },
+#endif /* defined(SOL2) */
+
+ { "ipv6cp-restart", o_int, &ipv6cp_fsm[0].timeouttime,
+ "Set timeout for IPv6CP", OPT_PRIO },
+ { "ipv6cp-max-terminate", o_int, &ipv6cp_fsm[0].maxtermtransmits,
+ "Set max #xmits for term-reqs", OPT_PRIO },
+ { "ipv6cp-max-configure", o_int, &ipv6cp_fsm[0].maxconfreqtransmits,
+ "Set max #xmits for conf-reqs", OPT_PRIO },
+ { "ipv6cp-max-failure", o_int, &ipv6cp_fsm[0].maxnakloops,
+ "Set max #conf-naks for IPv6CP", OPT_PRIO },
+
+ { NULL }
+};
+
+
+/*
+ * Protocol entry points from main code.
+ */
+static void ipv6cp_init __P((int));
+static void ipv6cp_open __P((int));
+static void ipv6cp_close __P((int, char *));
+static void ipv6cp_lowerup __P((int));
+static void ipv6cp_lowerdown __P((int));
+static void ipv6cp_input __P((int, u_char *, int));
+static void ipv6cp_protrej __P((int));
+static int ipv6cp_printpkt __P((u_char *, int,
+ void (*) __P((void *, char *, ...)), void *));
+static void ipv6_check_options __P((void));
+static int ipv6_demand_conf __P((int));
+static int ipv6_active_pkt __P((u_char *, int));
+
+struct protent ipv6cp_protent = {
+ PPP_IPV6CP,
+ ipv6cp_init,
+ ipv6cp_input,
+ ipv6cp_protrej,
+ ipv6cp_lowerup,
+ ipv6cp_lowerdown,
+ ipv6cp_open,
+ ipv6cp_close,
+ ipv6cp_printpkt,
+ NULL,
+ 0,
+ "IPV6CP",
+ "IPV6",
+ ipv6cp_option_list,
+ ipv6_check_options,
+ ipv6_demand_conf,
+ ipv6_active_pkt
+};
+
+static void ipv6cp_clear_addrs __P((int, eui64_t, eui64_t));
+static void ipv6cp_script __P((char *));
+static void ipv6cp_script_done __P((void *));
+
+/*
+ * Lengths of configuration options.
+ */
+#define CILEN_VOID 2
+#define CILEN_COMPRESS 4 /* length for RFC2023 compress opt. */
+#define CILEN_IFACEID 10 /* RFC2472, interface identifier */
+
+#define CODENAME(x) ((x) == CONFACK ? "ACK" : \
+ (x) == CONFNAK ? "NAK" : "REJ")
+
+/*
+ * This state variable is used to ensure that we don't
+ * run an ipcp-up/down script while one is already running.
+ */
+static enum script_state {
+ s_down,
+ s_up,
+} ipv6cp_script_state;
+static pid_t ipv6cp_script_pid;
+
+/*
+ * setifaceid - set the interface identifiers manually
+ */
+static int
+setifaceid(argv)
+ char **argv;
+{
+ char *comma, *arg, c;
+ ipv6cp_options *wo = &ipv6cp_wantoptions[0];
+ struct in6_addr addr;
+ static int prio_local, prio_remote;
+
+#define VALIDID(a) ( (((a).s6_addr32[0] == 0) && ((a).s6_addr32[1] == 0)) && \
+ (((a).s6_addr32[2] != 0) || ((a).s6_addr32[3] != 0)) )
+
+ arg = *argv;
+ if ((comma = strchr(arg, ',')) == NULL)
+ comma = arg + strlen(arg);
+
+ /*
+ * If comma first character, then no local identifier
+ */
+ if (comma != arg) {
+ c = *comma;
+ *comma = '\0';
+
+ if (inet_pton(AF_INET6, arg, &addr) == 0 || !VALIDID(addr)) {
+ option_error("Illegal interface identifier (local): %s", arg);
+ return 0;
+ }
+
+ if (option_priority >= prio_local) {
+ eui64_copy(addr.s6_addr32[2], wo->ourid);
+ wo->opt_local = 1;
+ prio_local = option_priority;
+ }
+ *comma = c;
+ }
+
+ /*
+ * If comma last character, the no remote identifier
+ */
+ if (*comma != 0 && *++comma != '\0') {
+ if (inet_pton(AF_INET6, comma, &addr) == 0 || !VALIDID(addr)) {
+ option_error("Illegal interface identifier (remote): %s", comma);
+ return 0;
+ }
+ if (option_priority >= prio_remote) {
+ eui64_copy(addr.s6_addr32[2], wo->hisid);
+ wo->opt_remote = 1;
+ prio_remote = option_priority;
+ }
+ }
+
+ if (override_value("+ipv6", option_priority, option_source))
+ ipv6cp_protent.enabled_flag = 1;
+ return 1;
+}
+
+static void
+printifaceid(opt, printer, arg)
+ option_t *opt;
+ void (*printer) __P((void *, char *, ...));
+ void *arg;
+{
+ ipv6cp_options *wo = &ipv6cp_wantoptions[0];
+
+ if (wo->opt_local)
+ printer(arg, "%s", llv6_ntoa(wo->ourid));
+ printer(arg, ",");
+ if (wo->opt_remote)
+ printer(arg, "%s", llv6_ntoa(wo->hisid));
+}
+
+/*
+ * Make a string representation of a network address.
+ */
+char *
+llv6_ntoa(ifaceid)
+ eui64_t ifaceid;
+{
+ static char b[64];
+
+ sprintf(b, "fe80::%s", eui64_ntoa(ifaceid));
+ return b;
+}
+
+
+/*
+ * ipv6cp_init - Initialize IPV6CP.
+ */
+static void
+ipv6cp_init(unit)
+ int unit;
+{
+ fsm *f = &ipv6cp_fsm[unit];
+ ipv6cp_options *wo = &ipv6cp_wantoptions[unit];
+ ipv6cp_options *ao = &ipv6cp_allowoptions[unit];
+
+ f->unit = unit;
+ f->protocol = PPP_IPV6CP;
+ f->callbacks = &ipv6cp_callbacks;
+ fsm_init(&ipv6cp_fsm[unit]);
+
+ memset(wo, 0, sizeof(*wo));
+ memset(ao, 0, sizeof(*ao));
+
+ wo->accept_local = 1;
+ wo->neg_ifaceid = 1;
+ ao->neg_ifaceid = 1;
+
+#ifdef IPV6CP_COMP
+ wo->neg_vj = 1;
+ ao->neg_vj = 1;
+ wo->vj_protocol = IPV6CP_COMP;
+#endif
+
+}
+
+
+/*
+ * ipv6cp_open - IPV6CP is allowed to come up.
+ */
+static void
+ipv6cp_open(unit)
+ int unit;
+{
+ fsm_open(&ipv6cp_fsm[unit]);
+}
+
+
+/*
+ * ipv6cp_close - Take IPV6CP down.
+ */
+static void
+ipv6cp_close(unit, reason)
+ int unit;
+ char *reason;
+{
+ fsm_close(&ipv6cp_fsm[unit], reason);
+}
+
+
+/*
+ * ipv6cp_lowerup - The lower layer is up.
+ */
+static void
+ipv6cp_lowerup(unit)
+ int unit;
+{
+ fsm_lowerup(&ipv6cp_fsm[unit]);
+}
+
+
+/*
+ * ipv6cp_lowerdown - The lower layer is down.
+ */
+static void
+ipv6cp_lowerdown(unit)
+ int unit;
+{
+ fsm_lowerdown(&ipv6cp_fsm[unit]);
+}
+
+
+/*
+ * ipv6cp_input - Input IPV6CP packet.
+ */
+static void
+ipv6cp_input(unit, p, len)
+ int unit;
+ u_char *p;
+ int len;
+{
+ fsm_input(&ipv6cp_fsm[unit], p, len);
+}
+
+
+/*
+ * ipv6cp_protrej - A Protocol-Reject was received for IPV6CP.
+ *
+ * Pretend the lower layer went down, so we shut up.
+ */
+static void
+ipv6cp_protrej(unit)
+ int unit;
+{
+ fsm_lowerdown(&ipv6cp_fsm[unit]);
+}
+
+
+/*
+ * ipv6cp_resetci - Reset our CI.
+ */
+static void
+ipv6cp_resetci(f)
+ fsm *f;
+{
+ ipv6cp_options *wo = &ipv6cp_wantoptions[f->unit];
+ ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
+
+ wo->req_ifaceid = wo->neg_ifaceid && ipv6cp_allowoptions[f->unit].neg_ifaceid;
+
+ if (!wo->opt_local) {
+ eui64_magic_nz(wo->ourid);
+ }
+
+ *go = *wo;
+ eui64_zero(go->hisid); /* last proposed interface identifier */
+}
+
+
+/*
+ * ipv6cp_cilen - Return length of our CI.
+ */
+static int
+ipv6cp_cilen(f)
+ fsm *f;
+{
+ ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
+
+#define LENCIVJ(neg) (neg ? CILEN_COMPRESS : 0)
+#define LENCIIFACEID(neg) (neg ? CILEN_IFACEID : 0)
+
+ return (LENCIIFACEID(go->neg_ifaceid) +
+ LENCIVJ(go->neg_vj));
+}
+
+
+/*
+ * ipv6cp_addci - Add our desired CIs to a packet.
+ */
+static void
+ipv6cp_addci(f, ucp, lenp)
+ fsm *f;
+ u_char *ucp;
+ int *lenp;
+{
+ ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
+ int len = *lenp;
+
+#define ADDCIVJ(opt, neg, val) \
+ if (neg) { \
+ int vjlen = CILEN_COMPRESS; \
+ if (len >= vjlen) { \
+ PUTCHAR(opt, ucp); \
+ PUTCHAR(vjlen, ucp); \
+ PUTSHORT(val, ucp); \
+ len -= vjlen; \
+ } else \
+ neg = 0; \
+ }
+
+#define ADDCIIFACEID(opt, neg, val1) \
+ if (neg) { \
+ int idlen = CILEN_IFACEID; \
+ if (len >= idlen) { \
+ PUTCHAR(opt, ucp); \
+ PUTCHAR(idlen, ucp); \
+ eui64_put(val1, ucp); \
+ len -= idlen; \
+ } else \
+ neg = 0; \
+ }
+
+ ADDCIIFACEID(CI_IFACEID, go->neg_ifaceid, go->ourid);
+
+ ADDCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol);
+
+ *lenp -= len;
+}
+
+
+/*
+ * ipv6cp_ackci - Ack our CIs.
+ *
+ * Returns:
+ * 0 - Ack was bad.
+ * 1 - Ack was good.
+ */
+static int
+ipv6cp_ackci(f, p, len)
+ fsm *f;
+ u_char *p;
+ int len;
+{
+ ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
+ u_short cilen, citype, cishort;
+ eui64_t ifaceid;
+
+ /*
+ * CIs must be in exactly the same order that we sent...
+ * Check packet length and CI length at each step.
+ * If we find any deviations, then this packet is bad.
+ */
+
+#define ACKCIVJ(opt, neg, val) \
+ if (neg) { \
+ int vjlen = CILEN_COMPRESS; \
+ if ((len -= vjlen) < 0) \
+ goto bad; \
+ GETCHAR(citype, p); \
+ GETCHAR(cilen, p); \
+ if (cilen != vjlen || \
+ citype != opt) \
+ goto bad; \
+ GETSHORT(cishort, p); \
+ if (cishort != val) \
+ goto bad; \
+ }
+
+#define ACKCIIFACEID(opt, neg, val1) \
+ if (neg) { \
+ int idlen = CILEN_IFACEID; \
+ if ((len -= idlen) < 0) \
+ goto bad; \
+ GETCHAR(citype, p); \
+ GETCHAR(cilen, p); \
+ if (cilen != idlen || \
+ citype != opt) \
+ goto bad; \
+ eui64_get(ifaceid, p); \
+ if (! eui64_equals(val1, ifaceid)) \
+ goto bad; \
+ }
+
+ ACKCIIFACEID(CI_IFACEID, go->neg_ifaceid, go->ourid);
+
+ ACKCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol);
+
+ /*
+ * If there are any remaining CIs, then this packet is bad.
+ */
+ if (len != 0)
+ goto bad;
+ return (1);
+
+bad:
+ IPV6CPDEBUG(("ipv6cp_ackci: received bad Ack!"));
+ return (0);
+}
+
+/*
+ * ipv6cp_nakci - Peer has sent a NAK for some of our CIs.
+ * This should not modify any state if the Nak is bad
+ * or if IPV6CP is in the OPENED state.
+ *
+ * Returns:
+ * 0 - Nak was bad.
+ * 1 - Nak was good.
+ */
+static int
+ipv6cp_nakci(f, p, len)
+ fsm *f;
+ u_char *p;
+ int len;
+{
+ ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
+ u_char citype, cilen, *next;
+ u_short cishort;
+ eui64_t ifaceid;
+ ipv6cp_options no; /* options we've seen Naks for */
+ ipv6cp_options try; /* options to request next time */
+
+ BZERO(&no, sizeof(no));
+ try = *go;
+
+ /*
+ * Any Nak'd CIs must be in exactly the same order that we sent.
+ * Check packet length and CI length at each step.
+ * If we find any deviations, then this packet is bad.
+ */
+#define NAKCIIFACEID(opt, neg, code) \
+ if (go->neg && \
+ len >= (cilen = CILEN_IFACEID) && \
+ p[1] == cilen && \
+ p[0] == opt) { \
+ len -= cilen; \
+ INCPTR(2, p); \
+ eui64_get(ifaceid, p); \
+ no.neg = 1; \
+ code \
+ }
+
+#define NAKCIVJ(opt, neg, code) \
+ if (go->neg && \
+ ((cilen = p[1]) == CILEN_COMPRESS) && \
+ len >= cilen && \
+ p[0] == opt) { \
+ len -= cilen; \
+ INCPTR(2, p); \
+ GETSHORT(cishort, p); \
+ no.neg = 1; \
+ code \
+ }
+
+ /*
+ * Accept the peer's idea of {our,his} interface identifier, if different
+ * from our idea, only if the accept_{local,remote} flag is set.
+ */
+ NAKCIIFACEID(CI_IFACEID, neg_ifaceid,
+ if (go->accept_local) {
+ while (eui64_iszero(ifaceid) ||
+ eui64_equals(ifaceid, go->hisid)) /* bad luck */
+ eui64_magic(ifaceid);
+ try.ourid = ifaceid;
+ IPV6CPDEBUG(("local LL address %s", llv6_ntoa(ifaceid)));
+ }
+ );
+
+#ifdef IPV6CP_COMP
+ NAKCIVJ(CI_COMPRESSTYPE, neg_vj,
+ {
+ if (cishort == IPV6CP_COMP) {
+ try.vj_protocol = cishort;
+ } else {
+ try.neg_vj = 0;
+ }
+ }
+ );
+#else
+ NAKCIVJ(CI_COMPRESSTYPE, neg_vj,
+ {
+ try.neg_vj = 0;
+ }
+ );
+#endif
+
+ /*
+ * There may be remaining CIs, if the peer is requesting negotiation
+ * on an option that we didn't include in our request packet.
+ * If they want to negotiate about interface identifier, we comply.
+ * If they want us to ask for compression, we refuse.
+ */
+ while (len > CILEN_VOID) {
+ GETCHAR(citype, p);
+ GETCHAR(cilen, p);
+ if( (len -= cilen) < 0 )
+ goto bad;
+ next = p + cilen - 2;
+
+ switch (citype) {
+ case CI_COMPRESSTYPE:
+ if (go->neg_vj || no.neg_vj ||
+ (cilen != CILEN_COMPRESS))
+ goto bad;
+ no.neg_vj = 1;
+ break;
+ case CI_IFACEID:
+ if (go->neg_ifaceid || no.neg_ifaceid || cilen != CILEN_IFACEID)
+ goto bad;
+ try.neg_ifaceid = 1;
+ eui64_get(ifaceid, p);
+ if (go->accept_local) {
+ while (eui64_iszero(ifaceid) ||
+ eui64_equals(ifaceid, go->hisid)) /* bad luck */
+ eui64_magic(ifaceid);
+ try.ourid = ifaceid;
+ }
+ no.neg_ifaceid = 1;
+ break;
+ }
+ p = next;
+ }
+
+ /* If there is still anything left, this packet is bad. */
+ if (len != 0)
+ goto bad;
+
+ /*
+ * OK, the Nak is good. Now we can update state.
+ */
+ if (f->state != OPENED)
+ *go = try;
+
+ return 1;
+
+bad:
+ IPV6CPDEBUG(("ipv6cp_nakci: received bad Nak!"));
+ return 0;
+}
+
+
+/*
+ * ipv6cp_rejci - Reject some of our CIs.
+ */
+static int
+ipv6cp_rejci(f, p, len)
+ fsm *f;
+ u_char *p;
+ int len;
+{
+ ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
+ u_char cilen;
+ u_short cishort;
+ eui64_t ifaceid;
+ ipv6cp_options try; /* options to request next time */
+
+ try = *go;
+ /*
+ * Any Rejected CIs must be in exactly the same order that we sent.
+ * Check packet length and CI length at each step.
+ * If we find any deviations, then this packet is bad.
+ */
+#define REJCIIFACEID(opt, neg, val1) \
+ if (go->neg && \
+ len >= (cilen = CILEN_IFACEID) && \
+ p[1] == cilen && \
+ p[0] == opt) { \
+ len -= cilen; \
+ INCPTR(2, p); \
+ eui64_get(ifaceid, p); \
+ /* Check rejected value. */ \
+ if (! eui64_equals(ifaceid, val1)) \
+ goto bad; \
+ try.neg = 0; \
+ }
+
+#define REJCIVJ(opt, neg, val) \
+ if (go->neg && \
+ p[1] == CILEN_COMPRESS && \
+ len >= p[1] && \
+ p[0] == opt) { \
+ len -= p[1]; \
+ INCPTR(2, p); \
+ GETSHORT(cishort, p); \
+ /* Check rejected value. */ \
+ if (cishort != val) \
+ goto bad; \
+ try.neg = 0; \
+ }
+
+ REJCIIFACEID(CI_IFACEID, neg_ifaceid, go->ourid);
+
+ REJCIVJ(CI_COMPRESSTYPE, neg_vj, go->vj_protocol);
+
+ /*
+ * If there are any remaining CIs, then this packet is bad.
+ */
+ if (len != 0)
+ goto bad;
+ /*
+ * Now we can update state.
+ */
+ if (f->state != OPENED)
+ *go = try;
+ return 1;
+
+bad:
+ IPV6CPDEBUG(("ipv6cp_rejci: received bad Reject!"));
+ return 0;
+}
+
+
+/*
+ * ipv6cp_reqci - Check the peer's requested CIs and send appropriate response.
+ *
+ * Returns: CONFACK, CONFNAK or CONFREJ and input packet modified
+ * appropriately. If reject_if_disagree is non-zero, doesn't return
+ * CONFNAK; returns CONFREJ if it can't return CONFACK.
+ */
+static int
+ipv6cp_reqci(f, inp, len, reject_if_disagree)
+ fsm *f;
+ u_char *inp; /* Requested CIs */
+ int *len; /* Length of requested CIs */
+ int reject_if_disagree;
+{
+ ipv6cp_options *wo = &ipv6cp_wantoptions[f->unit];
+ ipv6cp_options *ho = &ipv6cp_hisoptions[f->unit];
+ ipv6cp_options *ao = &ipv6cp_allowoptions[f->unit];
+ ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
+ u_char *cip, *next; /* Pointer to current and next CIs */
+ u_short cilen, citype; /* Parsed len, type */
+ u_short cishort; /* Parsed short value */
+ eui64_t ifaceid; /* Parsed interface identifier */
+ int rc = CONFACK; /* Final packet return code */
+ int orc; /* Individual option return code */
+ u_char *p; /* Pointer to next char to parse */
+ u_char *ucp = inp; /* Pointer to current output char */
+ int l = *len; /* Length left */
+
+ /*
+ * Reset all his options.
+ */
+ BZERO(ho, sizeof(*ho));
+
+ /*
+ * Process all his options.
+ */
+ next = inp;
+ while (l) {
+ orc = CONFACK; /* Assume success */
+ cip = p = next; /* Remember begining of CI */
+ if (l < 2 || /* Not enough data for CI header or */
+ p[1] < 2 || /* CI length too small or */
+ p[1] > l) { /* CI length too big? */
+ IPV6CPDEBUG(("ipv6cp_reqci: bad CI length!"));
+ orc = CONFREJ; /* Reject bad CI */
+ cilen = l; /* Reject till end of packet */
+ l = 0; /* Don't loop again */
+ goto endswitch;
+ }
+ GETCHAR(citype, p); /* Parse CI type */
+ GETCHAR(cilen, p); /* Parse CI length */
+ l -= cilen; /* Adjust remaining length */
+ next += cilen; /* Step to next CI */
+
+ switch (citype) { /* Check CI type */
+ case CI_IFACEID:
+ IPV6CPDEBUG(("ipv6cp: received interface identifier "));
+
+ if (!ao->neg_ifaceid ||
+ cilen != CILEN_IFACEID) { /* Check CI length */
+ orc = CONFREJ; /* Reject CI */
+ break;
+ }
+
+ /*
+ * If he has no interface identifier, or if we both have same
+ * identifier then NAK it with new idea.
+ * In particular, if we don't know his identifier, but he does,
+ * then accept it.
+ */
+ eui64_get(ifaceid, p);
+ IPV6CPDEBUG(("(%s)", llv6_ntoa(ifaceid)));
+ if (eui64_iszero(ifaceid) && eui64_iszero(go->ourid)) {
+ orc = CONFREJ; /* Reject CI */
+ break;
+ }
+ if (!eui64_iszero(wo->hisid) &&
+ !eui64_equals(ifaceid, wo->hisid) &&
+ eui64_iszero(go->hisid)) {
+
+ orc = CONFNAK;
+ ifaceid = wo->hisid;
+ go->hisid = ifaceid;
+ DECPTR(sizeof(ifaceid), p);
+ eui64_put(ifaceid, p);
+ } else
+ if (eui64_iszero(ifaceid) || eui64_equals(ifaceid, go->ourid)) {
+ orc = CONFNAK;
+ if (eui64_iszero(go->hisid)) /* first time, try option */
+ ifaceid = wo->hisid;
+ while (eui64_iszero(ifaceid) ||
+ eui64_equals(ifaceid, go->ourid)) /* bad luck */
+ eui64_magic(ifaceid);
+ go->hisid = ifaceid;
+ DECPTR(sizeof(ifaceid), p);
+ eui64_put(ifaceid, p);
+ }
+
+ ho->neg_ifaceid = 1;
+ ho->hisid = ifaceid;
+ break;
+
+ case CI_COMPRESSTYPE:
+ IPV6CPDEBUG(("ipv6cp: received COMPRESSTYPE "));
+ if (!ao->neg_vj ||
+ (cilen != CILEN_COMPRESS)) {
+ orc = CONFREJ;
+ break;
+ }
+ GETSHORT(cishort, p);
+ IPV6CPDEBUG(("(%d)", cishort));
+
+#ifdef IPV6CP_COMP
+ if (!(cishort == IPV6CP_COMP)) {
+ orc = CONFREJ;
+ break;
+ }
+
+ ho->neg_vj = 1;
+ ho->vj_protocol = cishort;
+ break;
+#else
+ orc = CONFREJ;
+ break;
+#endif
+
+ default:
+ orc = CONFREJ;
+ break;
+ }
+
+endswitch:
+ IPV6CPDEBUG((" (%s)\n", CODENAME(orc)));
+
+ if (orc == CONFACK && /* Good CI */
+ rc != CONFACK) /* but prior CI wasnt? */
+ continue; /* Don't send this one */
+
+ if (orc == CONFNAK) { /* Nak this CI? */
+ if (reject_if_disagree) /* Getting fed up with sending NAKs? */
+ orc = CONFREJ; /* Get tough if so */
+ else {
+ if (rc == CONFREJ) /* Rejecting prior CI? */
+ continue; /* Don't send this one */
+ if (rc == CONFACK) { /* Ack'd all prior CIs? */
+ rc = CONFNAK; /* Not anymore... */
+ ucp = inp; /* Backup */
+ }
+ }
+ }
+
+ if (orc == CONFREJ && /* Reject this CI */
+ rc != CONFREJ) { /* but no prior ones? */
+ rc = CONFREJ;
+ ucp = inp; /* Backup */
+ }
+
+ /* Need to move CI? */
+ if (ucp != cip)
+ BCOPY(cip, ucp, cilen); /* Move it */
+
+ /* Update output pointer */
+ INCPTR(cilen, ucp);
+ }
+
+ /*
+ * If we aren't rejecting this packet, and we want to negotiate
+ * their identifier and they didn't send their identifier, then we
+ * send a NAK with a CI_IFACEID option appended. We assume the
+ * input buffer is long enough that we can append the extra
+ * option safely.
+ */
+ if (rc != CONFREJ && !ho->neg_ifaceid &&
+ wo->req_ifaceid && !reject_if_disagree) {
+ if (rc == CONFACK) {
+ rc = CONFNAK;
+ ucp = inp; /* reset pointer */
+ wo->req_ifaceid = 0; /* don't ask again */
+ }
+ PUTCHAR(CI_IFACEID, ucp);
+ PUTCHAR(CILEN_IFACEID, ucp);
+ eui64_put(wo->hisid, ucp);
+ }
+
+ *len = ucp - inp; /* Compute output length */
+ IPV6CPDEBUG(("ipv6cp: returning Configure-%s", CODENAME(rc)));
+ return (rc); /* Return final code */
+}
+
+
+/*
+ * ipv6_check_options - check that any IP-related options are OK,
+ * and assign appropriate defaults.
+ */
+static void
+ipv6_check_options()
+{
+ ipv6cp_options *wo = &ipv6cp_wantoptions[0];
+
+ if (!ipv6cp_protent.enabled_flag)
+ return;
+
+#if defined(SOL2)
+ /*
+ * Persistent link-local id is only used when user has not explicitly
+ * configure/hard-code the id
+ */
+ if ((wo->use_persistent) && (!wo->opt_local) && (!wo->opt_remote)) {
+
+ /*
+ * On systems where there are no Ethernet interfaces used, there
+ * may be other ways to obtain a persistent id. Right now, it
+ * will fall back to using magic [see eui64_magic] below when
+ * an EUI-48 from MAC address can't be obtained. Other possibilities
+ * include obtaining EEPROM serial numbers, or some other unique
+ * yet persistent number. On Sparc platforms, this is possible,
+ * but too bad there's no standards yet for x86 machines.
+ */
+ if (ether_to_eui64(&wo->ourid)) {
+ wo->opt_local = 1;
+ }
+ }
+#endif
+
+ if (!wo->opt_local) { /* init interface identifier */
+ if (wo->use_ip && eui64_iszero(wo->ourid)) {
+ eui64_setlo32(wo->ourid, ntohl(ipcp_wantoptions[0].ouraddr));
+ if (!eui64_iszero(wo->ourid))
+ wo->opt_local = 1;
+ }
+
+ while (eui64_iszero(wo->ourid))
+ eui64_magic(wo->ourid);
+ }
+
+ if (!wo->opt_remote) {
+ if (wo->use_ip && eui64_iszero(wo->hisid)) {
+ eui64_setlo32(wo->hisid, ntohl(ipcp_wantoptions[0].hisaddr));
+ if (!eui64_iszero(wo->hisid))
+ wo->opt_remote = 1;
+ }
+ }
+
+ if (demand && (eui64_iszero(wo->ourid) || eui64_iszero(wo->hisid))) {
+ option_error("local/remote LL address required for demand-dialling\n");
+ exit(1);
+ }
+}
+
+
+/*
+ * ipv6_demand_conf - configure the interface as though
+ * IPV6CP were up, for use with dial-on-demand.
+ */
+static int
+ipv6_demand_conf(u)
+ int u;
+{
+ ipv6cp_options *wo = &ipv6cp_wantoptions[u];
+
+#if defined(__linux__) || defined(SOL2) || (defined(SVR4) && (defined(SNI) || defined(__USLC__)))
+#if defined(SOL2)
+ if (!sif6up(u))
+ return 0;
+#else
+ if (!sifup(u))
+ return 0;
+#endif /* defined(SOL2) */
+#endif
+ if (!sif6addr(u, wo->ourid, wo->hisid))
+ return 0;
+#if !defined(__linux__) && !(defined(SVR4) && (defined(SNI) || defined(__USLC__)))
+ if (!sifup(u))
+ return 0;
+#endif
+ if (!sifnpmode(u, PPP_IPV6, NPMODE_QUEUE))
+ return 0;
+
+ notice("ipv6_demand_conf");
+ notice("local LL address %s", llv6_ntoa(wo->ourid));
+ notice("remote LL address %s", llv6_ntoa(wo->hisid));
+
+ return 1;
+}
+
+
+/*
+ * ipv6cp_up - IPV6CP has come UP.
+ *
+ * Configure the IPv6 network interface appropriately and bring it up.
+ */
+static void
+ipv6cp_up(f)
+ fsm *f;
+{
+ ipv6cp_options *ho = &ipv6cp_hisoptions[f->unit];
+ ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
+ ipv6cp_options *wo = &ipv6cp_wantoptions[f->unit];
+
+ IPV6CPDEBUG(("ipv6cp: up"));
+
+ /*
+ * We must have a non-zero LL address for both ends of the link.
+ */
+ if (!ho->neg_ifaceid)
+ ho->hisid = wo->hisid;
+
+ if(!no_ifaceid_neg) {
+ if (eui64_iszero(ho->hisid)) {
+ error("Could not determine remote LL address");
+ ipv6cp_close(f->unit, "Could not determine remote LL address");
+ return;
+ }
+ if (eui64_iszero(go->ourid)) {
+ error("Could not determine local LL address");
+ ipv6cp_close(f->unit, "Could not determine local LL address");
+ return;
+ }
+ if (eui64_equals(go->ourid, ho->hisid)) {
+ error("local and remote LL addresses are equal");
+ ipv6cp_close(f->unit, "local and remote LL addresses are equal");
+ return;
+ }
+ }
+ script_setenv("LLLOCAL", llv6_ntoa(go->ourid), 0);
+ script_setenv("LLREMOTE", llv6_ntoa(ho->hisid), 0);
+
+#ifdef IPV6CP_COMP
+ /* set tcp compression */
+ sif6comp(f->unit, ho->neg_vj);
+#endif
+
+ /*
+ * If we are doing dial-on-demand, the interface is already
+ * configured, so we put out any saved-up packets, then set the
+ * interface to pass IPv6 packets.
+ */
+ if (demand) {
+ if (! eui64_equals(go->ourid, wo->ourid) ||
+ ! eui64_equals(ho->hisid, wo->hisid)) {
+ if (! eui64_equals(go->ourid, wo->ourid))
+ warn("Local LL address changed to %s",
+ llv6_ntoa(go->ourid));
+ if (! eui64_equals(ho->hisid, wo->hisid))
+ warn("Remote LL address changed to %s",
+ llv6_ntoa(ho->hisid));
+ ipv6cp_clear_addrs(f->unit, go->ourid, ho->hisid);
+
+ /* Set the interface to the new addresses */
+ if (!sif6addr(f->unit, go->ourid, ho->hisid)) {
+ if (debug)
+ warn("sif6addr failed");
+ ipv6cp_close(f->unit, "Interface configuration failed");
+ return;
+ }
+
+ }
+ demand_rexmit(PPP_IPV6);
+ sifnpmode(f->unit, PPP_IPV6, NPMODE_PASS);
+
+ } else {
+ /*
+ * Set LL addresses
+ */
+#if !defined(__linux__) && !defined(SOL2) && !(defined(SVR4) && (defined(SNI) || defined(__USLC__)))
+ if (!sif6addr(f->unit, go->ourid, ho->hisid)) {
+ if (debug)
+ warn("sif6addr failed");
+ ipv6cp_close(f->unit, "Interface configuration failed");
+ return;
+ }
+#endif
+
+ /* bring the interface up for IPv6 */
+#if defined(SOL2)
+ if (!sif6up(f->unit)) {
+ if (debug)
+ warn("sifup failed (IPV6)");
+ ipv6cp_close(f->unit, "Interface configuration failed");
+ return;
+ }
+#else
+ if (!sifup(f->unit)) {
+ if (debug)
+ warn("sifup failed (IPV6)");
+ ipv6cp_close(f->unit, "Interface configuration failed");
+ return;
+ }
+#endif /* defined(SOL2) */
+
+#if defined(__linux__) || defined(SOL2) || (defined(SVR4) && (defined(SNI) || defined(__USLC__)))
+ if (!sif6addr(f->unit, go->ourid, ho->hisid)) {
+ if (debug)
+ warn("sif6addr failed");
+ ipv6cp_close(f->unit, "Interface configuration failed");
+ return;
+ }
+#endif
+ sifnpmode(f->unit, PPP_IPV6, NPMODE_PASS);
+
+ notice("local LL address %s", llv6_ntoa(go->ourid));
+ notice("remote LL address %s", llv6_ntoa(ho->hisid));
+ }
+
+ np_up(f->unit, PPP_IPV6);
+ ipv6cp_is_up = 1;
+
+ /*
+ * Execute the ipv6-up script, like this:
+ * /etc/ppp/ipv6-up interface tty speed local-LL remote-LL
+ */
+ if (ipv6cp_script_state == s_down && ipv6cp_script_pid == 0) {
+ ipv6cp_script_state = s_up;
+ ipv6cp_script(_PATH_IPV6UP);
+ }
+}
+
+
+/*
+ * ipv6cp_down - IPV6CP has gone DOWN.
+ *
+ * Take the IPv6 network interface down, clear its addresses
+ * and delete routes through it.
+ */
+static void
+ipv6cp_down(f)
+ fsm *f;
+{
+ IPV6CPDEBUG(("ipv6cp: down"));
+ update_link_stats(f->unit);
+ if (ipv6cp_is_up) {
+ ipv6cp_is_up = 0;
+ np_down(f->unit, PPP_IPV6);
+ }
+#ifdef IPV6CP_COMP
+ sif6comp(f->unit, 0);
+#endif
+
+ /*
+ * If we are doing dial-on-demand, set the interface
+ * to queue up outgoing packets (for now).
+ */
+ if (demand) {
+ sifnpmode(f->unit, PPP_IPV6, NPMODE_QUEUE);
+ } else {
+ sifnpmode(f->unit, PPP_IPV6, NPMODE_DROP);
+#if !defined(__linux__) && !(defined(SVR4) && (defined(SNI) || defined(__USLC)))
+#if defined(SOL2)
+ sif6down(f->unit);
+#else
+ sifdown(f->unit);
+#endif /* defined(SOL2) */
+#endif
+ ipv6cp_clear_addrs(f->unit,
+ ipv6cp_gotoptions[f->unit].ourid,
+ ipv6cp_hisoptions[f->unit].hisid);
+#if defined(__linux__) || (defined(SVR4) && (defined(SNI) || defined(__USLC)))
+ sifdown(f->unit);
+#endif
+ }
+
+ /* Execute the ipv6-down script */
+ if (ipv6cp_script_state == s_up && ipv6cp_script_pid == 0) {
+ ipv6cp_script_state = s_down;
+ ipv6cp_script(_PATH_IPV6DOWN);
+ }
+}
+
+
+/*
+ * ipv6cp_clear_addrs() - clear the interface addresses, routes,
+ * proxy neighbour discovery entries, etc.
+ */
+static void
+ipv6cp_clear_addrs(unit, ourid, hisid)
+ int unit;
+ eui64_t ourid;
+ eui64_t hisid;
+{
+ cif6addr(unit, ourid, hisid);
+}
+
+
+/*
+ * ipv6cp_finished - possibly shut down the lower layers.
+ */
+static void
+ipv6cp_finished(f)
+ fsm *f;
+{
+ np_finished(f->unit, PPP_IPV6);
+}
+
+
+/*
+ * ipv6cp_script_done - called when the ipv6-up or ipv6-down script
+ * has finished.
+ */
+static void
+ipv6cp_script_done(arg)
+ void *arg;
+{
+ ipv6cp_script_pid = 0;
+ switch (ipv6cp_script_state) {
+ case s_up:
+ if (ipv6cp_fsm[0].state != OPENED) {
+ ipv6cp_script_state = s_down;
+ ipv6cp_script(_PATH_IPV6DOWN);
+ }
+ break;
+ case s_down:
+ if (ipv6cp_fsm[0].state == OPENED) {
+ ipv6cp_script_state = s_up;
+ ipv6cp_script(_PATH_IPV6UP);
+ }
+ break;
+ }
+}
+
+
+/*
+ * ipv6cp_script - Execute a script with arguments
+ * interface-name tty-name speed local-LL remote-LL.
+ */
+static void
+ipv6cp_script(script)
+ char *script;
+{
+ char strspeed[32], strlocal[32], strremote[32];
+ char *argv[8];
+
+ sprintf(strspeed, "%d", baud_rate);
+ strcpy(strlocal, llv6_ntoa(ipv6cp_gotoptions[0].ourid));
+ strcpy(strremote, llv6_ntoa(ipv6cp_hisoptions[0].hisid));
+
+ argv[0] = script;
+ argv[1] = ifname;
+ argv[2] = devnam;
+ argv[3] = strspeed;
+ argv[4] = strlocal;
+ argv[5] = strremote;
+ argv[6] = ipparam;
+ argv[7] = NULL;
+
+ ipv6cp_script_pid = run_program(script, argv, 0, ipv6cp_script_done, NULL);
+}
+
+/*
+ * ipv6cp_printpkt - print the contents of an IPV6CP packet.
+ */
+static char *ipv6cp_codenames[] = {
+ "ConfReq", "ConfAck", "ConfNak", "ConfRej",
+ "TermReq", "TermAck", "CodeRej"
+};
+
+static int
+ipv6cp_printpkt(p, plen, printer, arg)
+ u_char *p;
+ int plen;
+ void (*printer) __P((void *, char *, ...));
+ void *arg;
+{
+ int code, id, len, olen;
+ u_char *pstart, *optend;
+ u_short cishort;
+ eui64_t ifaceid;
+
+ if (plen < HEADERLEN)
+ return 0;
+ pstart = p;
+ GETCHAR(code, p);
+ GETCHAR(id, p);
+ GETSHORT(len, p);
+ if (len < HEADERLEN || len > plen)
+ return 0;
+
+ if (code >= 1 && code <= sizeof(ipv6cp_codenames) / sizeof(char *))
+ printer(arg, " %s", ipv6cp_codenames[code-1]);
+ else
+ printer(arg, " code=0x%x", code);
+ printer(arg, " id=0x%x", id);
+ len -= HEADERLEN;
+ switch (code) {
+ case CONFREQ:
+ case CONFACK:
+ case CONFNAK:
+ case CONFREJ:
+ /* print option list */
+ while (len >= 2) {
+ GETCHAR(code, p);
+ GETCHAR(olen, p);
+ p -= 2;
+ if (olen < 2 || olen > len) {
+ break;
+ }
+ printer(arg, " <");
+ len -= olen;
+ optend = p + olen;
+ switch (code) {
+ case CI_COMPRESSTYPE:
+ if (olen >= CILEN_COMPRESS) {
+ p += 2;
+ GETSHORT(cishort, p);
+ printer(arg, "compress ");
+ printer(arg, "0x%x", cishort);
+ }
+ break;
+ case CI_IFACEID:
+ if (olen == CILEN_IFACEID) {
+ p += 2;
+ eui64_get(ifaceid, p);
+ printer(arg, "addr %s", llv6_ntoa(ifaceid));
+ }
+ break;
+ }
+ while (p < optend) {
+ GETCHAR(code, p);
+ printer(arg, " %.2x", code);
+ }
+ printer(arg, ">");
+ }
+ break;
+
+ case TERMACK:
+ case TERMREQ:
+ if (len > 0 && *p >= ' ' && *p < 0x7f) {
+ printer(arg, " ");
+ print_string((char *)p, len, printer, arg);
+ p += len;
+ len = 0;
+ }
+ break;
+ }
+
+ /* print the rest of the bytes in the packet */
+ for (; len > 0; --len) {
+ GETCHAR(code, p);
+ printer(arg, " %.2x", code);
+ }
+
+ return p - pstart;
+}
+
+/*
+ * ipv6_active_pkt - see if this IP packet is worth bringing the link up for.
+ * We don't bring the link up for IP fragments or for TCP FIN packets
+ * with no data.
+ */
+#define IP6_HDRLEN 40 /* bytes */
+#define IP6_NHDR_FRAG 44 /* fragment IPv6 header */
+#define IPPROTO_TCP 6
+#define TCP_HDRLEN 20
+#define TH_FIN 0x01
+
+/*
+ * We use these macros because the IP header may be at an odd address,
+ * and some compilers might use word loads to get th_off or ip_hl.
+ */
+
+#define get_ip6nh(x) (((unsigned char *)(x))[6])
+#define get_tcpoff(x) (((unsigned char *)(x))[12] >> 4)
+#define get_tcpflags(x) (((unsigned char *)(x))[13])
+
+static int
+ipv6_active_pkt(pkt, len)
+ u_char *pkt;
+ int len;
+{
+ u_char *tcp;
+
+ len -= PPP_HDRLEN;
+ pkt += PPP_HDRLEN;
+ if (len < IP6_HDRLEN)
+ return 0;
+ if (get_ip6nh(pkt) == IP6_NHDR_FRAG)
+ return 0;
+ if (get_ip6nh(pkt) != IPPROTO_TCP)
+ return 1;
+ if (len < IP6_HDRLEN + TCP_HDRLEN)
+ return 0;
+ tcp = pkt + IP6_HDRLEN;
+ if ((get_tcpflags(tcp) & TH_FIN) != 0 && len == IP6_HDRLEN + get_tcpoff(tcp) * 4)
+ return 0;
+ return 1;
+}
diff --git a/mdk-stage1/ppp/pppd/ipv6cp.h b/mdk-stage1/ppp/pppd/ipv6cp.h
new file mode 100644
index 000000000..eba75465c
--- /dev/null
+++ b/mdk-stage1/ppp/pppd/ipv6cp.h
@@ -0,0 +1,126 @@
+/*
+ ipv6cp.h - PPP IPV6 Control Protocol.
+ Copyright (C) 1999 Tommi Komulainen <Tommi.Komulainen@iki.fi>
+
+ Redistribution and use in source and binary forms are permitted
+ provided that the above copyright notice and this paragraph are
+ duplicated in all such forms. The name of the author may not be
+ used to endorse or promote products derived from this software
+ without specific prior written permission.
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+*/
+
+/* Original version, based on RFC2023 :
+
+ Copyright (c) 1995, 1996, 1997 Francis.Dupont@inria.fr, INRIA Rocquencourt,
+ Alain.Durand@imag.fr, IMAG,
+ Jean-Luc.Richier@imag.fr, IMAG-LSR.
+
+ Copyright (c) 1998, 1999 Francis.Dupont@inria.fr, GIE DYADE,
+ Alain.Durand@imag.fr, IMAG,
+ Jean-Luc.Richier@imag.fr, IMAG-LSR.
+
+ Ce travail a été fait au sein du GIE DYADE (Groupement d'Intérêt
+ Économique ayant pour membres BULL S.A. et l'INRIA).
+
+ Ce logiciel informatique est disponible aux conditions
+ usuelles dans la recherche, c'est-à-dire qu'il peut
+ être utilisé, copié, modifié, distribué à l'unique
+ condition que ce texte soit conservé afin que
+ l'origine de ce logiciel soit reconnue.
+
+ Le nom de l'Institut National de Recherche en Informatique
+ et en Automatique (INRIA), de l'IMAG, ou d'une personne morale
+ ou physique ayant participé à l'élaboration de ce logiciel ne peut
+ être utilisé sans son accord préalable explicite.
+
+ Ce logiciel est fourni tel quel sans aucune garantie,
+ support ou responsabilité d'aucune sorte.
+ Ce logiciel est dérivé de sources d'origine
+ "University of California at Berkeley" et
+ "Digital Equipment Corporation" couvertes par des copyrights.
+
+ L'Institut d'Informatique et de Mathématiques Appliquées de Grenoble (IMAG)
+ est une fédération d'unités mixtes de recherche du CNRS, de l'Institut National
+ Polytechnique de Grenoble et de l'Université Joseph Fourier regroupant
+ sept laboratoires dont le laboratoire Logiciels, Systèmes, Réseaux (LSR).
+
+ This work has been done in the context of GIE DYADE (joint R & D venture
+ between BULL S.A. and INRIA).
+
+ This software is available with usual "research" terms
+ with the aim of retain credits of the software.
+ Permission to use, copy, modify and distribute this software for any
+ purpose and without fee is hereby granted, provided that the above
+ copyright notice and this permission notice appear in all copies,
+ and the name of INRIA, IMAG, or any contributor not be used in advertising
+ or publicity pertaining to this material without the prior explicit
+ permission. The software is provided "as is" without any
+ warranties, support or liabilities of any kind.
+ This software is derived from source code from
+ "University of California at Berkeley" and
+ "Digital Equipment Corporation" protected by copyrights.
+
+ Grenoble's Institute of Computer Science and Applied Mathematics (IMAG)
+ is a federation of seven research units funded by the CNRS, National
+ Polytechnic Institute of Grenoble and University Joseph Fourier.
+ The research unit in Software, Systems, Networks (LSR) is member of IMAG.
+*/
+
+/*
+ * Derived from :
+ *
+ *
+ * ipcp.h - IP Control Protocol definitions.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id: ipv6cp.h 215411 2007-04-25 12:26:16Z pixel $
+ */
+
+/*
+ * Options.
+ */
+#define CI_IFACEID 1 /* Interface Identifier */
+#define CI_COMPRESSTYPE 2 /* Compression Type */
+
+/* No compression types yet defined.
+ *#define IPV6CP_COMP 0x004f
+ */
+typedef struct ipv6cp_options {
+ int neg_ifaceid; /* Negotiate interface identifier? */
+ int req_ifaceid; /* Ask peer to send interface identifier? */
+ int accept_local; /* accept peer's value for iface id? */
+ int opt_local; /* ourtoken set by option */
+ int opt_remote; /* histoken set by option */
+ int use_ip; /* use IP as interface identifier */
+#if defined(SOL2)
+ int use_persistent; /* use uniquely persistent value for address */
+#endif /* defined(SOL2) */
+ int neg_vj; /* Van Jacobson Compression? */
+ u_short vj_protocol; /* protocol value to use in VJ option */
+ eui64_t ourid, hisid; /* Interface identifiers */
+} ipv6cp_options;
+
+extern fsm ipv6cp_fsm[];
+extern ipv6cp_options ipv6cp_wantoptions[];
+extern ipv6cp_options ipv6cp_gotoptions[];
+extern ipv6cp_options ipv6cp_allowoptions[];
+extern ipv6cp_options ipv6cp_hisoptions[];
+
+extern struct protent ipv6cp_protent;
diff --git a/mdk-stage1/ppp/pppd/ipxcp.c b/mdk-stage1/ppp/pppd/ipxcp.c
new file mode 100644
index 000000000..30f3f2028
--- /dev/null
+++ b/mdk-stage1/ppp/pppd/ipxcp.c
@@ -0,0 +1,1570 @@
+/*
+ * ipxcp.c - PPP IPX Control Protocol.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifdef IPX_CHANGE
+
+#define RCSID "$Id: ipxcp.c 195720 2001-06-11 11:44:34Z gc $"
+
+/*
+ * TODO:
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#include "pppd.h"
+#include "fsm.h"
+#include "ipxcp.h"
+#include "pathnames.h"
+#include "magic.h"
+
+static const char rcsid[] = RCSID;
+
+/* global vars */
+ipxcp_options ipxcp_wantoptions[NUM_PPP]; /* Options that we want to request */
+ipxcp_options ipxcp_gotoptions[NUM_PPP]; /* Options that peer ack'd */
+ipxcp_options ipxcp_allowoptions[NUM_PPP]; /* Options we allow peer to request */
+ipxcp_options ipxcp_hisoptions[NUM_PPP]; /* Options that we ack'd */
+
+#define wo (&ipxcp_wantoptions[0])
+#define ao (&ipxcp_allowoptions[0])
+#define go (&ipxcp_gotoptions[0])
+#define ho (&ipxcp_hisoptions[0])
+
+/*
+ * Callbacks for fsm code. (CI = Configuration Information)
+ */
+static void ipxcp_resetci __P((fsm *)); /* Reset our CI */
+static int ipxcp_cilen __P((fsm *)); /* Return length of our CI */
+static void ipxcp_addci __P((fsm *, u_char *, int *)); /* Add our CI */
+static int ipxcp_ackci __P((fsm *, u_char *, int)); /* Peer ack'd our CI */
+static int ipxcp_nakci __P((fsm *, u_char *, int)); /* Peer nak'd our CI */
+static int ipxcp_rejci __P((fsm *, u_char *, int)); /* Peer rej'd our CI */
+static int ipxcp_reqci __P((fsm *, u_char *, int *, int)); /* Rcv CI */
+static void ipxcp_up __P((fsm *)); /* We're UP */
+static void ipxcp_down __P((fsm *)); /* We're DOWN */
+static void ipxcp_finished __P((fsm *)); /* Don't need lower layer */
+static void ipxcp_script __P((fsm *, char *)); /* Run an up/down script */
+
+fsm ipxcp_fsm[NUM_PPP]; /* IPXCP fsm structure */
+
+static fsm_callbacks ipxcp_callbacks = { /* IPXCP callback routines */
+ ipxcp_resetci, /* Reset our Configuration Information */
+ ipxcp_cilen, /* Length of our Configuration Information */
+ ipxcp_addci, /* Add our Configuration Information */
+ ipxcp_ackci, /* ACK our Configuration Information */
+ ipxcp_nakci, /* NAK our Configuration Information */
+ ipxcp_rejci, /* Reject our Configuration Information */
+ ipxcp_reqci, /* Request peer's Configuration Information */
+ ipxcp_up, /* Called when fsm reaches OPENED state */
+ ipxcp_down, /* Called when fsm leaves OPENED state */
+ NULL, /* Called when we want the lower layer up */
+ ipxcp_finished, /* Called when we want the lower layer down */
+ NULL, /* Called when Protocol-Reject received */
+ NULL, /* Retransmission is necessary */
+ NULL, /* Called to handle protocol-specific codes */
+ "IPXCP" /* String name of protocol */
+};
+
+/*
+ * Command-line options.
+ */
+static int setipxnode __P((char **));
+static void printipxnode __P((option_t *,
+ void (*)(void *, char *, ...), void *));
+static int setipxname __P((char **));
+
+static option_t ipxcp_option_list[] = {
+ { "ipx", o_bool, &ipxcp_protent.enabled_flag,
+ "Enable IPXCP (and IPX)", OPT_PRIO | 1 },
+ { "+ipx", o_bool, &ipxcp_protent.enabled_flag,
+ "Enable IPXCP (and IPX)", OPT_PRIOSUB | OPT_ALIAS | 1 },
+ { "noipx", o_bool, &ipxcp_protent.enabled_flag,
+ "Disable IPXCP (and IPX)", OPT_PRIOSUB },
+ { "-ipx", o_bool, &ipxcp_protent.enabled_flag,
+ "Disable IPXCP (and IPX)", OPT_PRIOSUB | OPT_ALIAS },
+
+ { "ipx-network", o_uint32, &ipxcp_wantoptions[0].our_network,
+ "Set our IPX network number", OPT_PRIO, &ipxcp_wantoptions[0].neg_nn },
+
+ { "ipxcp-accept-network", o_bool, &ipxcp_wantoptions[0].accept_network,
+ "Accept peer IPX network number", 1,
+ &ipxcp_allowoptions[0].accept_network },
+
+ { "ipx-node", o_special, (void *)setipxnode,
+ "Set IPX node number", OPT_A2PRINTER, (void *)printipxnode },
+
+ { "ipxcp-accept-local", o_bool, &ipxcp_wantoptions[0].accept_local,
+ "Accept our IPX address", 1,
+ &ipxcp_allowoptions[0].accept_local },
+
+ { "ipxcp-accept-remote", o_bool, &ipxcp_wantoptions[0].accept_remote,
+ "Accept peer's IPX address", 1,
+ &ipxcp_allowoptions[0].accept_remote },
+
+ { "ipx-routing", o_int, &ipxcp_wantoptions[0].router,
+ "Set IPX routing proto number", OPT_PRIO,
+ &ipxcp_wantoptions[0].neg_router },
+
+ { "ipx-router-name", o_special, setipxname,
+ "Set IPX router name", OPT_PRIO | OPT_A2STRVAL | OPT_STATIC,
+ &ipxcp_wantoptions[0].name },
+
+ { "ipxcp-restart", o_int, &ipxcp_fsm[0].timeouttime,
+ "Set timeout for IPXCP", OPT_PRIO },
+ { "ipxcp-max-terminate", o_int, &ipxcp_fsm[0].maxtermtransmits,
+ "Set max #xmits for IPXCP term-reqs", OPT_PRIO },
+ { "ipxcp-max-configure", o_int, &ipxcp_fsm[0].maxconfreqtransmits,
+ "Set max #xmits for IPXCP conf-reqs", OPT_PRIO },
+ { "ipxcp-max-failure", o_int, &ipxcp_fsm[0].maxnakloops,
+ "Set max #conf-naks for IPXCP", OPT_PRIO },
+
+ { NULL }
+};
+
+/*
+ * Protocol entry points.
+ */
+
+static void ipxcp_init __P((int));
+static void ipxcp_open __P((int));
+static void ipxcp_close __P((int, char *));
+static void ipxcp_lowerup __P((int));
+static void ipxcp_lowerdown __P((int));
+static void ipxcp_input __P((int, u_char *, int));
+static void ipxcp_protrej __P((int));
+static int ipxcp_printpkt __P((u_char *, int,
+ void (*) __P((void *, char *, ...)), void *));
+
+struct protent ipxcp_protent = {
+ PPP_IPXCP,
+ ipxcp_init,
+ ipxcp_input,
+ ipxcp_protrej,
+ ipxcp_lowerup,
+ ipxcp_lowerdown,
+ ipxcp_open,
+ ipxcp_close,
+ ipxcp_printpkt,
+ NULL,
+ 0,
+ "IPXCP",
+ "IPX",
+ ipxcp_option_list,
+ NULL,
+ NULL,
+ NULL
+};
+
+/*
+ * Lengths of configuration options.
+ */
+
+#define CILEN_VOID 2
+#define CILEN_COMPLETE 2 /* length of complete option */
+#define CILEN_NETN 6 /* network number length option */
+#define CILEN_NODEN 8 /* node number length option */
+#define CILEN_PROTOCOL 4 /* Minimum length of routing protocol */
+#define CILEN_NAME 3 /* Minimum length of router name */
+#define CILEN_COMPRESS 4 /* Minimum length of compression protocol */
+
+#define CODENAME(x) ((x) == CONFACK ? "ACK" : \
+ (x) == CONFNAK ? "NAK" : "REJ")
+
+static int ipxcp_is_up;
+
+static char *ipx_ntoa __P((u_int32_t));
+
+/* Used in printing the node number */
+#define NODE(base) base[0], base[1], base[2], base[3], base[4], base[5]
+
+/* Used to generate the proper bit mask */
+#define BIT(num) (1 << (num))
+
+/*
+ * Convert from internal to external notation
+ */
+
+static short int
+to_external(internal)
+short int internal;
+{
+ short int external;
+
+ if (internal & BIT(IPX_NONE) )
+ external = IPX_NONE;
+ else
+ external = RIP_SAP;
+
+ return external;
+}
+
+/*
+ * Make a string representation of a network IP address.
+ */
+
+static char *
+ipx_ntoa(ipxaddr)
+u_int32_t ipxaddr;
+{
+ static char b[64];
+ slprintf(b, sizeof(b), "%x", ipxaddr);
+ return b;
+}
+
+
+static u_char *
+setipxnodevalue(src,dst)
+u_char *src, *dst;
+{
+ int indx;
+ int item;
+
+ for (;;) {
+ if (!isxdigit (*src))
+ break;
+
+ for (indx = 0; indx < 5; ++indx) {
+ dst[indx] <<= 4;
+ dst[indx] |= (dst[indx + 1] >> 4) & 0x0F;
+ }
+
+ item = toupper (*src) - '0';
+ if (item > 9)
+ item -= 7;
+
+ dst[5] = (dst[5] << 4) | item;
+ ++src;
+ }
+ return src;
+}
+
+static int ipx_prio_our, ipx_prio_his;
+
+static int
+setipxnode(argv)
+ char **argv;
+{
+ char *end;
+ int have_his = 0;
+ u_char our_node[6];
+ u_char his_node[6];
+
+ memset (our_node, 0, 6);
+ memset (his_node, 0, 6);
+
+ end = setipxnodevalue (*argv, our_node);
+ if (*end == ':') {
+ have_his = 1;
+ end = setipxnodevalue (++end, his_node);
+ }
+
+ if (*end == '\0') {
+ ipxcp_wantoptions[0].neg_node = 1;
+ if (option_priority >= ipx_prio_our) {
+ memcpy(&ipxcp_wantoptions[0].our_node[0], our_node, 6);
+ ipx_prio_our = option_priority;
+ }
+ if (have_his && option_priority >= ipx_prio_his) {
+ memcpy(&ipxcp_wantoptions[0].his_node[0], his_node, 6);
+ ipx_prio_his = option_priority;
+ }
+ return 1;
+ }
+
+ option_error("invalid parameter '%s' for ipx-node option", *argv);
+ return 0;
+}
+
+static void
+printipxnode(opt, printer, arg)
+ option_t *opt;
+ void (*printer) __P((void *, char *, ...));
+ void *arg;
+{
+ unsigned char *p;
+
+ p = ipxcp_wantoptions[0].our_node;
+ if (ipx_prio_our)
+ printer(arg, "%.2x%.2x%.2x%.2x%.2x%.2x",
+ p[0], p[1], p[2], p[3], p[4], p[5]);
+ printer(arg, ":");
+ p = ipxcp_wantoptions[0].his_node;
+ if (ipx_prio_his)
+ printer(arg, "%.2x%.2x%.2x%.2x%.2x%.2x",
+ p[0], p[1], p[2], p[3], p[4], p[5]);
+}
+
+static int
+setipxname (argv)
+ char **argv;
+{
+ char *dest = ipxcp_wantoptions[0].name;
+ char *src = *argv;
+ int count;
+ char ch;
+
+ ipxcp_wantoptions[0].neg_name = 1;
+ ipxcp_allowoptions[0].neg_name = 1;
+ memset (dest, '\0', sizeof (ipxcp_wantoptions[0].name));
+
+ count = 0;
+ while (*src) {
+ ch = *src++;
+ if (! isalnum (ch) && ch != '_') {
+ option_error("IPX router name must be alphanumeric or _");
+ return 0;
+ }
+
+ if (count >= sizeof (ipxcp_wantoptions[0].name) - 1) {
+ option_error("IPX router name is limited to %d characters",
+ sizeof (ipxcp_wantoptions[0].name) - 1);
+ return 0;
+ }
+
+ dest[count++] = toupper (ch);
+ }
+ dest[count] = 0;
+
+ return 1;
+}
+
+/*
+ * ipxcp_init - Initialize IPXCP.
+ */
+static void
+ipxcp_init(unit)
+ int unit;
+{
+ fsm *f = &ipxcp_fsm[unit];
+
+ f->unit = unit;
+ f->protocol = PPP_IPXCP;
+ f->callbacks = &ipxcp_callbacks;
+ fsm_init(&ipxcp_fsm[unit]);
+
+ memset (wo->name, 0, sizeof (wo->name));
+ memset (wo->our_node, 0, sizeof (wo->our_node));
+ memset (wo->his_node, 0, sizeof (wo->his_node));
+
+ wo->neg_nn = 1;
+ wo->neg_complete = 1;
+ wo->network = 0;
+
+ ao->neg_node = 1;
+ ao->neg_nn = 1;
+ ao->neg_name = 1;
+ ao->neg_complete = 1;
+ ao->neg_router = 1;
+
+ ao->accept_local = 0;
+ ao->accept_remote = 0;
+ ao->accept_network = 0;
+
+ wo->tried_rip = 0;
+ wo->tried_nlsp = 0;
+}
+
+/*
+ * Copy the node number
+ */
+
+static void
+copy_node (src, dst)
+u_char *src, *dst;
+{
+ memcpy (dst, src, sizeof (ipxcp_wantoptions[0].our_node));
+}
+
+/*
+ * Compare node numbers
+ */
+
+static int
+compare_node (src, dst)
+u_char *src, *dst;
+{
+ return memcmp (dst, src, sizeof (ipxcp_wantoptions[0].our_node)) == 0;
+}
+
+/*
+ * Is the node number zero?
+ */
+
+static int
+zero_node (node)
+u_char *node;
+{
+ int indx;
+ for (indx = 0; indx < sizeof (ipxcp_wantoptions[0].our_node); ++indx)
+ if (node [indx] != 0)
+ return 0;
+ return 1;
+}
+
+/*
+ * Increment the node number
+ */
+
+static void
+inc_node (node)
+u_char *node;
+{
+ u_char *outp;
+ u_int32_t magic_num;
+
+ outp = node;
+ magic_num = magic();
+ *outp++ = '\0';
+ *outp++ = '\0';
+ PUTLONG (magic_num, outp);
+}
+
+/*
+ * ipxcp_open - IPXCP is allowed to come up.
+ */
+static void
+ipxcp_open(unit)
+ int unit;
+{
+ fsm_open(&ipxcp_fsm[unit]);
+}
+
+/*
+ * ipxcp_close - Take IPXCP down.
+ */
+static void
+ipxcp_close(unit, reason)
+ int unit;
+ char *reason;
+{
+ fsm_close(&ipxcp_fsm[unit], reason);
+}
+
+
+/*
+ * ipxcp_lowerup - The lower layer is up.
+ */
+static void
+ipxcp_lowerup(unit)
+ int unit;
+{
+ fsm_lowerup(&ipxcp_fsm[unit]);
+}
+
+
+/*
+ * ipxcp_lowerdown - The lower layer is down.
+ */
+static void
+ipxcp_lowerdown(unit)
+ int unit;
+{
+ fsm_lowerdown(&ipxcp_fsm[unit]);
+}
+
+
+/*
+ * ipxcp_input - Input IPXCP packet.
+ */
+static void
+ipxcp_input(unit, p, len)
+ int unit;
+ u_char *p;
+ int len;
+{
+ fsm_input(&ipxcp_fsm[unit], p, len);
+}
+
+
+/*
+ * ipxcp_protrej - A Protocol-Reject was received for IPXCP.
+ *
+ * Pretend the lower layer went down, so we shut up.
+ */
+static void
+ipxcp_protrej(unit)
+ int unit;
+{
+ fsm_lowerdown(&ipxcp_fsm[unit]);
+}
+
+
+/*
+ * ipxcp_resetci - Reset our CI.
+ */
+static void
+ipxcp_resetci(f)
+ fsm *f;
+{
+ wo->req_node = wo->neg_node && ao->neg_node;
+ wo->req_nn = wo->neg_nn && ao->neg_nn;
+
+ if (wo->our_network == 0) {
+ wo->neg_node = 1;
+ ao->accept_network = 1;
+ }
+/*
+ * If our node number is zero then change it.
+ */
+ if (zero_node (wo->our_node)) {
+ inc_node (wo->our_node);
+ ao->accept_local = 1;
+ wo->neg_node = 1;
+ }
+/*
+ * If his node number is zero then change it.
+ */
+ if (zero_node (wo->his_node)) {
+ inc_node (wo->his_node);
+ ao->accept_remote = 1;
+ }
+/*
+ * If no routing agent was specified then we do RIP/SAP according to the
+ * RFC documents. If you have specified something then OK. Otherwise, we
+ * do RIP/SAP.
+ */
+ if (ao->router == 0) {
+ ao->router |= BIT(RIP_SAP);
+ wo->router |= BIT(RIP_SAP);
+ }
+
+ /* Always specify a routing protocol unless it was REJected. */
+ wo->neg_router = 1;
+/*
+ * Start with these default values
+ */
+ *go = *wo;
+}
+
+/*
+ * ipxcp_cilen - Return length of our CI.
+ */
+
+static int
+ipxcp_cilen(f)
+ fsm *f;
+{
+ int len;
+
+ len = go->neg_nn ? CILEN_NETN : 0;
+ len += go->neg_node ? CILEN_NODEN : 0;
+ len += go->neg_name ? CILEN_NAME + strlen (go->name) - 1 : 0;
+
+ /* RFC says that defaults should not be included. */
+ if (go->neg_router && to_external(go->router) != RIP_SAP)
+ len += CILEN_PROTOCOL;
+
+ return (len);
+}
+
+
+/*
+ * ipxcp_addci - Add our desired CIs to a packet.
+ */
+static void
+ipxcp_addci(f, ucp, lenp)
+ fsm *f;
+ u_char *ucp;
+ int *lenp;
+{
+/*
+ * Add the options to the record.
+ */
+ if (go->neg_nn) {
+ PUTCHAR (IPX_NETWORK_NUMBER, ucp);
+ PUTCHAR (CILEN_NETN, ucp);
+ PUTLONG (go->our_network, ucp);
+ }
+
+ if (go->neg_node) {
+ int indx;
+ PUTCHAR (IPX_NODE_NUMBER, ucp);
+ PUTCHAR (CILEN_NODEN, ucp);
+ for (indx = 0; indx < sizeof (go->our_node); ++indx)
+ PUTCHAR (go->our_node[indx], ucp);
+ }
+
+ if (go->neg_name) {
+ int cilen = strlen (go->name);
+ int indx;
+ PUTCHAR (IPX_ROUTER_NAME, ucp);
+ PUTCHAR (CILEN_NAME + cilen - 1, ucp);
+ for (indx = 0; indx < cilen; ++indx)
+ PUTCHAR (go->name [indx], ucp);
+ }
+
+ if (go->neg_router) {
+ short external = to_external (go->router);
+ if (external != RIP_SAP) {
+ PUTCHAR (IPX_ROUTER_PROTOCOL, ucp);
+ PUTCHAR (CILEN_PROTOCOL, ucp);
+ PUTSHORT (external, ucp);
+ }
+ }
+}
+
+/*
+ * ipxcp_ackci - Ack our CIs.
+ *
+ * Returns:
+ * 0 - Ack was bad.
+ * 1 - Ack was good.
+ */
+static int
+ipxcp_ackci(f, p, len)
+ fsm *f;
+ u_char *p;
+ int len;
+{
+ u_short cilen, citype, cishort;
+ u_char cichar;
+ u_int32_t cilong;
+
+#define ACKCIVOID(opt, neg) \
+ if (neg) { \
+ if ((len -= CILEN_VOID) < 0) \
+ break; \
+ GETCHAR(citype, p); \
+ GETCHAR(cilen, p); \
+ if (cilen != CILEN_VOID || \
+ citype != opt) \
+ break; \
+ }
+
+#define ACKCICOMPLETE(opt,neg) ACKCIVOID(opt, neg)
+
+#define ACKCICHARS(opt, neg, val, cnt) \
+ if (neg) { \
+ int indx, count = cnt; \
+ len -= (count + 2); \
+ if (len < 0) \
+ break; \
+ GETCHAR(citype, p); \
+ GETCHAR(cilen, p); \
+ if (cilen != (count + 2) || \
+ citype != opt) \
+ break; \
+ for (indx = 0; indx < count; ++indx) {\
+ GETCHAR(cichar, p); \
+ if (cichar != ((u_char *) &val)[indx]) \
+ break; \
+ }\
+ if (indx != count) \
+ break; \
+ }
+
+#define ACKCINODE(opt,neg,val) ACKCICHARS(opt,neg,val,sizeof(val))
+#define ACKCINAME(opt,neg,val) ACKCICHARS(opt,neg,val,strlen(val))
+
+#define ACKCINETWORK(opt, neg, val) \
+ if (neg) { \
+ if ((len -= CILEN_NETN) < 0) \
+ break; \
+ GETCHAR(citype, p); \
+ GETCHAR(cilen, p); \
+ if (cilen != CILEN_NETN || \
+ citype != opt) \
+ break; \
+ GETLONG(cilong, p); \
+ if (cilong != val) \
+ break; \
+ }
+
+#define ACKCIPROTO(opt, neg, val) \
+ if (neg) { \
+ if (len < 2) \
+ break; \
+ GETCHAR(citype, p); \
+ GETCHAR(cilen, p); \
+ if (cilen != CILEN_PROTOCOL || citype != opt) \
+ break; \
+ len -= cilen; \
+ if (len < 0) \
+ break; \
+ GETSHORT(cishort, p); \
+ if (cishort != to_external (val) || cishort == RIP_SAP) \
+ break; \
+ }
+/*
+ * Process the ACK frame in the order in which the frame was assembled
+ */
+ do {
+ ACKCINETWORK (IPX_NETWORK_NUMBER, go->neg_nn, go->our_network);
+ ACKCINODE (IPX_NODE_NUMBER, go->neg_node, go->our_node);
+ ACKCINAME (IPX_ROUTER_NAME, go->neg_name, go->name);
+ if (len > 0)
+ ACKCIPROTO (IPX_ROUTER_PROTOCOL, go->neg_router, go->router);
+/*
+ * This is the end of the record.
+ */
+ if (len == 0)
+ return (1);
+ } while (0);
+/*
+ * The frame is invalid
+ */
+ IPXCPDEBUG(("ipxcp_ackci: received bad Ack!"));
+ return (0);
+}
+
+/*
+ * ipxcp_nakci - Peer has sent a NAK for some of our CIs.
+ * This should not modify any state if the Nak is bad
+ * or if IPXCP is in the OPENED state.
+ *
+ * Returns:
+ * 0 - Nak was bad.
+ * 1 - Nak was good.
+ */
+
+static int
+ipxcp_nakci(f, p, len)
+ fsm *f;
+ u_char *p;
+ int len;
+{
+ u_char citype, cilen, *next;
+ u_short s;
+ u_int32_t l;
+ ipxcp_options no; /* options we've seen Naks for */
+ ipxcp_options try; /* options to request next time */
+
+ BZERO(&no, sizeof(no));
+ try = *go;
+
+ while (len > CILEN_VOID) {
+ GETCHAR (citype, p);
+ GETCHAR (cilen, p);
+ len -= cilen;
+ if (len < 0)
+ goto bad;
+ next = &p [cilen - CILEN_VOID];
+
+ switch (citype) {
+ case IPX_NETWORK_NUMBER:
+ if (!go->neg_nn || no.neg_nn || (cilen != CILEN_NETN))
+ goto bad;
+ no.neg_nn = 1;
+
+ GETLONG(l, p);
+ if (l && ao->accept_network)
+ try.our_network = l;
+ break;
+
+ case IPX_NODE_NUMBER:
+ if (!go->neg_node || no.neg_node || (cilen != CILEN_NODEN))
+ goto bad;
+ no.neg_node = 1;
+
+ if (!zero_node (p) && ao->accept_local &&
+ ! compare_node (p, ho->his_node))
+ copy_node (p, try.our_node);
+ break;
+
+ /* This has never been sent. Ignore the NAK frame */
+ case IPX_COMPRESSION_PROTOCOL:
+ goto bad;
+
+ case IPX_ROUTER_PROTOCOL:
+ if (!go->neg_router || (cilen < CILEN_PROTOCOL))
+ goto bad;
+
+ GETSHORT (s, p);
+ if (s > 15) /* This is just bad, but ignore for now. */
+ break;
+
+ s = BIT(s);
+ if (no.router & s) /* duplicate NAKs are always bad */
+ goto bad;
+
+ if (no.router == 0) /* Reset on first NAK only */
+ try.router = 0;
+
+ no.router |= s;
+ try.router |= s;
+ try.neg_router = 1;
+ break;
+
+ /* These, according to the RFC, must never be NAKed. */
+ case IPX_ROUTER_NAME:
+ case IPX_COMPLETE:
+ goto bad;
+
+ /* These are for options which we have not seen. */
+ default:
+ break;
+ }
+ p = next;
+ }
+
+ /*
+ * Do not permit the peer to force a router protocol which we do not
+ * support. However, default to the condition that will accept "NONE".
+ */
+ try.router &= (ao->router | BIT(IPX_NONE));
+ if (try.router == 0 && ao->router != 0)
+ try.router = BIT(IPX_NONE);
+
+ if (try.router != 0)
+ try.neg_router = 1;
+
+ /*
+ * OK, the Nak is good. Now we can update state.
+ * If there are any options left, we ignore them.
+ */
+ if (f->state != OPENED)
+ *go = try;
+
+ return 1;
+
+bad:
+ IPXCPDEBUG(("ipxcp_nakci: received bad Nak!"));
+ return 0;
+}
+
+/*
+ * ipxcp_rejci - Reject some of our CIs.
+ */
+static int
+ipxcp_rejci(f, p, len)
+ fsm *f;
+ u_char *p;
+ int len;
+{
+ u_short cilen, citype, cishort;
+ u_char cichar;
+ u_int32_t cilong;
+ ipxcp_options try; /* options to request next time */
+
+#define REJCINETWORK(opt, neg, val) \
+ if (neg && p[0] == opt) { \
+ if ((len -= CILEN_NETN) < 0) \
+ break; \
+ GETCHAR(citype, p); \
+ GETCHAR(cilen, p); \
+ if (cilen != CILEN_NETN || \
+ citype != opt) \
+ break; \
+ GETLONG(cilong, p); \
+ if (cilong != val) \
+ break; \
+ neg = 0; \
+ }
+
+#define REJCICHARS(opt, neg, val, cnt) \
+ if (neg && p[0] == opt) { \
+ int indx, count = cnt; \
+ len -= (count + 2); \
+ if (len < 0) \
+ break; \
+ GETCHAR(citype, p); \
+ GETCHAR(cilen, p); \
+ if (cilen != (count + 2) || \
+ citype != opt) \
+ break; \
+ for (indx = 0; indx < count; ++indx) {\
+ GETCHAR(cichar, p); \
+ if (cichar != ((u_char *) &val)[indx]) \
+ break; \
+ }\
+ if (indx != count) \
+ break; \
+ neg = 0; \
+ }
+
+#define REJCINODE(opt,neg,val) REJCICHARS(opt,neg,val,sizeof(val))
+#define REJCINAME(opt,neg,val) REJCICHARS(opt,neg,val,strlen(val))
+
+#define REJCIVOID(opt, neg) \
+ if (neg && p[0] == opt) { \
+ if ((len -= CILEN_VOID) < 0) \
+ break; \
+ GETCHAR(citype, p); \
+ GETCHAR(cilen, p); \
+ if (cilen != CILEN_VOID || citype != opt) \
+ break; \
+ neg = 0; \
+ }
+
+/* a reject for RIP/SAP is invalid since we don't send it and you can't
+ reject something which is not sent. (You can NAK, but you can't REJ.) */
+#define REJCIPROTO(opt, neg, val, bit) \
+ if (neg && p[0] == opt) { \
+ if ((len -= CILEN_PROTOCOL) < 0) \
+ break; \
+ GETCHAR(citype, p); \
+ GETCHAR(cilen, p); \
+ if (cilen != CILEN_PROTOCOL) \
+ break; \
+ GETSHORT(cishort, p); \
+ if (cishort != to_external (val) || cishort == RIP_SAP) \
+ break; \
+ neg = 0; \
+ }
+/*
+ * Any Rejected CIs must be in exactly the same order that we sent.
+ * Check packet length and CI length at each step.
+ * If we find any deviations, then this packet is bad.
+ */
+ try = *go;
+
+ do {
+ REJCINETWORK (IPX_NETWORK_NUMBER, try.neg_nn, try.our_network);
+ REJCINODE (IPX_NODE_NUMBER, try.neg_node, try.our_node);
+ REJCINAME (IPX_ROUTER_NAME, try.neg_name, try.name);
+ REJCIPROTO (IPX_ROUTER_PROTOCOL, try.neg_router, try.router, 0);
+/*
+ * This is the end of the record.
+ */
+ if (len == 0) {
+ if (f->state != OPENED)
+ *go = try;
+ return (1);
+ }
+ } while (0);
+/*
+ * The frame is invalid at this point.
+ */
+ IPXCPDEBUG(("ipxcp_rejci: received bad Reject!"));
+ return 0;
+}
+
+/*
+ * ipxcp_reqci - Check the peer's requested CIs and send appropriate response.
+ *
+ * Returns: CONFACK, CONFNAK or CONFREJ and input packet modified
+ * appropriately. If reject_if_disagree is non-zero, doesn't return
+ * CONFNAK; returns CONFREJ if it can't return CONFACK.
+ */
+static int
+ipxcp_reqci(f, inp, len, reject_if_disagree)
+ fsm *f;
+ u_char *inp; /* Requested CIs */
+ int *len; /* Length of requested CIs */
+ int reject_if_disagree;
+{
+ u_char *cip, *next; /* Pointer to current and next CIs */
+ u_short cilen, citype; /* Parsed len, type */
+ u_short cishort; /* Parsed short value */
+ u_int32_t cinetwork; /* Parsed address values */
+ int rc = CONFACK; /* Final packet return code */
+ int orc; /* Individual option return code */
+ u_char *p; /* Pointer to next char to parse */
+ u_char *ucp = inp; /* Pointer to current output char */
+ int l = *len; /* Length left */
+
+ /*
+ * Reset all his options.
+ */
+ BZERO(ho, sizeof(*ho));
+
+ /*
+ * Process all his options.
+ */
+ next = inp;
+ while (l) {
+ orc = CONFACK; /* Assume success */
+ cip = p = next; /* Remember begining of CI */
+ if (l < 2 || /* Not enough data for CI header or */
+ p[1] < 2 || /* CI length too small or */
+ p[1] > l) { /* CI length too big? */
+ IPXCPDEBUG(("ipxcp_reqci: bad CI length!"));
+ orc = CONFREJ; /* Reject bad CI */
+ cilen = l; /* Reject till end of packet */
+ l = 0; /* Don't loop again */
+ goto endswitch;
+ }
+ GETCHAR(citype, p); /* Parse CI type */
+ GETCHAR(cilen, p); /* Parse CI length */
+ l -= cilen; /* Adjust remaining length */
+ next += cilen; /* Step to next CI */
+
+ switch (citype) { /* Check CI type */
+/*
+ * The network number must match. Choose the larger of the two.
+ */
+ case IPX_NETWORK_NUMBER:
+ /* if we wont negotiate the network number or the length is wrong
+ then reject the option */
+ if ( !ao->neg_nn || cilen != CILEN_NETN ) {
+ orc = CONFREJ;
+ break;
+ }
+ GETLONG(cinetwork, p);
+
+ /* If the network numbers match then acknowledge them. */
+ if (cinetwork != 0) {
+ ho->his_network = cinetwork;
+ ho->neg_nn = 1;
+ if (wo->our_network == cinetwork)
+ break;
+/*
+ * If the network number is not given or we don't accept their change or
+ * the network number is too small then NAK it.
+ */
+ if (! ao->accept_network || cinetwork < wo->our_network) {
+ DECPTR (sizeof (u_int32_t), p);
+ PUTLONG (wo->our_network, p);
+ orc = CONFNAK;
+ }
+ break;
+ }
+/*
+ * The peer sent '0' for the network. Give it ours if we have one.
+ */
+ if (go->our_network != 0) {
+ DECPTR (sizeof (u_int32_t), p);
+ PUTLONG (wo->our_network, p);
+ orc = CONFNAK;
+/*
+ * We don't have one. Reject the value.
+ */
+ } else
+ orc = CONFREJ;
+
+ break;
+/*
+ * The node number is required
+ */
+ case IPX_NODE_NUMBER:
+ /* if we wont negotiate the node number or the length is wrong
+ then reject the option */
+ if ( cilen != CILEN_NODEN ) {
+ orc = CONFREJ;
+ break;
+ }
+
+ copy_node (p, ho->his_node);
+ ho->neg_node = 1;
+/*
+ * If the remote does not have a number and we do then NAK it with the value
+ * which we have for it. (We never have a default value of zero.)
+ */
+ if (zero_node (ho->his_node)) {
+ orc = CONFNAK;
+ copy_node (wo->his_node, p);
+ INCPTR (sizeof (wo->his_node), p);
+ break;
+ }
+/*
+ * If you have given me the expected network node number then I'll accept
+ * it now.
+ */
+ if (compare_node (wo->his_node, ho->his_node)) {
+ orc = CONFACK;
+ ho->neg_node = 1;
+ INCPTR (sizeof (wo->his_node), p);
+ break;
+ }
+/*
+ * If his node number is the same as ours then ask him to try the next
+ * value.
+ */
+ if (compare_node (ho->his_node, go->our_node)) {
+ inc_node (ho->his_node);
+ orc = CONFNAK;
+ copy_node (ho->his_node, p);
+ INCPTR (sizeof (wo->his_node), p);
+ break;
+ }
+/*
+ * If we don't accept a new value then NAK it.
+ */
+ if (! ao->accept_remote) {
+ copy_node (wo->his_node, p);
+ INCPTR (sizeof (wo->his_node), p);
+ orc = CONFNAK;
+ break;
+ }
+ orc = CONFACK;
+ ho->neg_node = 1;
+ INCPTR (sizeof (wo->his_node), p);
+ break;
+/*
+ * Compression is not desired at this time. It is always rejected.
+ */
+ case IPX_COMPRESSION_PROTOCOL:
+ orc = CONFREJ;
+ break;
+/*
+ * The routing protocol is a bitmask of various types. Any combination
+ * of the values RIP_SAP and NLSP are permissible. 'IPX_NONE' for no
+ * routing protocol must be specified only once.
+ */
+ case IPX_ROUTER_PROTOCOL:
+ if ( !ao->neg_router || cilen < CILEN_PROTOCOL ) {
+ orc = CONFREJ;
+ break;
+ }
+
+ GETSHORT (cishort, p);
+
+ if (wo->neg_router == 0) {
+ wo->neg_router = 1;
+ wo->router = BIT(IPX_NONE);
+ }
+
+ if ((cishort == IPX_NONE && ho->router != 0) ||
+ (ho->router & BIT(IPX_NONE))) {
+ orc = CONFREJ;
+ break;
+ }
+
+ cishort = BIT(cishort);
+ if (ho->router & cishort) {
+ orc = CONFREJ;
+ break;
+ }
+
+ ho->router |= cishort;
+ ho->neg_router = 1;
+
+ /* Finally do not allow a router protocol which we do not
+ support. */
+
+ if ((cishort & (ao->router | BIT(IPX_NONE))) == 0) {
+ int protocol;
+
+ if (cishort == BIT(NLSP) &&
+ (ao->router & BIT(RIP_SAP)) &&
+ !wo->tried_rip) {
+ protocol = RIP_SAP;
+ wo->tried_rip = 1;
+ } else
+ protocol = IPX_NONE;
+
+ DECPTR (sizeof (u_int16_t), p);
+ PUTSHORT (protocol, p);
+ orc = CONFNAK;
+ }
+ break;
+/*
+ * The router name is advisorary. Just accept it if it is not too large.
+ */
+ case IPX_ROUTER_NAME:
+ if (cilen >= CILEN_NAME) {
+ int name_size = cilen - CILEN_NAME;
+ if (name_size > sizeof (ho->name))
+ name_size = sizeof (ho->name) - 1;
+ memset (ho->name, 0, sizeof (ho->name));
+ memcpy (ho->name, p, name_size);
+ ho->name [name_size] = '\0';
+ ho->neg_name = 1;
+ orc = CONFACK;
+ break;
+ }
+ orc = CONFREJ;
+ break;
+/*
+ * This is advisorary.
+ */
+ case IPX_COMPLETE:
+ if (cilen != CILEN_COMPLETE)
+ orc = CONFREJ;
+ else {
+ ho->neg_complete = 1;
+ orc = CONFACK;
+ }
+ break;
+/*
+ * All other entries are not known at this time.
+ */
+ default:
+ orc = CONFREJ;
+ break;
+ }
+endswitch:
+ if (orc == CONFACK && /* Good CI */
+ rc != CONFACK) /* but prior CI wasnt? */
+ continue; /* Don't send this one */
+
+ if (orc == CONFNAK) { /* Nak this CI? */
+ if (reject_if_disagree) /* Getting fed up with sending NAKs? */
+ orc = CONFREJ; /* Get tough if so */
+ if (rc == CONFREJ) /* Rejecting prior CI? */
+ continue; /* Don't send this one */
+ if (rc == CONFACK) { /* Ack'd all prior CIs? */
+ rc = CONFNAK; /* Not anymore... */
+ ucp = inp; /* Backup */
+ }
+ }
+
+ if (orc == CONFREJ && /* Reject this CI */
+ rc != CONFREJ) { /* but no prior ones? */
+ rc = CONFREJ;
+ ucp = inp; /* Backup */
+ }
+
+ /* Need to move CI? */
+ if (ucp != cip)
+ BCOPY(cip, ucp, cilen); /* Move it */
+
+ /* Update output pointer */
+ INCPTR(cilen, ucp);
+ }
+
+ /*
+ * If we aren't rejecting this packet, and we want to negotiate
+ * their address, and they didn't send their address, then we
+ * send a NAK with a IPX_NODE_NUMBER option appended. We assume the
+ * input buffer is long enough that we can append the extra
+ * option safely.
+ */
+
+ if (rc != CONFREJ && !ho->neg_node &&
+ wo->req_nn && !reject_if_disagree) {
+ if (rc == CONFACK) {
+ rc = CONFNAK;
+ wo->req_nn = 0; /* don't ask again */
+ ucp = inp; /* reset pointer */
+ }
+
+ if (zero_node (wo->his_node))
+ inc_node (wo->his_node);
+
+ PUTCHAR (IPX_NODE_NUMBER, ucp);
+ PUTCHAR (CILEN_NODEN, ucp);
+ copy_node (wo->his_node, ucp);
+ INCPTR (sizeof (wo->his_node), ucp);
+ }
+
+ *len = ucp - inp; /* Compute output length */
+ IPXCPDEBUG(("ipxcp: returning Configure-%s", CODENAME(rc)));
+ return (rc); /* Return final code */
+}
+
+/*
+ * ipxcp_up - IPXCP has come UP.
+ *
+ * Configure the IP network interface appropriately and bring it up.
+ */
+
+static void
+ipxcp_up(f)
+ fsm *f;
+{
+ int unit = f->unit;
+
+ IPXCPDEBUG(("ipxcp: up"));
+
+ /* The default router protocol is RIP/SAP. */
+ if (ho->router == 0)
+ ho->router = BIT(RIP_SAP);
+
+ if (go->router == 0)
+ go->router = BIT(RIP_SAP);
+
+ /* Fetch the network number */
+ if (!ho->neg_nn)
+ ho->his_network = wo->his_network;
+
+ if (!ho->neg_node)
+ copy_node (wo->his_node, ho->his_node);
+
+ if (!wo->neg_node && !go->neg_node)
+ copy_node (wo->our_node, go->our_node);
+
+ if (zero_node (go->our_node)) {
+ static char errmsg[] = "Could not determine local IPX node address";
+ if (debug)
+ error(errmsg);
+ ipxcp_close(f->unit, errmsg);
+ return;
+ }
+
+ go->network = go->our_network;
+ if (ho->his_network != 0 && ho->his_network > go->network)
+ go->network = ho->his_network;
+
+ if (go->network == 0) {
+ static char errmsg[] = "Can not determine network number";
+ if (debug)
+ error(errmsg);
+ ipxcp_close (unit, errmsg);
+ return;
+ }
+
+ /* bring the interface up */
+ if (!sifup(unit)) {
+ if (debug)
+ warn("sifup failed (IPX)");
+ ipxcp_close(unit, "Interface configuration failed");
+ return;
+ }
+ ipxcp_is_up = 1;
+
+ /* set the network number for IPX */
+ if (!sipxfaddr(unit, go->network, go->our_node)) {
+ if (debug)
+ warn("sipxfaddr failed");
+ ipxcp_close(unit, "Interface configuration failed");
+ return;
+ }
+
+ np_up(f->unit, PPP_IPX);
+
+ /*
+ * Execute the ipx-up script, like this:
+ * /etc/ppp/ipx-up interface tty speed local-IPX remote-IPX
+ */
+
+ ipxcp_script (f, _PATH_IPXUP);
+}
+
+/*
+ * ipxcp_down - IPXCP has gone DOWN.
+ *
+ * Take the IP network interface down, clear its addresses
+ * and delete routes through it.
+ */
+
+static void
+ipxcp_down(f)
+ fsm *f;
+{
+ IPXCPDEBUG(("ipxcp: down"));
+
+ if (!ipxcp_is_up)
+ return;
+ ipxcp_is_up = 0;
+ np_down(f->unit, PPP_IPX);
+ cipxfaddr(f->unit);
+ sifnpmode(f->unit, PPP_IPX, NPMODE_DROP);
+ sifdown(f->unit);
+ ipxcp_script (f, _PATH_IPXDOWN);
+}
+
+
+/*
+ * ipxcp_finished - possibly shut down the lower layers.
+ */
+static void
+ipxcp_finished(f)
+ fsm *f;
+{
+ np_finished(f->unit, PPP_IPX);
+}
+
+
+/*
+ * ipxcp_script - Execute a script with arguments
+ * interface-name tty-name speed local-IPX remote-IPX networks.
+ */
+static void
+ipxcp_script(f, script)
+ fsm *f;
+ char *script;
+{
+ char strspeed[32], strlocal[32], strremote[32];
+ char strnetwork[32], strpid[32];
+ char *argv[14], strproto_lcl[32], strproto_rmt[32];
+
+ slprintf(strpid, sizeof(strpid), "%d", getpid());
+ slprintf(strspeed, sizeof(strspeed),"%d", baud_rate);
+
+ strproto_lcl[0] = '\0';
+ if (go->neg_router && ((go->router & BIT(IPX_NONE)) == 0)) {
+ if (go->router & BIT(RIP_SAP))
+ strlcpy (strproto_lcl, "RIP ", sizeof(strproto_lcl));
+ if (go->router & BIT(NLSP))
+ strlcat (strproto_lcl, "NLSP ", sizeof(strproto_lcl));
+ }
+
+ if (strproto_lcl[0] == '\0')
+ strlcpy (strproto_lcl, "NONE ", sizeof(strproto_lcl));
+
+ strproto_lcl[strlen (strproto_lcl)-1] = '\0';
+
+ strproto_rmt[0] = '\0';
+ if (ho->neg_router && ((ho->router & BIT(IPX_NONE)) == 0)) {
+ if (ho->router & BIT(RIP_SAP))
+ strlcpy (strproto_rmt, "RIP ", sizeof(strproto_rmt));
+ if (ho->router & BIT(NLSP))
+ strlcat (strproto_rmt, "NLSP ", sizeof(strproto_rmt));
+ }
+
+ if (strproto_rmt[0] == '\0')
+ strlcpy (strproto_rmt, "NONE ", sizeof(strproto_rmt));
+
+ strproto_rmt[strlen (strproto_rmt)-1] = '\0';
+
+ strlcpy (strnetwork, ipx_ntoa (go->network), sizeof(strnetwork));
+
+ slprintf (strlocal, sizeof(strlocal), "%0.6B", go->our_node);
+
+ slprintf (strremote, sizeof(strremote), "%0.6B", ho->his_node);
+
+ argv[0] = script;
+ argv[1] = ifname;
+ argv[2] = devnam;
+ argv[3] = strspeed;
+ argv[4] = strnetwork;
+ argv[5] = strlocal;
+ argv[6] = strremote;
+ argv[7] = strproto_lcl;
+ argv[8] = strproto_rmt;
+ argv[9] = go->name;
+ argv[10] = ho->name;
+ argv[11] = ipparam;
+ argv[12] = strpid;
+ argv[13] = NULL;
+ run_program(script, argv, 0, NULL, NULL);
+}
+
+/*
+ * ipxcp_printpkt - print the contents of an IPXCP packet.
+ */
+static char *ipxcp_codenames[] = {
+ "ConfReq", "ConfAck", "ConfNak", "ConfRej",
+ "TermReq", "TermAck", "CodeRej"
+};
+
+static int
+ipxcp_printpkt(p, plen, printer, arg)
+ u_char *p;
+ int plen;
+ void (*printer) __P((void *, char *, ...));
+ void *arg;
+{
+ int code, id, len, olen;
+ u_char *pstart, *optend;
+ u_short cishort;
+ u_int32_t cilong;
+
+ if (plen < HEADERLEN)
+ return 0;
+ pstart = p;
+ GETCHAR(code, p);
+ GETCHAR(id, p);
+ GETSHORT(len, p);
+ if (len < HEADERLEN || len > plen)
+ return 0;
+
+ if (code >= 1 && code <= sizeof(ipxcp_codenames) / sizeof(char *))
+ printer(arg, " %s", ipxcp_codenames[code-1]);
+ else
+ printer(arg, " code=0x%x", code);
+ printer(arg, " id=0x%x", id);
+ len -= HEADERLEN;
+ switch (code) {
+ case CONFREQ:
+ case CONFACK:
+ case CONFNAK:
+ case CONFREJ:
+ /* print option list */
+ while (len >= 2) {
+ GETCHAR(code, p);
+ GETCHAR(olen, p);
+ p -= 2;
+ if (olen < CILEN_VOID || olen > len) {
+ break;
+ }
+ printer(arg, " <");
+ len -= olen;
+ optend = p + olen;
+ switch (code) {
+ case IPX_NETWORK_NUMBER:
+ if (olen == CILEN_NETN) {
+ p += 2;
+ GETLONG(cilong, p);
+ printer (arg, "network %s", ipx_ntoa (cilong));
+ }
+ break;
+ case IPX_NODE_NUMBER:
+ if (olen == CILEN_NODEN) {
+ p += 2;
+ printer (arg, "node ");
+ while (p < optend) {
+ GETCHAR(code, p);
+ printer(arg, "%.2x", (int) (unsigned int) (unsigned char) code);
+ }
+ }
+ break;
+ case IPX_COMPRESSION_PROTOCOL:
+ if (olen == CILEN_COMPRESS) {
+ p += 2;
+ GETSHORT (cishort, p);
+ printer (arg, "compression %d", (int) cishort);
+ }
+ break;
+ case IPX_ROUTER_PROTOCOL:
+ if (olen == CILEN_PROTOCOL) {
+ p += 2;
+ GETSHORT (cishort, p);
+ printer (arg, "router proto %d", (int) cishort);
+ }
+ break;
+ case IPX_ROUTER_NAME:
+ if (olen >= CILEN_NAME) {
+ p += 2;
+ printer (arg, "router name \"");
+ while (p < optend) {
+ GETCHAR(code, p);
+ if (code >= 0x20 && code <= 0x7E)
+ printer (arg, "%c", (int) (unsigned int) (unsigned char) code);
+ else
+ printer (arg, " \\%.2x", (int) (unsigned int) (unsigned char) code);
+ }
+ printer (arg, "\"");
+ }
+ break;
+ case IPX_COMPLETE:
+ if (olen == CILEN_COMPLETE) {
+ p += 2;
+ printer (arg, "complete");
+ }
+ break;
+ default:
+ break;
+ }
+
+ while (p < optend) {
+ GETCHAR(code, p);
+ printer(arg, " %.2x", (int) (unsigned int) (unsigned char) code);
+ }
+ printer(arg, ">");
+ }
+ break;
+
+ case TERMACK:
+ case TERMREQ:
+ if (len > 0 && *p >= ' ' && *p < 0x7f) {
+ printer(arg, " ");
+ print_string(p, len, printer, arg);
+ p += len;
+ len = 0;
+ }
+ break;
+ }
+
+ /* print the rest of the bytes in the packet */
+ for (; len > 0; --len) {
+ GETCHAR(code, p);
+ printer(arg, " %.2x", (int) (unsigned int) (unsigned char) code);
+ }
+
+ return p - pstart;
+}
+#endif /* ifdef IPX_CHANGE */
diff --git a/mdk-stage1/ppp/pppd/ipxcp.h b/mdk-stage1/ppp/pppd/ipxcp.h
new file mode 100644
index 000000000..12bc6700e
--- /dev/null
+++ b/mdk-stage1/ppp/pppd/ipxcp.h
@@ -0,0 +1,71 @@
+/*
+ * ipxcp.h - IPX Control Protocol definitions.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id: ipxcp.h 195720 2001-06-11 11:44:34Z gc $
+ */
+
+/*
+ * Options.
+ */
+#define IPX_NETWORK_NUMBER 1 /* IPX Network Number */
+#define IPX_NODE_NUMBER 2
+#define IPX_COMPRESSION_PROTOCOL 3
+#define IPX_ROUTER_PROTOCOL 4
+#define IPX_ROUTER_NAME 5
+#define IPX_COMPLETE 6
+
+/* Values for the router protocol */
+#define IPX_NONE 0
+#define RIP_SAP 2
+#define NLSP 4
+
+typedef struct ipxcp_options {
+ bool neg_node; /* Negotiate IPX node number? */
+ bool req_node; /* Ask peer to send IPX node number? */
+
+ bool neg_nn; /* Negotiate IPX network number? */
+ bool req_nn; /* Ask peer to send IPX network number */
+
+ bool neg_name; /* Negotiate IPX router name */
+ bool neg_complete; /* Negotiate completion */
+ bool neg_router; /* Negotiate IPX router number */
+
+ bool accept_local; /* accept peer's value for ournode */
+ bool accept_remote; /* accept peer's value for hisnode */
+ bool accept_network; /* accept network number */
+
+ bool tried_nlsp; /* I have suggested NLSP already */
+ bool tried_rip; /* I have suggested RIP/SAP already */
+
+ u_int32_t his_network; /* base network number */
+ u_int32_t our_network; /* our value for network number */
+ u_int32_t network; /* the final network number */
+
+ u_char his_node[6]; /* peer's node number */
+ u_char our_node[6]; /* our node number */
+ u_char name [48]; /* name of the router */
+ int router; /* routing protocol */
+} ipxcp_options;
+
+extern fsm ipxcp_fsm[];
+extern ipxcp_options ipxcp_wantoptions[];
+extern ipxcp_options ipxcp_gotoptions[];
+extern ipxcp_options ipxcp_allowoptions[];
+extern ipxcp_options ipxcp_hisoptions[];
+
+extern struct protent ipxcp_protent;
diff --git a/mdk-stage1/ppp/pppd/lcp.c b/mdk-stage1/ppp/pppd/lcp.c
new file mode 100644
index 000000000..73f7efdbc
--- /dev/null
+++ b/mdk-stage1/ppp/pppd/lcp.c
@@ -0,0 +1,2224 @@
+/*
+ * lcp.c - PPP Link Control Protocol.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#define RCSID "$Id: lcp.c 195720 2001-06-11 11:44:34Z gc $"
+
+/*
+ * TODO:
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "pppd.h"
+#include "fsm.h"
+#include "lcp.h"
+#include "chap.h"
+#include "magic.h"
+
+static const char rcsid[] = RCSID;
+
+/*
+ * When the link comes up we want to be able to wait for a short while,
+ * or until seeing some input from the peer, before starting to send
+ * configure-requests. We do this by delaying the fsm_lowerup call.
+ */
+/* steal a bit in fsm flags word */
+#define DELAYED_UP 0x100
+
+static void lcp_delayed_up __P((void *));
+
+/*
+ * LCP-related command-line options.
+ */
+int lcp_echo_interval = 0; /* Interval between LCP echo-requests */
+int lcp_echo_fails = 0; /* Tolerance to unanswered echo-requests */
+bool lax_recv = 0; /* accept control chars in asyncmap */
+bool noendpoint = 0; /* don't send/accept endpoint discriminator */
+
+static int noopt __P((char **));
+
+#ifdef HAVE_MULTILINK
+static int setendpoint __P((char **));
+static void printendpoint __P((option_t *, void (*)(void *, char *, ...),
+ void *));
+#endif /* HAVE_MULTILINK */
+
+static option_t lcp_option_list[] = {
+ /* LCP options */
+ { "-all", o_special_noarg, (void *)noopt,
+ "Don't request/allow any LCP options" },
+
+ { "noaccomp", o_bool, &lcp_wantoptions[0].neg_accompression,
+ "Disable address/control compression",
+ OPT_A2CLR, &lcp_allowoptions[0].neg_accompression },
+ { "-ac", o_bool, &lcp_wantoptions[0].neg_accompression,
+ "Disable address/control compression",
+ OPT_ALIAS | OPT_A2CLR, &lcp_allowoptions[0].neg_accompression },
+
+ { "asyncmap", o_uint32, &lcp_wantoptions[0].asyncmap,
+ "Set asyncmap (for received packets)",
+ OPT_OR, &lcp_wantoptions[0].neg_asyncmap },
+ { "-as", o_uint32, &lcp_wantoptions[0].asyncmap,
+ "Set asyncmap (for received packets)",
+ OPT_ALIAS | OPT_OR, &lcp_wantoptions[0].neg_asyncmap },
+ { "default-asyncmap", o_uint32, &lcp_wantoptions[0].asyncmap,
+ "Disable asyncmap negotiation",
+ OPT_OR | OPT_NOARG | OPT_VAL(~0U) | OPT_A2CLR,
+ &lcp_allowoptions[0].neg_asyncmap },
+ { "-am", o_uint32, &lcp_wantoptions[0].asyncmap,
+ "Disable asyncmap negotiation",
+ OPT_ALIAS | OPT_OR | OPT_NOARG | OPT_VAL(~0U) | OPT_A2CLR,
+ &lcp_allowoptions[0].neg_asyncmap },
+
+ { "nomagic", o_bool, &lcp_wantoptions[0].neg_magicnumber,
+ "Disable magic number negotiation (looped-back line detection)",
+ OPT_A2CLR, &lcp_allowoptions[0].neg_magicnumber },
+ { "-mn", o_bool, &lcp_wantoptions[0].neg_magicnumber,
+ "Disable magic number negotiation (looped-back line detection)",
+ OPT_ALIAS | OPT_A2CLR, &lcp_allowoptions[0].neg_magicnumber },
+
+ { "mru", o_int, &lcp_wantoptions[0].mru,
+ "Set MRU (maximum received packet size) for negotiation",
+ OPT_PRIO, &lcp_wantoptions[0].neg_mru },
+ { "default-mru", o_bool, &lcp_wantoptions[0].neg_mru,
+ "Disable MRU negotiation (use default 1500)",
+ OPT_PRIOSUB | OPT_A2CLR, &lcp_allowoptions[0].neg_mru },
+ { "-mru", o_bool, &lcp_wantoptions[0].neg_mru,
+ "Disable MRU negotiation (use default 1500)",
+ OPT_ALIAS | OPT_PRIOSUB | OPT_A2CLR, &lcp_allowoptions[0].neg_mru },
+
+ { "mtu", o_int, &lcp_allowoptions[0].mru,
+ "Set our MTU", OPT_LIMITS, NULL, MAXMRU, MINMRU },
+
+ { "nopcomp", o_bool, &lcp_wantoptions[0].neg_pcompression,
+ "Disable protocol field compression",
+ OPT_A2CLR, &lcp_allowoptions[0].neg_pcompression },
+ { "-pc", o_bool, &lcp_wantoptions[0].neg_pcompression,
+ "Disable protocol field compression",
+ OPT_ALIAS | OPT_A2CLR, &lcp_allowoptions[0].neg_pcompression },
+
+ { "passive", o_bool, &lcp_wantoptions[0].passive,
+ "Set passive mode", 1 },
+ { "-p", o_bool, &lcp_wantoptions[0].passive,
+ "Set passive mode", OPT_ALIAS | 1 },
+
+ { "silent", o_bool, &lcp_wantoptions[0].silent,
+ "Set silent mode", 1 },
+
+ { "lcp-echo-failure", o_int, &lcp_echo_fails,
+ "Set number of consecutive echo failures to indicate link failure",
+ OPT_PRIO },
+ { "lcp-echo-interval", o_int, &lcp_echo_interval,
+ "Set time in seconds between LCP echo requests", OPT_PRIO },
+ { "lcp-restart", o_int, &lcp_fsm[0].timeouttime,
+ "Set time in seconds between LCP retransmissions", OPT_PRIO },
+ { "lcp-max-terminate", o_int, &lcp_fsm[0].maxtermtransmits,
+ "Set maximum number of LCP terminate-request transmissions", OPT_PRIO },
+ { "lcp-max-configure", o_int, &lcp_fsm[0].maxconfreqtransmits,
+ "Set maximum number of LCP configure-request transmissions", OPT_PRIO },
+ { "lcp-max-failure", o_int, &lcp_fsm[0].maxnakloops,
+ "Set limit on number of LCP configure-naks", OPT_PRIO },
+
+ { "receive-all", o_bool, &lax_recv,
+ "Accept all received control characters", 1 },
+
+#ifdef HAVE_MULTILINK
+ { "mrru", o_int, &lcp_wantoptions[0].mrru,
+ "Maximum received packet size for multilink bundle",
+ OPT_PRIO, &lcp_wantoptions[0].neg_mrru },
+
+ { "mpshortseq", o_bool, &lcp_wantoptions[0].neg_ssnhf,
+ "Use short sequence numbers in multilink headers",
+ OPT_PRIO | 1, &lcp_allowoptions[0].neg_ssnhf },
+ { "nompshortseq", o_bool, &lcp_wantoptions[0].neg_ssnhf,
+ "Don't use short sequence numbers in multilink headers",
+ OPT_PRIOSUB | OPT_A2CLR, &lcp_allowoptions[0].neg_ssnhf },
+
+ { "endpoint", o_special, (void *) setendpoint,
+ "Endpoint discriminator for multilink",
+ OPT_PRIO | OPT_A2PRINTER, (void *) printendpoint },
+#endif /* HAVE_MULTILINK */
+
+ { "noendpoint", o_bool, &noendpoint,
+ "Don't send or accept multilink endpoint discriminator", 1 },
+
+ {NULL}
+};
+
+/* global vars */
+fsm lcp_fsm[NUM_PPP]; /* LCP fsm structure (global)*/
+lcp_options lcp_wantoptions[NUM_PPP]; /* Options that we want to request */
+lcp_options lcp_gotoptions[NUM_PPP]; /* Options that peer ack'd */
+lcp_options lcp_allowoptions[NUM_PPP]; /* Options we allow peer to request */
+lcp_options lcp_hisoptions[NUM_PPP]; /* Options that we ack'd */
+
+static int lcp_echos_pending = 0; /* Number of outstanding echo msgs */
+static int lcp_echo_number = 0; /* ID number of next echo frame */
+static int lcp_echo_timer_running = 0; /* set if a timer is running */
+
+static u_char nak_buffer[PPP_MRU]; /* where we construct a nak packet */
+
+/*
+ * Callbacks for fsm code. (CI = Configuration Information)
+ */
+static void lcp_resetci __P((fsm *)); /* Reset our CI */
+static int lcp_cilen __P((fsm *)); /* Return length of our CI */
+static void lcp_addci __P((fsm *, u_char *, int *)); /* Add our CI to pkt */
+static int lcp_ackci __P((fsm *, u_char *, int)); /* Peer ack'd our CI */
+static int lcp_nakci __P((fsm *, u_char *, int)); /* Peer nak'd our CI */
+static int lcp_rejci __P((fsm *, u_char *, int)); /* Peer rej'd our CI */
+static int lcp_reqci __P((fsm *, u_char *, int *, int)); /* Rcv peer CI */
+static void lcp_up __P((fsm *)); /* We're UP */
+static void lcp_down __P((fsm *)); /* We're DOWN */
+static void lcp_starting __P((fsm *)); /* We need lower layer up */
+static void lcp_finished __P((fsm *)); /* We need lower layer down */
+static int lcp_extcode __P((fsm *, int, int, u_char *, int));
+static void lcp_rprotrej __P((fsm *, u_char *, int));
+
+/*
+ * routines to send LCP echos to peer
+ */
+
+static void lcp_echo_lowerup __P((int));
+static void lcp_echo_lowerdown __P((int));
+static void LcpEchoTimeout __P((void *));
+static void lcp_received_echo_reply __P((fsm *, int, u_char *, int));
+static void LcpSendEchoRequest __P((fsm *));
+static void LcpLinkFailure __P((fsm *));
+static void LcpEchoCheck __P((fsm *));
+
+static fsm_callbacks lcp_callbacks = { /* LCP callback routines */
+ lcp_resetci, /* Reset our Configuration Information */
+ lcp_cilen, /* Length of our Configuration Information */
+ lcp_addci, /* Add our Configuration Information */
+ lcp_ackci, /* ACK our Configuration Information */
+ lcp_nakci, /* NAK our Configuration Information */
+ lcp_rejci, /* Reject our Configuration Information */
+ lcp_reqci, /* Request peer's Configuration Information */
+ lcp_up, /* Called when fsm reaches OPENED state */
+ lcp_down, /* Called when fsm leaves OPENED state */
+ lcp_starting, /* Called when we want the lower layer up */
+ lcp_finished, /* Called when we want the lower layer down */
+ NULL, /* Called when Protocol-Reject received */
+ NULL, /* Retransmission is necessary */
+ lcp_extcode, /* Called to handle LCP-specific codes */
+ "LCP" /* String name of protocol */
+};
+
+/*
+ * Protocol entry points.
+ * Some of these are called directly.
+ */
+
+static void lcp_init __P((int));
+static void lcp_input __P((int, u_char *, int));
+static void lcp_protrej __P((int));
+static int lcp_printpkt __P((u_char *, int,
+ void (*) __P((void *, char *, ...)), void *));
+
+struct protent lcp_protent = {
+ PPP_LCP,
+ lcp_init,
+ lcp_input,
+ lcp_protrej,
+ lcp_lowerup,
+ lcp_lowerdown,
+ lcp_open,
+ lcp_close,
+ lcp_printpkt,
+ NULL,
+ 1,
+ "LCP",
+ NULL,
+ lcp_option_list,
+ NULL,
+ NULL,
+ NULL
+};
+
+int lcp_loopbackfail = DEFLOOPBACKFAIL;
+
+/*
+ * Length of each type of configuration option (in octets)
+ */
+#define CILEN_VOID 2
+#define CILEN_CHAR 3
+#define CILEN_SHORT 4 /* CILEN_VOID + 2 */
+#define CILEN_CHAP 5 /* CILEN_VOID + 2 + 1 */
+#define CILEN_LONG 6 /* CILEN_VOID + 4 */
+#define CILEN_LQR 8 /* CILEN_VOID + 2 + 4 */
+#define CILEN_CBCP 3
+
+#define CODENAME(x) ((x) == CONFACK ? "ACK" : \
+ (x) == CONFNAK ? "NAK" : "REJ")
+
+/*
+ * noopt - Disable all options (why?).
+ */
+static int
+noopt(argv)
+ char **argv;
+{
+ BZERO((char *) &lcp_wantoptions[0], sizeof (struct lcp_options));
+ BZERO((char *) &lcp_allowoptions[0], sizeof (struct lcp_options));
+
+ return (1);
+}
+
+#ifdef HAVE_MULTILINK
+static int
+setendpoint(argv)
+ char **argv;
+{
+ if (str_to_epdisc(&lcp_wantoptions[0].endpoint, *argv)) {
+ lcp_wantoptions[0].neg_endpoint = 1;
+ return 1;
+ }
+ option_error("Can't parse '%s' as an endpoint discriminator", *argv);
+ return 0;
+}
+
+static void
+printendpoint(opt, printer, arg)
+ option_t *opt;
+ void (*printer) __P((void *, char *, ...));
+ void *arg;
+{
+ printer(arg, "%s", epdisc_to_str(&lcp_wantoptions[0].endpoint));
+}
+#endif /* HAVE_MULTILINK */
+
+/*
+ * lcp_init - Initialize LCP.
+ */
+static void
+lcp_init(unit)
+ int unit;
+{
+ fsm *f = &lcp_fsm[unit];
+ lcp_options *wo = &lcp_wantoptions[unit];
+ lcp_options *ao = &lcp_allowoptions[unit];
+
+ f->unit = unit;
+ f->protocol = PPP_LCP;
+ f->callbacks = &lcp_callbacks;
+
+ fsm_init(f);
+
+ BZERO(wo, sizeof(*wo));
+ wo->neg_mru = 1;
+ wo->mru = DEFMRU;
+ wo->neg_asyncmap = 1;
+ wo->chap_mdtype = CHAP_DIGEST_MD5;
+ wo->neg_magicnumber = 1;
+ wo->neg_pcompression = 1;
+ wo->neg_accompression = 1;
+
+ BZERO(ao, sizeof(*ao));
+ ao->neg_mru = 1;
+ ao->mru = MAXMRU;
+ ao->neg_asyncmap = 1;
+ ao->neg_chap = 1;
+ ao->chap_mdtype = CHAP_DIGEST_MD5;
+ ao->neg_upap = 1;
+ ao->neg_magicnumber = 1;
+ ao->neg_pcompression = 1;
+ ao->neg_accompression = 1;
+#ifdef CBCP_SUPPORT
+ ao->neg_cbcp = 1;
+#endif
+ ao->neg_endpoint = 1;
+}
+
+
+/*
+ * lcp_open - LCP is allowed to come up.
+ */
+void
+lcp_open(unit)
+ int unit;
+{
+ fsm *f = &lcp_fsm[unit];
+ lcp_options *wo = &lcp_wantoptions[unit];
+
+ f->flags &= ~(OPT_PASSIVE | OPT_SILENT);
+ if (wo->passive)
+ f->flags |= OPT_PASSIVE;
+ if (wo->silent)
+ f->flags |= OPT_SILENT;
+ fsm_open(f);
+}
+
+
+/*
+ * lcp_close - Take LCP down.
+ */
+void
+lcp_close(unit, reason)
+ int unit;
+ char *reason;
+{
+ fsm *f = &lcp_fsm[unit];
+
+ if (phase != PHASE_DEAD)
+ new_phase(PHASE_TERMINATE);
+ if (f->state == STOPPED && f->flags & (OPT_PASSIVE|OPT_SILENT)) {
+ /*
+ * This action is not strictly according to the FSM in RFC1548,
+ * but it does mean that the program terminates if you do a
+ * lcp_close() in passive/silent mode when a connection hasn't
+ * been established.
+ */
+ f->state = CLOSED;
+ lcp_finished(f);
+
+ } else
+ fsm_close(&lcp_fsm[unit], reason);
+}
+
+
+/*
+ * lcp_lowerup - The lower layer is up.
+ */
+void
+lcp_lowerup(unit)
+ int unit;
+{
+ lcp_options *wo = &lcp_wantoptions[unit];
+ fsm *f = &lcp_fsm[unit];
+
+ /*
+ * Don't use A/C or protocol compression on transmission,
+ * but accept A/C and protocol compressed packets
+ * if we are going to ask for A/C and protocol compression.
+ */
+ ppp_send_config(unit, PPP_MRU, 0xffffffff, 0, 0);
+ ppp_recv_config(unit, PPP_MRU, (lax_recv? 0: 0xffffffff),
+ wo->neg_pcompression, wo->neg_accompression);
+ peer_mru[unit] = PPP_MRU;
+
+ if (listen_time != 0) {
+ f->flags |= DELAYED_UP;
+ timeout(lcp_delayed_up, f, 0, listen_time * 1000);
+ } else
+ fsm_lowerup(f);
+}
+
+
+/*
+ * lcp_lowerdown - The lower layer is down.
+ */
+void
+lcp_lowerdown(unit)
+ int unit;
+{
+ fsm *f = &lcp_fsm[unit];
+
+ if (f->flags & DELAYED_UP)
+ f->flags &= ~DELAYED_UP;
+ else
+ fsm_lowerdown(&lcp_fsm[unit]);
+}
+
+
+/*
+ * lcp_delayed_up - Bring the lower layer up now.
+ */
+static void
+lcp_delayed_up(arg)
+ void *arg;
+{
+ fsm *f = arg;
+
+ if (f->flags & DELAYED_UP) {
+ f->flags &= ~DELAYED_UP;
+ fsm_lowerup(f);
+ }
+}
+
+
+/*
+ * lcp_input - Input LCP packet.
+ */
+static void
+lcp_input(unit, p, len)
+ int unit;
+ u_char *p;
+ int len;
+{
+ fsm *f = &lcp_fsm[unit];
+
+ if (f->flags & DELAYED_UP) {
+ f->flags &= ~DELAYED_UP;
+ fsm_lowerup(f);
+ }
+ fsm_input(f, p, len);
+}
+
+
+/*
+ * lcp_extcode - Handle a LCP-specific code.
+ */
+static int
+lcp_extcode(f, code, id, inp, len)
+ fsm *f;
+ int code, id;
+ u_char *inp;
+ int len;
+{
+ u_char *magp;
+
+ switch( code ){
+ case PROTREJ:
+ lcp_rprotrej(f, inp, len);
+ break;
+
+ case ECHOREQ:
+ if (f->state != OPENED)
+ break;
+ magp = inp;
+ PUTLONG(lcp_gotoptions[f->unit].magicnumber, magp);
+ fsm_sdata(f, ECHOREP, id, inp, len);
+ break;
+
+ case ECHOREP:
+ lcp_received_echo_reply(f, id, inp, len);
+ break;
+
+ case DISCREQ:
+ break;
+
+ default:
+ return 0;
+ }
+ return 1;
+}
+
+
+/*
+ * lcp_rprotrej - Receive an Protocol-Reject.
+ *
+ * Figure out which protocol is rejected and inform it.
+ */
+static void
+lcp_rprotrej(f, inp, len)
+ fsm *f;
+ u_char *inp;
+ int len;
+{
+ int i;
+ struct protent *protp;
+ u_short prot;
+
+ if (len < 2) {
+ LCPDEBUG(("lcp_rprotrej: Rcvd short Protocol-Reject packet!"));
+ return;
+ }
+
+ GETSHORT(prot, inp);
+
+ /*
+ * Protocol-Reject packets received in any state other than the LCP
+ * OPENED state SHOULD be silently discarded.
+ */
+ if( f->state != OPENED ){
+ LCPDEBUG(("Protocol-Reject discarded: LCP in state %d", f->state));
+ return;
+ }
+
+ /*
+ * Upcall the proper Protocol-Reject routine.
+ */
+ for (i = 0; (protp = protocols[i]) != NULL; ++i)
+ if (protp->protocol == prot && protp->enabled_flag) {
+ (*protp->protrej)(f->unit);
+ return;
+ }
+
+ warn("Protocol-Reject for unsupported protocol 0x%x", prot);
+}
+
+
+/*
+ * lcp_protrej - A Protocol-Reject was received.
+ */
+/*ARGSUSED*/
+static void
+lcp_protrej(unit)
+ int unit;
+{
+ /*
+ * Can't reject LCP!
+ */
+ error("Received Protocol-Reject for LCP!");
+ fsm_protreject(&lcp_fsm[unit]);
+}
+
+
+/*
+ * lcp_sprotrej - Send a Protocol-Reject for some protocol.
+ */
+void
+lcp_sprotrej(unit, p, len)
+ int unit;
+ u_char *p;
+ int len;
+{
+ /*
+ * Send back the protocol and the information field of the
+ * rejected packet. We only get here if LCP is in the OPENED state.
+ */
+ p += 2;
+ len -= 2;
+
+ fsm_sdata(&lcp_fsm[unit], PROTREJ, ++lcp_fsm[unit].id,
+ p, len);
+}
+
+
+/*
+ * lcp_resetci - Reset our CI.
+ */
+static void
+lcp_resetci(f)
+ fsm *f;
+{
+ lcp_options *wo = &lcp_wantoptions[f->unit];
+ lcp_options *go = &lcp_gotoptions[f->unit];
+ lcp_options *ao = &lcp_allowoptions[f->unit];
+
+ wo->magicnumber = magic();
+ wo->numloops = 0;
+ *go = *wo;
+ if (!multilink) {
+ go->neg_mrru = 0;
+ go->neg_ssnhf = 0;
+ go->neg_endpoint = 0;
+ }
+ if (noendpoint)
+ ao->neg_endpoint = 0;
+ peer_mru[f->unit] = PPP_MRU;
+ auth_reset(f->unit);
+}
+
+
+/*
+ * lcp_cilen - Return length of our CI.
+ */
+static int
+lcp_cilen(f)
+ fsm *f;
+{
+ lcp_options *go = &lcp_gotoptions[f->unit];
+
+#define LENCIVOID(neg) ((neg) ? CILEN_VOID : 0)
+#define LENCICHAP(neg) ((neg) ? CILEN_CHAP : 0)
+#define LENCISHORT(neg) ((neg) ? CILEN_SHORT : 0)
+#define LENCILONG(neg) ((neg) ? CILEN_LONG : 0)
+#define LENCILQR(neg) ((neg) ? CILEN_LQR: 0)
+#define LENCICBCP(neg) ((neg) ? CILEN_CBCP: 0)
+ /*
+ * NB: we only ask for one of CHAP and UPAP, even if we will
+ * accept either.
+ */
+ return (LENCISHORT(go->neg_mru && go->mru != DEFMRU) +
+ LENCILONG(go->neg_asyncmap && go->asyncmap != 0xFFFFFFFF) +
+ LENCICHAP(go->neg_chap) +
+ LENCISHORT(!go->neg_chap && go->neg_upap) +
+ LENCILQR(go->neg_lqr) +
+ LENCICBCP(go->neg_cbcp) +
+ LENCILONG(go->neg_magicnumber) +
+ LENCIVOID(go->neg_pcompression) +
+ LENCIVOID(go->neg_accompression) +
+ LENCISHORT(go->neg_mrru) +
+ LENCIVOID(go->neg_ssnhf) +
+ (go->neg_endpoint? CILEN_CHAR + go->endpoint.length: 0));
+}
+
+
+/*
+ * lcp_addci - Add our desired CIs to a packet.
+ */
+static void
+lcp_addci(f, ucp, lenp)
+ fsm *f;
+ u_char *ucp;
+ int *lenp;
+{
+ lcp_options *go = &lcp_gotoptions[f->unit];
+ u_char *start_ucp = ucp;
+
+#define ADDCIVOID(opt, neg) \
+ if (neg) { \
+ PUTCHAR(opt, ucp); \
+ PUTCHAR(CILEN_VOID, ucp); \
+ }
+#define ADDCISHORT(opt, neg, val) \
+ if (neg) { \
+ PUTCHAR(opt, ucp); \
+ PUTCHAR(CILEN_SHORT, ucp); \
+ PUTSHORT(val, ucp); \
+ }
+#define ADDCICHAP(opt, neg, val, digest) \
+ if (neg) { \
+ PUTCHAR(opt, ucp); \
+ PUTCHAR(CILEN_CHAP, ucp); \
+ PUTSHORT(val, ucp); \
+ PUTCHAR(digest, ucp); \
+ }
+#define ADDCILONG(opt, neg, val) \
+ if (neg) { \
+ PUTCHAR(opt, ucp); \
+ PUTCHAR(CILEN_LONG, ucp); \
+ PUTLONG(val, ucp); \
+ }
+#define ADDCILQR(opt, neg, val) \
+ if (neg) { \
+ PUTCHAR(opt, ucp); \
+ PUTCHAR(CILEN_LQR, ucp); \
+ PUTSHORT(PPP_LQR, ucp); \
+ PUTLONG(val, ucp); \
+ }
+#define ADDCICHAR(opt, neg, val) \
+ if (neg) { \
+ PUTCHAR(opt, ucp); \
+ PUTCHAR(CILEN_CHAR, ucp); \
+ PUTCHAR(val, ucp); \
+ }
+#define ADDCIENDP(opt, neg, class, val, len) \
+ if (neg) { \
+ int i; \
+ PUTCHAR(opt, ucp); \
+ PUTCHAR(CILEN_CHAR + len, ucp); \
+ PUTCHAR(class, ucp); \
+ for (i = 0; i < len; ++i) \
+ PUTCHAR(val[i], ucp); \
+ }
+
+ ADDCISHORT(CI_MRU, go->neg_mru && go->mru != DEFMRU, go->mru);
+ ADDCILONG(CI_ASYNCMAP, go->neg_asyncmap && go->asyncmap != 0xFFFFFFFF,
+ go->asyncmap);
+ ADDCICHAP(CI_AUTHTYPE, go->neg_chap, PPP_CHAP, go->chap_mdtype);
+ ADDCISHORT(CI_AUTHTYPE, !go->neg_chap && go->neg_upap, PPP_PAP);
+ ADDCILQR(CI_QUALITY, go->neg_lqr, go->lqr_period);
+ ADDCICHAR(CI_CALLBACK, go->neg_cbcp, CBCP_OPT);
+ ADDCILONG(CI_MAGICNUMBER, go->neg_magicnumber, go->magicnumber);
+ ADDCIVOID(CI_PCOMPRESSION, go->neg_pcompression);
+ ADDCIVOID(CI_ACCOMPRESSION, go->neg_accompression);
+ ADDCISHORT(CI_MRRU, go->neg_mrru, go->mrru);
+ ADDCIVOID(CI_SSNHF, go->neg_ssnhf);
+ ADDCIENDP(CI_EPDISC, go->neg_endpoint, go->endpoint.class,
+ go->endpoint.value, go->endpoint.length);
+
+ if (ucp - start_ucp != *lenp) {
+ /* this should never happen, because peer_mtu should be 1500 */
+ error("Bug in lcp_addci: wrong length");
+ }
+}
+
+
+/*
+ * lcp_ackci - Ack our CIs.
+ * This should not modify any state if the Ack is bad.
+ *
+ * Returns:
+ * 0 - Ack was bad.
+ * 1 - Ack was good.
+ */
+static int
+lcp_ackci(f, p, len)
+ fsm *f;
+ u_char *p;
+ int len;
+{
+ lcp_options *go = &lcp_gotoptions[f->unit];
+ u_char cilen, citype, cichar;
+ u_short cishort;
+ u_int32_t cilong;
+
+ /*
+ * CIs must be in exactly the same order that we sent.
+ * Check packet length and CI length at each step.
+ * If we find any deviations, then this packet is bad.
+ */
+#define ACKCIVOID(opt, neg) \
+ if (neg) { \
+ if ((len -= CILEN_VOID) < 0) \
+ goto bad; \
+ GETCHAR(citype, p); \
+ GETCHAR(cilen, p); \
+ if (cilen != CILEN_VOID || \
+ citype != opt) \
+ goto bad; \
+ }
+#define ACKCISHORT(opt, neg, val) \
+ if (neg) { \
+ if ((len -= CILEN_SHORT) < 0) \
+ goto bad; \
+ GETCHAR(citype, p); \
+ GETCHAR(cilen, p); \
+ if (cilen != CILEN_SHORT || \
+ citype != opt) \
+ goto bad; \
+ GETSHORT(cishort, p); \
+ if (cishort != val) \
+ goto bad; \
+ }
+#define ACKCICHAR(opt, neg, val) \
+ if (neg) { \
+ if ((len -= CILEN_CHAR) < 0) \
+ goto bad; \
+ GETCHAR(citype, p); \
+ GETCHAR(cilen, p); \
+ if (cilen != CILEN_CHAR || \
+ citype != opt) \
+ goto bad; \
+ GETCHAR(cichar, p); \
+ if (cichar != val) \
+ goto bad; \
+ }
+#define ACKCICHAP(opt, neg, val, digest) \
+ if (neg) { \
+ if ((len -= CILEN_CHAP) < 0) \
+ goto bad; \
+ GETCHAR(citype, p); \
+ GETCHAR(cilen, p); \
+ if (cilen != CILEN_CHAP || \
+ citype != opt) \
+ goto bad; \
+ GETSHORT(cishort, p); \
+ if (cishort != val) \
+ goto bad; \
+ GETCHAR(cichar, p); \
+ if (cichar != digest) \
+ goto bad; \
+ }
+#define ACKCILONG(opt, neg, val) \
+ if (neg) { \
+ if ((len -= CILEN_LONG) < 0) \
+ goto bad; \
+ GETCHAR(citype, p); \
+ GETCHAR(cilen, p); \
+ if (cilen != CILEN_LONG || \
+ citype != opt) \
+ goto bad; \
+ GETLONG(cilong, p); \
+ if (cilong != val) \
+ goto bad; \
+ }
+#define ACKCILQR(opt, neg, val) \
+ if (neg) { \
+ if ((len -= CILEN_LQR) < 0) \
+ goto bad; \
+ GETCHAR(citype, p); \
+ GETCHAR(cilen, p); \
+ if (cilen != CILEN_LQR || \
+ citype != opt) \
+ goto bad; \
+ GETSHORT(cishort, p); \
+ if (cishort != PPP_LQR) \
+ goto bad; \
+ GETLONG(cilong, p); \
+ if (cilong != val) \
+ goto bad; \
+ }
+#define ACKCIENDP(opt, neg, class, val, vlen) \
+ if (neg) { \
+ int i; \
+ if ((len -= CILEN_CHAR + vlen) < 0) \
+ goto bad; \
+ GETCHAR(citype, p); \
+ GETCHAR(cilen, p); \
+ if (cilen != CILEN_CHAR + vlen || \
+ citype != opt) \
+ goto bad; \
+ GETCHAR(cichar, p); \
+ if (cichar != class) \
+ goto bad; \
+ for (i = 0; i < vlen; ++i) { \
+ GETCHAR(cichar, p); \
+ if (cichar != val[i]) \
+ goto bad; \
+ } \
+ }
+
+ ACKCISHORT(CI_MRU, go->neg_mru && go->mru != DEFMRU, go->mru);
+ ACKCILONG(CI_ASYNCMAP, go->neg_asyncmap && go->asyncmap != 0xFFFFFFFF,
+ go->asyncmap);
+ ACKCICHAP(CI_AUTHTYPE, go->neg_chap, PPP_CHAP, go->chap_mdtype);
+ ACKCISHORT(CI_AUTHTYPE, !go->neg_chap && go->neg_upap, PPP_PAP);
+ ACKCILQR(CI_QUALITY, go->neg_lqr, go->lqr_period);
+ ACKCICHAR(CI_CALLBACK, go->neg_cbcp, CBCP_OPT);
+ ACKCILONG(CI_MAGICNUMBER, go->neg_magicnumber, go->magicnumber);
+ ACKCIVOID(CI_PCOMPRESSION, go->neg_pcompression);
+ ACKCIVOID(CI_ACCOMPRESSION, go->neg_accompression);
+ ACKCISHORT(CI_MRRU, go->neg_mrru, go->mrru);
+ ACKCIVOID(CI_SSNHF, go->neg_ssnhf);
+ ACKCIENDP(CI_EPDISC, go->neg_endpoint, go->endpoint.class,
+ go->endpoint.value, go->endpoint.length);
+
+ /*
+ * If there are any remaining CIs, then this packet is bad.
+ */
+ if (len != 0)
+ goto bad;
+ return (1);
+bad:
+ LCPDEBUG(("lcp_acki: received bad Ack!"));
+ return (0);
+}
+
+
+/*
+ * lcp_nakci - Peer has sent a NAK for some of our CIs.
+ * This should not modify any state if the Nak is bad
+ * or if LCP is in the OPENED state.
+ *
+ * Returns:
+ * 0 - Nak was bad.
+ * 1 - Nak was good.
+ */
+static int
+lcp_nakci(f, p, len)
+ fsm *f;
+ u_char *p;
+ int len;
+{
+ lcp_options *go = &lcp_gotoptions[f->unit];
+ lcp_options *wo = &lcp_wantoptions[f->unit];
+ u_char citype, cichar, *next;
+ u_short cishort;
+ u_int32_t cilong;
+ lcp_options no; /* options we've seen Naks for */
+ lcp_options try; /* options to request next time */
+ int looped_back = 0;
+ int cilen;
+
+ BZERO(&no, sizeof(no));
+ try = *go;
+
+ /*
+ * Any Nak'd CIs must be in exactly the same order that we sent.
+ * Check packet length and CI length at each step.
+ * If we find any deviations, then this packet is bad.
+ */
+#define NAKCIVOID(opt, neg) \
+ if (go->neg && \
+ len >= CILEN_VOID && \
+ p[1] == CILEN_VOID && \
+ p[0] == opt) { \
+ len -= CILEN_VOID; \
+ INCPTR(CILEN_VOID, p); \
+ no.neg = 1; \
+ try.neg = 0; \
+ }
+#define NAKCICHAP(opt, neg, code) \
+ if (go->neg && \
+ len >= CILEN_CHAP && \
+ p[1] == CILEN_CHAP && \
+ p[0] == opt) { \
+ len -= CILEN_CHAP; \
+ INCPTR(2, p); \
+ GETSHORT(cishort, p); \
+ GETCHAR(cichar, p); \
+ no.neg = 1; \
+ code \
+ }
+#define NAKCICHAR(opt, neg, code) \
+ if (go->neg && \
+ len >= CILEN_CHAR && \
+ p[1] == CILEN_CHAR && \
+ p[0] == opt) { \
+ len -= CILEN_CHAR; \
+ INCPTR(2, p); \
+ GETCHAR(cichar, p); \
+ no.neg = 1; \
+ code \
+ }
+#define NAKCISHORT(opt, neg, code) \
+ if (go->neg && \
+ len >= CILEN_SHORT && \
+ p[1] == CILEN_SHORT && \
+ p[0] == opt) { \
+ len -= CILEN_SHORT; \
+ INCPTR(2, p); \
+ GETSHORT(cishort, p); \
+ no.neg = 1; \
+ code \
+ }
+#define NAKCILONG(opt, neg, code) \
+ if (go->neg && \
+ len >= CILEN_LONG && \
+ p[1] == CILEN_LONG && \
+ p[0] == opt) { \
+ len -= CILEN_LONG; \
+ INCPTR(2, p); \
+ GETLONG(cilong, p); \
+ no.neg = 1; \
+ code \
+ }
+#define NAKCILQR(opt, neg, code) \
+ if (go->neg && \
+ len >= CILEN_LQR && \
+ p[1] == CILEN_LQR && \
+ p[0] == opt) { \
+ len -= CILEN_LQR; \
+ INCPTR(2, p); \
+ GETSHORT(cishort, p); \
+ GETLONG(cilong, p); \
+ no.neg = 1; \
+ code \
+ }
+#define NAKCIENDP(opt, neg) \
+ if (go->neg && \
+ len >= CILEN_CHAR && \
+ p[0] == opt && \
+ p[1] >= CILEN_CHAR && \
+ p[1] <= len) { \
+ len -= p[1]; \
+ INCPTR(p[1], p); \
+ no.neg = 1; \
+ try.neg = 0; \
+ }
+
+ /*
+ * We don't care if they want to send us smaller packets than
+ * we want. Therefore, accept any MRU less than what we asked for,
+ * but then ignore the new value when setting the MRU in the kernel.
+ * If they send us a bigger MRU than what we asked, accept it, up to
+ * the limit of the default MRU we'd get if we didn't negotiate.
+ */
+ if (go->neg_mru && go->mru != DEFMRU) {
+ NAKCISHORT(CI_MRU, neg_mru,
+ if (cishort <= wo->mru || cishort <= DEFMRU)
+ try.mru = cishort;
+ );
+ }
+
+ /*
+ * Add any characters they want to our (receive-side) asyncmap.
+ */
+ if (go->neg_asyncmap && go->asyncmap != 0xFFFFFFFF) {
+ NAKCILONG(CI_ASYNCMAP, neg_asyncmap,
+ try.asyncmap = go->asyncmap | cilong;
+ );
+ }
+
+ /*
+ * If they've nak'd our authentication-protocol, check whether
+ * they are proposing a different protocol, or a different
+ * hash algorithm for CHAP.
+ */
+ if ((go->neg_chap || go->neg_upap)
+ && len >= CILEN_SHORT
+ && p[0] == CI_AUTHTYPE && p[1] >= CILEN_SHORT && p[1] <= len) {
+ cilen = p[1];
+ len -= cilen;
+ no.neg_chap = go->neg_chap;
+ no.neg_upap = go->neg_upap;
+ INCPTR(2, p);
+ GETSHORT(cishort, p);
+ if (cishort == PPP_PAP && cilen == CILEN_SHORT) {
+ /*
+ * If we were asking for CHAP, they obviously don't want to do it.
+ * If we weren't asking for CHAP, then we were asking for PAP,
+ * in which case this Nak is bad.
+ */
+ if (!go->neg_chap)
+ goto bad;
+ try.neg_chap = 0;
+
+ } else if (cishort == PPP_CHAP && cilen == CILEN_CHAP) {
+ GETCHAR(cichar, p);
+ if (go->neg_chap) {
+ /*
+ * We were asking for CHAP/MD5; they must want a different
+ * algorithm. If they can't do MD5, we can ask for M$-CHAP
+ * if we support it, otherwise we'll have to stop
+ * asking for CHAP.
+ */
+ if (cichar != go->chap_mdtype) {
+#ifdef CHAPMS
+ if (cichar == CHAP_MICROSOFT)
+ go->chap_mdtype = CHAP_MICROSOFT;
+ else
+#endif /* CHAPMS */
+ try.neg_chap = 0;
+ }
+ } else {
+ /*
+ * Stop asking for PAP if we were asking for it.
+ */
+ try.neg_upap = 0;
+ }
+
+ } else {
+ /*
+ * We don't recognize what they're suggesting.
+ * Stop asking for what we were asking for.
+ */
+ if (go->neg_chap)
+ try.neg_chap = 0;
+ else
+ try.neg_upap = 0;
+ p += cilen - CILEN_SHORT;
+ }
+ }
+
+ /*
+ * If they can't cope with our link quality protocol, we'll have
+ * to stop asking for LQR. We haven't got any other protocol.
+ * If they Nak the reporting period, take their value XXX ?
+ */
+ NAKCILQR(CI_QUALITY, neg_lqr,
+ if (cishort != PPP_LQR)
+ try.neg_lqr = 0;
+ else
+ try.lqr_period = cilong;
+ );
+
+ /*
+ * Only implementing CBCP...not the rest of the callback options
+ */
+ NAKCICHAR(CI_CALLBACK, neg_cbcp,
+ try.neg_cbcp = 0;
+ );
+
+ /*
+ * Check for a looped-back line.
+ */
+ NAKCILONG(CI_MAGICNUMBER, neg_magicnumber,
+ try.magicnumber = magic();
+ looped_back = 1;
+ );
+
+ /*
+ * Peer shouldn't send Nak for protocol compression or
+ * address/control compression requests; they should send
+ * a Reject instead. If they send a Nak, treat it as a Reject.
+ */
+ NAKCIVOID(CI_PCOMPRESSION, neg_pcompression);
+ NAKCIVOID(CI_ACCOMPRESSION, neg_accompression);
+
+ /*
+ * Nak for MRRU option - accept their value if it is smaller
+ * than the one we want.
+ */
+ if (go->neg_mrru) {
+ NAKCISHORT(CI_MRRU, neg_mrru,
+ if (cishort <= wo->mrru)
+ try.mrru = cishort;
+ );
+ }
+
+ /*
+ * Nak for short sequence numbers shouldn't be sent, treat it
+ * like a reject.
+ */
+ NAKCIVOID(CI_SSNHF, neg_ssnhf);
+
+ /*
+ * Nak of the endpoint discriminator option is not permitted,
+ * treat it like a reject.
+ */
+ NAKCIENDP(CI_EPDISC, neg_endpoint);
+
+ /*
+ * There may be remaining CIs, if the peer is requesting negotiation
+ * on an option that we didn't include in our request packet.
+ * If we see an option that we requested, or one we've already seen
+ * in this packet, then this packet is bad.
+ * If we wanted to respond by starting to negotiate on the requested
+ * option(s), we could, but we don't, because except for the
+ * authentication type and quality protocol, if we are not negotiating
+ * an option, it is because we were told not to.
+ * For the authentication type, the Nak from the peer means
+ * `let me authenticate myself with you' which is a bit pointless.
+ * For the quality protocol, the Nak means `ask me to send you quality
+ * reports', but if we didn't ask for them, we don't want them.
+ * An option we don't recognize represents the peer asking to
+ * negotiate some option we don't support, so ignore it.
+ */
+ while (len > CILEN_VOID) {
+ GETCHAR(citype, p);
+ GETCHAR(cilen, p);
+ if (cilen < CILEN_VOID || (len -= cilen) < 0)
+ goto bad;
+ next = p + cilen - 2;
+
+ switch (citype) {
+ case CI_MRU:
+ if ((go->neg_mru && go->mru != DEFMRU)
+ || no.neg_mru || cilen != CILEN_SHORT)
+ goto bad;
+ GETSHORT(cishort, p);
+ if (cishort < DEFMRU) {
+ try.neg_mru = 1;
+ try.mru = cishort;
+ }
+ break;
+ case CI_ASYNCMAP:
+ if ((go->neg_asyncmap && go->asyncmap != 0xFFFFFFFF)
+ || no.neg_asyncmap || cilen != CILEN_LONG)
+ goto bad;
+ break;
+ case CI_AUTHTYPE:
+ if (go->neg_chap || no.neg_chap || go->neg_upap || no.neg_upap)
+ goto bad;
+ break;
+ case CI_MAGICNUMBER:
+ if (go->neg_magicnumber || no.neg_magicnumber ||
+ cilen != CILEN_LONG)
+ goto bad;
+ break;
+ case CI_PCOMPRESSION:
+ if (go->neg_pcompression || no.neg_pcompression
+ || cilen != CILEN_VOID)
+ goto bad;
+ break;
+ case CI_ACCOMPRESSION:
+ if (go->neg_accompression || no.neg_accompression
+ || cilen != CILEN_VOID)
+ goto bad;
+ break;
+ case CI_QUALITY:
+ if (go->neg_lqr || no.neg_lqr || cilen != CILEN_LQR)
+ goto bad;
+ break;
+ case CI_MRRU:
+ if (go->neg_mrru || no.neg_mrru || cilen != CILEN_SHORT)
+ goto bad;
+ break;
+ case CI_SSNHF:
+ if (go->neg_ssnhf || no.neg_ssnhf || cilen != CILEN_VOID)
+ goto bad;
+ try.neg_ssnhf = 1;
+ break;
+ case CI_EPDISC:
+ if (go->neg_endpoint || no.neg_endpoint || cilen < CILEN_CHAR)
+ goto bad;
+ break;
+ }
+ p = next;
+ }
+
+ /*
+ * OK, the Nak is good. Now we can update state.
+ * If there are any options left we ignore them.
+ */
+ if (f->state != OPENED) {
+ if (looped_back) {
+ if (++try.numloops >= lcp_loopbackfail) {
+ notice("Serial line is looped back.");
+ lcp_close(f->unit, "Loopback detected");
+ status = EXIT_LOOPBACK;
+ }
+ } else
+ try.numloops = 0;
+ *go = try;
+ }
+
+ return 1;
+
+bad:
+ LCPDEBUG(("lcp_nakci: received bad Nak!"));
+ return 0;
+}
+
+
+/*
+ * lcp_rejci - Peer has Rejected some of our CIs.
+ * This should not modify any state if the Reject is bad
+ * or if LCP is in the OPENED state.
+ *
+ * Returns:
+ * 0 - Reject was bad.
+ * 1 - Reject was good.
+ */
+static int
+lcp_rejci(f, p, len)
+ fsm *f;
+ u_char *p;
+ int len;
+{
+ lcp_options *go = &lcp_gotoptions[f->unit];
+ u_char cichar;
+ u_short cishort;
+ u_int32_t cilong;
+ lcp_options try; /* options to request next time */
+
+ try = *go;
+
+ /*
+ * Any Rejected CIs must be in exactly the same order that we sent.
+ * Check packet length and CI length at each step.
+ * If we find any deviations, then this packet is bad.
+ */
+#define REJCIVOID(opt, neg) \
+ if (go->neg && \
+ len >= CILEN_VOID && \
+ p[1] == CILEN_VOID && \
+ p[0] == opt) { \
+ len -= CILEN_VOID; \
+ INCPTR(CILEN_VOID, p); \
+ try.neg = 0; \
+ }
+#define REJCISHORT(opt, neg, val) \
+ if (go->neg && \
+ len >= CILEN_SHORT && \
+ p[1] == CILEN_SHORT && \
+ p[0] == opt) { \
+ len -= CILEN_SHORT; \
+ INCPTR(2, p); \
+ GETSHORT(cishort, p); \
+ /* Check rejected value. */ \
+ if (cishort != val) \
+ goto bad; \
+ try.neg = 0; \
+ }
+#define REJCICHAP(opt, neg, val, digest) \
+ if (go->neg && \
+ len >= CILEN_CHAP && \
+ p[1] == CILEN_CHAP && \
+ p[0] == opt) { \
+ len -= CILEN_CHAP; \
+ INCPTR(2, p); \
+ GETSHORT(cishort, p); \
+ GETCHAR(cichar, p); \
+ /* Check rejected value. */ \
+ if (cishort != val || cichar != digest) \
+ goto bad; \
+ try.neg = 0; \
+ try.neg_upap = 0; \
+ }
+#define REJCILONG(opt, neg, val) \
+ if (go->neg && \
+ len >= CILEN_LONG && \
+ p[1] == CILEN_LONG && \
+ p[0] == opt) { \
+ len -= CILEN_LONG; \
+ INCPTR(2, p); \
+ GETLONG(cilong, p); \
+ /* Check rejected value. */ \
+ if (cilong != val) \
+ goto bad; \
+ try.neg = 0; \
+ }
+#define REJCILQR(opt, neg, val) \
+ if (go->neg && \
+ len >= CILEN_LQR && \
+ p[1] == CILEN_LQR && \
+ p[0] == opt) { \
+ len -= CILEN_LQR; \
+ INCPTR(2, p); \
+ GETSHORT(cishort, p); \
+ GETLONG(cilong, p); \
+ /* Check rejected value. */ \
+ if (cishort != PPP_LQR || cilong != val) \
+ goto bad; \
+ try.neg = 0; \
+ }
+#define REJCICBCP(opt, neg, val) \
+ if (go->neg && \
+ len >= CILEN_CBCP && \
+ p[1] == CILEN_CBCP && \
+ p[0] == opt) { \
+ len -= CILEN_CBCP; \
+ INCPTR(2, p); \
+ GETCHAR(cichar, p); \
+ /* Check rejected value. */ \
+ if (cichar != val) \
+ goto bad; \
+ try.neg = 0; \
+ }
+#define REJCIENDP(opt, neg, class, val, vlen) \
+ if (go->neg && \
+ len >= CILEN_CHAR + vlen && \
+ p[0] == opt && \
+ p[1] == CILEN_CHAR + vlen) { \
+ int i; \
+ len -= CILEN_CHAR + vlen; \
+ INCPTR(2, p); \
+ GETCHAR(cichar, p); \
+ if (cichar != class) \
+ goto bad; \
+ for (i = 0; i < vlen; ++i) { \
+ GETCHAR(cichar, p); \
+ if (cichar != val[i]) \
+ goto bad; \
+ } \
+ try.neg = 0; \
+ }
+
+ REJCISHORT(CI_MRU, neg_mru, go->mru);
+ REJCILONG(CI_ASYNCMAP, neg_asyncmap, go->asyncmap);
+ REJCICHAP(CI_AUTHTYPE, neg_chap, PPP_CHAP, go->chap_mdtype);
+ if (!go->neg_chap) {
+ REJCISHORT(CI_AUTHTYPE, neg_upap, PPP_PAP);
+ }
+ REJCILQR(CI_QUALITY, neg_lqr, go->lqr_period);
+ REJCICBCP(CI_CALLBACK, neg_cbcp, CBCP_OPT);
+ REJCILONG(CI_MAGICNUMBER, neg_magicnumber, go->magicnumber);
+ REJCIVOID(CI_PCOMPRESSION, neg_pcompression);
+ REJCIVOID(CI_ACCOMPRESSION, neg_accompression);
+ REJCISHORT(CI_MRRU, neg_mrru, go->mrru);
+ REJCIVOID(CI_SSNHF, neg_ssnhf);
+ REJCIENDP(CI_EPDISC, neg_endpoint, go->endpoint.class,
+ go->endpoint.value, go->endpoint.length);
+
+ /*
+ * If there are any remaining CIs, then this packet is bad.
+ */
+ if (len != 0)
+ goto bad;
+ /*
+ * Now we can update state.
+ */
+ if (f->state != OPENED)
+ *go = try;
+ return 1;
+
+bad:
+ LCPDEBUG(("lcp_rejci: received bad Reject!"));
+ return 0;
+}
+
+
+/*
+ * lcp_reqci - Check the peer's requested CIs and send appropriate response.
+ *
+ * Returns: CONFACK, CONFNAK or CONFREJ and input packet modified
+ * appropriately. If reject_if_disagree is non-zero, doesn't return
+ * CONFNAK; returns CONFREJ if it can't return CONFACK.
+ */
+static int
+lcp_reqci(f, inp, lenp, reject_if_disagree)
+ fsm *f;
+ u_char *inp; /* Requested CIs */
+ int *lenp; /* Length of requested CIs */
+ int reject_if_disagree;
+{
+ lcp_options *go = &lcp_gotoptions[f->unit];
+ lcp_options *ho = &lcp_hisoptions[f->unit];
+ lcp_options *ao = &lcp_allowoptions[f->unit];
+ u_char *cip, *next; /* Pointer to current and next CIs */
+ int cilen, citype, cichar; /* Parsed len, type, char value */
+ u_short cishort; /* Parsed short value */
+ u_int32_t cilong; /* Parse long value */
+ int rc = CONFACK; /* Final packet return code */
+ int orc; /* Individual option return code */
+ u_char *p; /* Pointer to next char to parse */
+ u_char *rejp; /* Pointer to next char in reject frame */
+ u_char *nakp; /* Pointer to next char in Nak frame */
+ int l = *lenp; /* Length left */
+
+ /*
+ * Reset all his options.
+ */
+ BZERO(ho, sizeof(*ho));
+
+ /*
+ * Process all his options.
+ */
+ next = inp;
+ nakp = nak_buffer;
+ rejp = inp;
+ while (l) {
+ orc = CONFACK; /* Assume success */
+ cip = p = next; /* Remember begining of CI */
+ if (l < 2 || /* Not enough data for CI header or */
+ p[1] < 2 || /* CI length too small or */
+ p[1] > l) { /* CI length too big? */
+ LCPDEBUG(("lcp_reqci: bad CI length!"));
+ orc = CONFREJ; /* Reject bad CI */
+ cilen = l; /* Reject till end of packet */
+ l = 0; /* Don't loop again */
+ citype = 0;
+ goto endswitch;
+ }
+ GETCHAR(citype, p); /* Parse CI type */
+ GETCHAR(cilen, p); /* Parse CI length */
+ l -= cilen; /* Adjust remaining length */
+ next += cilen; /* Step to next CI */
+
+ switch (citype) { /* Check CI type */
+ case CI_MRU:
+ if (!ao->neg_mru || /* Allow option? */
+ cilen != CILEN_SHORT) { /* Check CI length */
+ orc = CONFREJ; /* Reject CI */
+ break;
+ }
+ GETSHORT(cishort, p); /* Parse MRU */
+
+ /*
+ * He must be able to receive at least our minimum.
+ * No need to check a maximum. If he sends a large number,
+ * we'll just ignore it.
+ */
+ if (cishort < MINMRU) {
+ orc = CONFNAK; /* Nak CI */
+ PUTCHAR(CI_MRU, nakp);
+ PUTCHAR(CILEN_SHORT, nakp);
+ PUTSHORT(MINMRU, nakp); /* Give him a hint */
+ break;
+ }
+ ho->neg_mru = 1; /* Remember he sent MRU */
+ ho->mru = cishort; /* And remember value */
+ break;
+
+ case CI_ASYNCMAP:
+ if (!ao->neg_asyncmap ||
+ cilen != CILEN_LONG) {
+ orc = CONFREJ;
+ break;
+ }
+ GETLONG(cilong, p);
+
+ /*
+ * Asyncmap must have set at least the bits
+ * which are set in lcp_allowoptions[unit].asyncmap.
+ */
+ if ((ao->asyncmap & ~cilong) != 0) {
+ orc = CONFNAK;
+ PUTCHAR(CI_ASYNCMAP, nakp);
+ PUTCHAR(CILEN_LONG, nakp);
+ PUTLONG(ao->asyncmap | cilong, nakp);
+ break;
+ }
+ ho->neg_asyncmap = 1;
+ ho->asyncmap = cilong;
+ break;
+
+ case CI_AUTHTYPE:
+ if (cilen < CILEN_SHORT ||
+ !(ao->neg_upap || ao->neg_chap)) {
+ /*
+ * Reject the option if we're not willing to authenticate.
+ */
+ orc = CONFREJ;
+ break;
+ }
+ GETSHORT(cishort, p);
+
+ /*
+ * Authtype must be PAP or CHAP.
+ *
+ * Note: if both ao->neg_upap and ao->neg_chap are set,
+ * and the peer sends a Configure-Request with two
+ * authenticate-protocol requests, one for CHAP and one
+ * for UPAP, then we will reject the second request.
+ * Whether we end up doing CHAP or UPAP depends then on
+ * the ordering of the CIs in the peer's Configure-Request.
+ */
+
+ if (cishort == PPP_PAP) {
+ if (ho->neg_chap || /* we've already accepted CHAP */
+ cilen != CILEN_SHORT) {
+ LCPDEBUG(("lcp_reqci: rcvd AUTHTYPE PAP, rejecting..."));
+ orc = CONFREJ;
+ break;
+ }
+ if (!ao->neg_upap) { /* we don't want to do PAP */
+ orc = CONFNAK; /* NAK it and suggest CHAP */
+ PUTCHAR(CI_AUTHTYPE, nakp);
+ PUTCHAR(CILEN_CHAP, nakp);
+ PUTSHORT(PPP_CHAP, nakp);
+ PUTCHAR(ao->chap_mdtype, nakp);
+ /* XXX if we can do CHAP_MICROSOFT as well, we should
+ probably put in another option saying so */
+ break;
+ }
+ ho->neg_upap = 1;
+ break;
+ }
+ if (cishort == PPP_CHAP) {
+ if (ho->neg_upap || /* we've already accepted PAP */
+ cilen != CILEN_CHAP) {
+ LCPDEBUG(("lcp_reqci: rcvd AUTHTYPE CHAP, rejecting..."));
+ orc = CONFREJ;
+ break;
+ }
+ if (!ao->neg_chap) { /* we don't want to do CHAP */
+ orc = CONFNAK; /* NAK it and suggest PAP */
+ PUTCHAR(CI_AUTHTYPE, nakp);
+ PUTCHAR(CILEN_SHORT, nakp);
+ PUTSHORT(PPP_PAP, nakp);
+ break;
+ }
+ GETCHAR(cichar, p); /* get digest type*/
+ if (cichar != CHAP_DIGEST_MD5
+#ifdef CHAPMS
+ && cichar != CHAP_MICROSOFT
+#endif
+ ) {
+ orc = CONFNAK;
+ PUTCHAR(CI_AUTHTYPE, nakp);
+ PUTCHAR(CILEN_CHAP, nakp);
+ PUTSHORT(PPP_CHAP, nakp);
+ PUTCHAR(ao->chap_mdtype, nakp);
+ break;
+ }
+ ho->chap_mdtype = cichar; /* save md type */
+ ho->neg_chap = 1;
+ break;
+ }
+
+ /*
+ * We don't recognize the protocol they're asking for.
+ * Nak it with something we're willing to do.
+ * (At this point we know ao->neg_upap || ao->neg_chap.)
+ */
+ orc = CONFNAK;
+ PUTCHAR(CI_AUTHTYPE, nakp);
+ if (ao->neg_chap) {
+ PUTCHAR(CILEN_CHAP, nakp);
+ PUTSHORT(PPP_CHAP, nakp);
+ PUTCHAR(ao->chap_mdtype, nakp);
+ } else {
+ PUTCHAR(CILEN_SHORT, nakp);
+ PUTSHORT(PPP_PAP, nakp);
+ }
+ break;
+
+ case CI_QUALITY:
+ if (!ao->neg_lqr ||
+ cilen != CILEN_LQR) {
+ orc = CONFREJ;
+ break;
+ }
+
+ GETSHORT(cishort, p);
+ GETLONG(cilong, p);
+
+ /*
+ * Check the protocol and the reporting period.
+ * XXX When should we Nak this, and what with?
+ */
+ if (cishort != PPP_LQR) {
+ orc = CONFNAK;
+ PUTCHAR(CI_QUALITY, nakp);
+ PUTCHAR(CILEN_LQR, nakp);
+ PUTSHORT(PPP_LQR, nakp);
+ PUTLONG(ao->lqr_period, nakp);
+ break;
+ }
+ break;
+
+ case CI_MAGICNUMBER:
+ if (!(ao->neg_magicnumber || go->neg_magicnumber) ||
+ cilen != CILEN_LONG) {
+ orc = CONFREJ;
+ break;
+ }
+ GETLONG(cilong, p);
+
+ /*
+ * He must have a different magic number.
+ */
+ if (go->neg_magicnumber &&
+ cilong == go->magicnumber) {
+ cilong = magic(); /* Don't put magic() inside macro! */
+ orc = CONFNAK;
+ PUTCHAR(CI_MAGICNUMBER, nakp);
+ PUTCHAR(CILEN_LONG, nakp);
+ PUTLONG(cilong, nakp);
+ break;
+ }
+ ho->neg_magicnumber = 1;
+ ho->magicnumber = cilong;
+ break;
+
+
+ case CI_PCOMPRESSION:
+ if (!ao->neg_pcompression ||
+ cilen != CILEN_VOID) {
+ orc = CONFREJ;
+ break;
+ }
+ ho->neg_pcompression = 1;
+ break;
+
+ case CI_ACCOMPRESSION:
+ if (!ao->neg_accompression ||
+ cilen != CILEN_VOID) {
+ orc = CONFREJ;
+ break;
+ }
+ ho->neg_accompression = 1;
+ break;
+
+ case CI_MRRU:
+ if (!ao->neg_mrru || !multilink ||
+ cilen != CILEN_SHORT) {
+ orc = CONFREJ;
+ break;
+ }
+
+ GETSHORT(cishort, p);
+ /* possibly should insist on a minimum/maximum MRRU here */
+ ho->neg_mrru = 1;
+ ho->mrru = cishort;
+ break;
+
+ case CI_SSNHF:
+ if (!ao->neg_ssnhf || !multilink ||
+ cilen != CILEN_VOID) {
+ orc = CONFREJ;
+ break;
+ }
+ ho->neg_ssnhf = 1;
+ break;
+
+ case CI_EPDISC:
+ if (!ao->neg_endpoint ||
+ cilen < CILEN_CHAR ||
+ cilen > CILEN_CHAR + MAX_ENDP_LEN) {
+ orc = CONFREJ;
+ break;
+ }
+ GETCHAR(cichar, p);
+ cilen -= CILEN_CHAR;
+ ho->neg_endpoint = 1;
+ ho->endpoint.class = cichar;
+ ho->endpoint.length = cilen;
+ BCOPY(p, ho->endpoint.value, cilen);
+ INCPTR(cilen, p);
+ break;
+
+ default:
+ LCPDEBUG(("lcp_reqci: rcvd unknown option %d", citype));
+ orc = CONFREJ;
+ break;
+ }
+
+endswitch:
+ if (orc == CONFACK && /* Good CI */
+ rc != CONFACK) /* but prior CI wasnt? */
+ continue; /* Don't send this one */
+
+ if (orc == CONFNAK) { /* Nak this CI? */
+ if (reject_if_disagree /* Getting fed up with sending NAKs? */
+ && citype != CI_MAGICNUMBER) {
+ orc = CONFREJ; /* Get tough if so */
+ } else {
+ if (rc == CONFREJ) /* Rejecting prior CI? */
+ continue; /* Don't send this one */
+ rc = CONFNAK;
+ }
+ }
+ if (orc == CONFREJ) { /* Reject this CI */
+ rc = CONFREJ;
+ if (cip != rejp) /* Need to move rejected CI? */
+ BCOPY(cip, rejp, cilen); /* Move it */
+ INCPTR(cilen, rejp); /* Update output pointer */
+ }
+ }
+
+ /*
+ * If we wanted to send additional NAKs (for unsent CIs), the
+ * code would go here. The extra NAKs would go at *nakp.
+ * At present there are no cases where we want to ask the
+ * peer to negotiate an option.
+ */
+
+ switch (rc) {
+ case CONFACK:
+ *lenp = next - inp;
+ break;
+ case CONFNAK:
+ /*
+ * Copy the Nak'd options from the nak_buffer to the caller's buffer.
+ */
+ *lenp = nakp - nak_buffer;
+ BCOPY(nak_buffer, inp, *lenp);
+ break;
+ case CONFREJ:
+ *lenp = rejp - inp;
+ break;
+ }
+
+ LCPDEBUG(("lcp_reqci: returning CONF%s.", CODENAME(rc)));
+ return (rc); /* Return final code */
+}
+
+
+/*
+ * lcp_up - LCP has come UP.
+ */
+static void
+lcp_up(f)
+ fsm *f;
+{
+ lcp_options *wo = &lcp_wantoptions[f->unit];
+ lcp_options *ho = &lcp_hisoptions[f->unit];
+ lcp_options *go = &lcp_gotoptions[f->unit];
+ lcp_options *ao = &lcp_allowoptions[f->unit];
+ int mtu;
+
+ if (!go->neg_magicnumber)
+ go->magicnumber = 0;
+ if (!ho->neg_magicnumber)
+ ho->magicnumber = 0;
+
+ /*
+ * Set our MTU to the smaller of the MTU we wanted and
+ * the MRU our peer wanted. If we negotiated an MRU,
+ * set our MRU to the larger of value we wanted and
+ * the value we got in the negotiation.
+ * Note on the MTU: the link MTU can be the MRU the peer wanted,
+ * the interface MTU is set to the lower of that and the
+ * MTU we want to use.
+ */
+ mtu = ho->neg_mru? ho->mru: PPP_MRU;
+#ifdef HAVE_MULTILINK
+ if (!(multilink && go->neg_mrru && ho->neg_mrru))
+#endif /* HAVE_MULTILINK */
+ netif_set_mtu(f->unit, MIN(mtu, ao->mru));
+ ppp_send_config(f->unit, mtu,
+ (ho->neg_asyncmap? ho->asyncmap: 0xffffffff),
+ ho->neg_pcompression, ho->neg_accompression);
+ ppp_recv_config(f->unit, (go->neg_mru? MAX(wo->mru, go->mru): PPP_MRU),
+ (lax_recv? 0: go->neg_asyncmap? go->asyncmap: 0xffffffff),
+ go->neg_pcompression, go->neg_accompression);
+
+ if (ho->neg_mru)
+ peer_mru[f->unit] = ho->mru;
+
+ lcp_echo_lowerup(f->unit); /* Enable echo messages */
+
+ link_established(f->unit);
+}
+
+
+/*
+ * lcp_down - LCP has gone DOWN.
+ *
+ * Alert other protocols.
+ */
+static void
+lcp_down(f)
+ fsm *f;
+{
+ lcp_options *go = &lcp_gotoptions[f->unit];
+
+ lcp_echo_lowerdown(f->unit);
+
+ link_down(f->unit);
+
+ ppp_send_config(f->unit, PPP_MRU, 0xffffffff, 0, 0);
+ ppp_recv_config(f->unit, PPP_MRU,
+ (go->neg_asyncmap? go->asyncmap: 0xffffffff),
+ go->neg_pcompression, go->neg_accompression);
+ peer_mru[f->unit] = PPP_MRU;
+}
+
+
+/*
+ * lcp_starting - LCP needs the lower layer up.
+ */
+static void
+lcp_starting(f)
+ fsm *f;
+{
+ link_required(f->unit);
+}
+
+
+/*
+ * lcp_finished - LCP has finished with the lower layer.
+ */
+static void
+lcp_finished(f)
+ fsm *f;
+{
+ link_terminated(f->unit);
+}
+
+
+/*
+ * lcp_printpkt - print the contents of an LCP packet.
+ */
+static char *lcp_codenames[] = {
+ "ConfReq", "ConfAck", "ConfNak", "ConfRej",
+ "TermReq", "TermAck", "CodeRej", "ProtRej",
+ "EchoReq", "EchoRep", "DiscReq"
+};
+
+static int
+lcp_printpkt(p, plen, printer, arg)
+ u_char *p;
+ int plen;
+ void (*printer) __P((void *, char *, ...));
+ void *arg;
+{
+ int code, id, len, olen, i;
+ u_char *pstart, *optend;
+ u_short cishort;
+ u_int32_t cilong;
+
+ if (plen < HEADERLEN)
+ return 0;
+ pstart = p;
+ GETCHAR(code, p);
+ GETCHAR(id, p);
+ GETSHORT(len, p);
+ if (len < HEADERLEN || len > plen)
+ return 0;
+
+ if (code >= 1 && code <= sizeof(lcp_codenames) / sizeof(char *))
+ printer(arg, " %s", lcp_codenames[code-1]);
+ else
+ printer(arg, " code=0x%x", code);
+ printer(arg, " id=0x%x", id);
+ len -= HEADERLEN;
+ switch (code) {
+ case CONFREQ:
+ case CONFACK:
+ case CONFNAK:
+ case CONFREJ:
+ /* print option list */
+ while (len >= 2) {
+ GETCHAR(code, p);
+ GETCHAR(olen, p);
+ p -= 2;
+ if (olen < 2 || olen > len) {
+ break;
+ }
+ printer(arg, " <");
+ len -= olen;
+ optend = p + olen;
+ switch (code) {
+ case CI_MRU:
+ if (olen == CILEN_SHORT) {
+ p += 2;
+ GETSHORT(cishort, p);
+ printer(arg, "mru %d", cishort);
+ }
+ break;
+ case CI_ASYNCMAP:
+ if (olen == CILEN_LONG) {
+ p += 2;
+ GETLONG(cilong, p);
+ printer(arg, "asyncmap 0x%x", cilong);
+ }
+ break;
+ case CI_AUTHTYPE:
+ if (olen >= CILEN_SHORT) {
+ p += 2;
+ printer(arg, "auth ");
+ GETSHORT(cishort, p);
+ switch (cishort) {
+ case PPP_PAP:
+ printer(arg, "pap");
+ break;
+ case PPP_CHAP:
+ printer(arg, "chap");
+ if (p < optend) {
+ switch (*p) {
+ case CHAP_DIGEST_MD5:
+ printer(arg, " MD5");
+ ++p;
+ break;
+#ifdef CHAPMS
+ case CHAP_MICROSOFT:
+ printer(arg, " m$oft");
+ ++p;
+ break;
+#endif
+ }
+ }
+ break;
+ default:
+ printer(arg, "0x%x", cishort);
+ }
+ }
+ break;
+ case CI_QUALITY:
+ if (olen >= CILEN_SHORT) {
+ p += 2;
+ printer(arg, "quality ");
+ GETSHORT(cishort, p);
+ switch (cishort) {
+ case PPP_LQR:
+ printer(arg, "lqr");
+ break;
+ default:
+ printer(arg, "0x%x", cishort);
+ }
+ }
+ break;
+ case CI_CALLBACK:
+ if (olen >= CILEN_CHAR) {
+ p += 2;
+ printer(arg, "callback ");
+ GETCHAR(cishort, p);
+ switch (cishort) {
+ case CBCP_OPT:
+ printer(arg, "CBCP");
+ break;
+ default:
+ printer(arg, "0x%x", cishort);
+ }
+ }
+ break;
+ case CI_MAGICNUMBER:
+ if (olen == CILEN_LONG) {
+ p += 2;
+ GETLONG(cilong, p);
+ printer(arg, "magic 0x%x", cilong);
+ }
+ break;
+ case CI_PCOMPRESSION:
+ if (olen == CILEN_VOID) {
+ p += 2;
+ printer(arg, "pcomp");
+ }
+ break;
+ case CI_ACCOMPRESSION:
+ if (olen == CILEN_VOID) {
+ p += 2;
+ printer(arg, "accomp");
+ }
+ break;
+ case CI_MRRU:
+ if (olen == CILEN_SHORT) {
+ p += 2;
+ GETSHORT(cishort, p);
+ printer(arg, "mrru %d", cishort);
+ }
+ break;
+ case CI_SSNHF:
+ if (olen == CILEN_VOID) {
+ p += 2;
+ printer(arg, "ssnhf");
+ }
+ break;
+ case CI_EPDISC:
+#ifdef HAVE_MULTILINK
+ if (olen >= CILEN_CHAR) {
+ struct epdisc epd;
+ p += 2;
+ GETCHAR(epd.class, p);
+ epd.length = olen - CILEN_CHAR;
+ if (epd.length > MAX_ENDP_LEN)
+ epd.length = MAX_ENDP_LEN;
+ if (epd.length > 0) {
+ BCOPY(p, epd.value, epd.length);
+ p += epd.length;
+ }
+ printer(arg, "endpoint [%s]", epdisc_to_str(&epd));
+ }
+#else
+ printer(arg, "endpoint");
+#endif
+ break;
+ }
+ while (p < optend) {
+ GETCHAR(code, p);
+ printer(arg, " %.2x", code);
+ }
+ printer(arg, ">");
+ }
+ break;
+
+ case TERMACK:
+ case TERMREQ:
+ if (len > 0 && *p >= ' ' && *p < 0x7f) {
+ printer(arg, " ");
+ print_string((char *)p, len, printer, arg);
+ p += len;
+ len = 0;
+ }
+ break;
+
+ case ECHOREQ:
+ case ECHOREP:
+ case DISCREQ:
+ if (len >= 4) {
+ GETLONG(cilong, p);
+ printer(arg, " magic=0x%x", cilong);
+ p += 4;
+ len -= 4;
+ }
+ break;
+ }
+
+ /* print the rest of the bytes in the packet */
+ for (i = 0; i < len && i < 32; ++i) {
+ GETCHAR(code, p);
+ printer(arg, " %.2x", code);
+ }
+ if (i < len) {
+ printer(arg, " ...");
+ p += len - i;
+ }
+
+ return p - pstart;
+}
+
+/*
+ * Time to shut down the link because there is nothing out there.
+ */
+
+static
+void LcpLinkFailure (f)
+ fsm *f;
+{
+ if (f->state == OPENED) {
+ info("No response to %d echo-requests", lcp_echos_pending);
+ notice("Serial link appears to be disconnected.");
+ lcp_close(f->unit, "Peer not responding");
+ status = EXIT_PEER_DEAD;
+ }
+}
+
+/*
+ * Timer expired for the LCP echo requests from this process.
+ */
+
+static void
+LcpEchoCheck (f)
+ fsm *f;
+{
+ LcpSendEchoRequest (f);
+ if (f->state != OPENED)
+ return;
+
+ /*
+ * Start the timer for the next interval.
+ */
+ if (lcp_echo_timer_running)
+ warn("assertion lcp_echo_timer_running==0 failed");
+ TIMEOUT (LcpEchoTimeout, f, lcp_echo_interval);
+ lcp_echo_timer_running = 1;
+}
+
+/*
+ * LcpEchoTimeout - Timer expired on the LCP echo
+ */
+
+static void
+LcpEchoTimeout (arg)
+ void *arg;
+{
+ if (lcp_echo_timer_running != 0) {
+ lcp_echo_timer_running = 0;
+ LcpEchoCheck ((fsm *) arg);
+ }
+}
+
+/*
+ * LcpEchoReply - LCP has received a reply to the echo
+ */
+
+static void
+lcp_received_echo_reply (f, id, inp, len)
+ fsm *f;
+ int id;
+ u_char *inp;
+ int len;
+{
+ u_int32_t magic;
+
+ /* Check the magic number - don't count replies from ourselves. */
+ if (len < 4) {
+ dbglog("lcp: received short Echo-Reply, length %d", len);
+ return;
+ }
+ GETLONG(magic, inp);
+ if (lcp_gotoptions[f->unit].neg_magicnumber
+ && magic == lcp_gotoptions[f->unit].magicnumber) {
+ warn("appear to have received our own echo-reply!");
+ return;
+ }
+
+ /* Reset the number of outstanding echo frames */
+ lcp_echos_pending = 0;
+}
+
+/*
+ * LcpSendEchoRequest - Send an echo request frame to the peer
+ */
+
+static void
+LcpSendEchoRequest (f)
+ fsm *f;
+{
+ u_int32_t lcp_magic;
+ u_char pkt[4], *pktp;
+
+ /*
+ * Detect the failure of the peer at this point.
+ */
+ if (lcp_echo_fails != 0) {
+ if (lcp_echos_pending >= lcp_echo_fails) {
+ LcpLinkFailure(f);
+ lcp_echos_pending = 0;
+ }
+ }
+
+ /*
+ * Make and send the echo request frame.
+ */
+ if (f->state == OPENED) {
+ lcp_magic = lcp_gotoptions[f->unit].magicnumber;
+ pktp = pkt;
+ PUTLONG(lcp_magic, pktp);
+ fsm_sdata(f, ECHOREQ, lcp_echo_number++ & 0xFF, pkt, pktp - pkt);
+ ++lcp_echos_pending;
+ }
+}
+
+/*
+ * lcp_echo_lowerup - Start the timer for the LCP frame
+ */
+
+static void
+lcp_echo_lowerup (unit)
+ int unit;
+{
+ fsm *f = &lcp_fsm[unit];
+
+ /* Clear the parameters for generating echo frames */
+ lcp_echos_pending = 0;
+ lcp_echo_number = 0;
+ lcp_echo_timer_running = 0;
+
+ /* If a timeout interval is specified then start the timer */
+ if (lcp_echo_interval != 0)
+ LcpEchoCheck (f);
+}
+
+/*
+ * lcp_echo_lowerdown - Stop the timer for the LCP frame
+ */
+
+static void
+lcp_echo_lowerdown (unit)
+ int unit;
+{
+ fsm *f = &lcp_fsm[unit];
+
+ if (lcp_echo_timer_running != 0) {
+ UNTIMEOUT (LcpEchoTimeout, f);
+ lcp_echo_timer_running = 0;
+ }
+}
diff --git a/mdk-stage1/ppp/pppd/lcp.h b/mdk-stage1/ppp/pppd/lcp.h
new file mode 100644
index 000000000..393b13c68
--- /dev/null
+++ b/mdk-stage1/ppp/pppd/lcp.h
@@ -0,0 +1,95 @@
+/*
+ * lcp.h - Link Control Protocol definitions.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id: lcp.h 195720 2001-06-11 11:44:34Z gc $
+ */
+
+/*
+ * Options.
+ */
+#define CI_MRU 1 /* Maximum Receive Unit */
+#define CI_ASYNCMAP 2 /* Async Control Character Map */
+#define CI_AUTHTYPE 3 /* Authentication Type */
+#define CI_QUALITY 4 /* Quality Protocol */
+#define CI_MAGICNUMBER 5 /* Magic Number */
+#define CI_PCOMPRESSION 7 /* Protocol Field Compression */
+#define CI_ACCOMPRESSION 8 /* Address/Control Field Compression */
+#define CI_CALLBACK 13 /* callback */
+#define CI_MRRU 17 /* max reconstructed receive unit; multilink */
+#define CI_SSNHF 18 /* short sequence numbers for multilink */
+#define CI_EPDISC 19 /* endpoint discriminator */
+
+/*
+ * LCP-specific packet types.
+ */
+#define PROTREJ 8 /* Protocol Reject */
+#define ECHOREQ 9 /* Echo Request */
+#define ECHOREP 10 /* Echo Reply */
+#define DISCREQ 11 /* Discard Request */
+#define CBCP_OPT 6 /* Use callback control protocol */
+
+/*
+ * The state of options is described by an lcp_options structure.
+ */
+typedef struct lcp_options {
+ bool passive; /* Don't die if we don't get a response */
+ bool silent; /* Wait for the other end to start first */
+ bool restart; /* Restart vs. exit after close */
+ bool neg_mru; /* Negotiate the MRU? */
+ bool neg_asyncmap; /* Negotiate the async map? */
+ bool neg_upap; /* Ask for UPAP authentication? */
+ bool neg_chap; /* Ask for CHAP authentication? */
+ bool neg_magicnumber; /* Ask for magic number? */
+ bool neg_pcompression; /* HDLC Protocol Field Compression? */
+ bool neg_accompression; /* HDLC Address/Control Field Compression? */
+ bool neg_lqr; /* Negotiate use of Link Quality Reports */
+ bool neg_cbcp; /* Negotiate use of CBCP */
+ bool neg_mrru; /* negotiate multilink MRRU */
+ bool neg_ssnhf; /* negotiate short sequence numbers */
+ bool neg_endpoint; /* negotiate endpoint discriminator */
+ int mru; /* Value of MRU */
+ int mrru; /* Value of MRRU, and multilink enable */
+ u_char chap_mdtype; /* which MD type (hashing algorithm) */
+ u_int32_t asyncmap; /* Value of async map */
+ u_int32_t magicnumber;
+ int numloops; /* Number of loops during magic number neg. */
+ u_int32_t lqr_period; /* Reporting period for LQR 1/100ths second */
+ struct epdisc endpoint; /* endpoint discriminator */
+} lcp_options;
+
+extern fsm lcp_fsm[];
+extern lcp_options lcp_wantoptions[];
+extern lcp_options lcp_gotoptions[];
+extern lcp_options lcp_allowoptions[];
+extern lcp_options lcp_hisoptions[];
+
+#define DEFMRU 1500 /* Try for this */
+#define MINMRU 128 /* No MRUs below this */
+#define MAXMRU 16384 /* Normally limit MRU to this */
+
+void lcp_open __P((int));
+void lcp_close __P((int, char *));
+void lcp_lowerup __P((int));
+void lcp_lowerdown __P((int));
+void lcp_sprotrej __P((int, u_char *, int)); /* send protocol reject */
+
+extern struct protent lcp_protent;
+
+/* Default number of times we receive our magic number from the peer
+ before deciding the link is looped-back. */
+#define DEFLOOPBACKFAIL 10
diff --git a/mdk-stage1/ppp/pppd/magic.c b/mdk-stage1/ppp/pppd/magic.c
new file mode 100644
index 000000000..845dfe21f
--- /dev/null
+++ b/mdk-stage1/ppp/pppd/magic.c
@@ -0,0 +1,88 @@
+/*
+ * magic.c - PPP Magic Number routines.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#define RCSID "$Id: magic.c 195734 2001-06-11 14:46:02Z gc $"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/time.h>
+
+#include "pppd.h"
+#include "magic.h"
+
+static const char rcsid[] = RCSID;
+
+extern long mrand48 __P((void));
+extern void srand48 __P((long));
+
+/*
+ * magic_init - Initialize the magic number generator.
+ *
+ * Attempts to compute a random number seed which will not repeat.
+ * The current method uses the current hostid, current process ID
+ * and current time, currently.
+ */
+void
+magic_init()
+{
+ long seed;
+ struct timeval t;
+
+ gettimeofday(&t, NULL);
+ seed = get_host_seed() ^ t.tv_sec ^ t.tv_usec ^ getpid();
+ srand48(seed);
+}
+
+/*
+ * magic - Returns the next magic number.
+ */
+u_int32_t
+magic()
+{
+ return (u_int32_t) mrand48();
+}
+
+#ifdef NO_DRAND48
+/*
+ * Substitute procedures for those systems which don't have
+ * drand48 et al.
+ */
+
+double
+drand48()
+{
+ return (double)random() / (double)0x7fffffffL; /* 2**31-1 */
+}
+
+long
+mrand48()
+{
+ return random();
+}
+
+void
+srand48(seedval)
+long seedval;
+{
+ srandom((int)seedval);
+}
+
+#endif
diff --git a/mdk-stage1/ppp/pppd/magic.h b/mdk-stage1/ppp/pppd/magic.h
new file mode 100644
index 000000000..3b709b563
--- /dev/null
+++ b/mdk-stage1/ppp/pppd/magic.h
@@ -0,0 +1,23 @@
+/*
+ * magic.h - PPP Magic Number definitions.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id: magic.h 195720 2001-06-11 11:44:34Z gc $
+ */
+
+void magic_init __P((void)); /* Initialize the magic number generator */
+u_int32_t magic __P((void)); /* Returns the next magic number */
diff --git a/mdk-stage1/ppp/pppd/main.c b/mdk-stage1/ppp/pppd/main.c
new file mode 100644
index 000000000..1e540ae90
--- /dev/null
+++ b/mdk-stage1/ppp/pppd/main.c
@@ -0,0 +1,1846 @@
+/*
+ * main.c - Point-to-Point Protocol main module
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#define RCSID "$Id: main.c 195734 2001-06-11 14:46:02Z gc $"
+
+#include <stdio.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <signal.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <syslog.h>
+#include <netdb.h>
+#include <utmp.h>
+#include <pwd.h>
+#include <setjmp.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include "pppd.h"
+#include "magic.h"
+#include "fsm.h"
+#include "lcp.h"
+#include "ipcp.h"
+#ifdef INET6
+#include "ipv6cp.h"
+#endif
+#include "upap.h"
+#include "chap.h"
+#include "ccp.h"
+#include "pathnames.h"
+#include "tdb.h"
+
+#ifdef CBCP_SUPPORT
+#include "cbcp.h"
+#endif
+
+#ifdef IPX_CHANGE
+#include "ipxcp.h"
+#endif /* IPX_CHANGE */
+#ifdef AT_CHANGE
+#include "atcp.h"
+#endif
+
+static const char rcsid[] = RCSID;
+
+/* interface vars */
+char ifname[32]; /* Interface name */
+int ifunit; /* Interface unit number */
+
+struct channel *the_channel;
+
+char *progname; /* Name of this program */
+char hostname[MAXNAMELEN]; /* Our hostname */
+static char pidfilename[MAXPATHLEN]; /* name of pid file */
+static char linkpidfile[MAXPATHLEN]; /* name of linkname pid file */
+char ppp_devnam[MAXPATHLEN]; /* name of PPP tty (maybe ttypx) */
+uid_t uid; /* Our real user-id */
+struct notifier *pidchange = NULL;
+struct notifier *phasechange = NULL;
+struct notifier *exitnotify = NULL;
+struct notifier *sigreceived = NULL;
+
+int hungup; /* terminal has been hung up */
+int privileged; /* we're running as real uid root */
+int need_holdoff; /* need holdoff period before restarting */
+int detached; /* have detached from terminal */
+volatile int status; /* exit status for pppd */
+int unsuccess; /* # unsuccessful connection attempts */
+int do_callback; /* != 0 if we should do callback next */
+int doing_callback; /* != 0 if we are doing callback */
+TDB_CONTEXT *pppdb; /* database for storing status etc. */
+char db_key[32];
+
+int (*holdoff_hook) __P((void)) = NULL;
+int (*new_phase_hook) __P((int)) = NULL;
+
+static int conn_running; /* we have a [dis]connector running */
+static int devfd; /* fd of underlying device */
+static int fd_ppp = -1; /* fd for talking PPP */
+static int fd_loop; /* fd for getting demand-dial packets */
+
+int phase; /* where the link is at */
+int kill_link;
+int open_ccp_flag;
+int listen_time;
+int got_sigusr2;
+int got_sigterm;
+int got_sighup;
+
+static int waiting;
+static sigjmp_buf sigjmp;
+
+char **script_env; /* Env. variable values for scripts */
+int s_env_nalloc; /* # words avail at script_env */
+
+u_char outpacket_buf[PPP_MRU+PPP_HDRLEN]; /* buffer for outgoing packet */
+u_char inpacket_buf[PPP_MRU+PPP_HDRLEN]; /* buffer for incoming packet */
+
+static int n_children; /* # child processes still running */
+static int got_sigchld; /* set if we have received a SIGCHLD */
+
+int privopen; /* don't lock, open device as root */
+
+char *no_ppp_msg = "Sorry - this system lacks PPP kernel support\n";
+
+GIDSET_TYPE groups[NGROUPS_MAX];/* groups the user is in */
+int ngroups; /* How many groups valid in groups */
+
+static struct timeval start_time; /* Time when link was started. */
+
+struct pppd_stats link_stats;
+int link_connect_time;
+int link_stats_valid;
+
+/*
+ * We maintain a list of child process pids and
+ * functions to call when they exit.
+ */
+struct subprocess {
+ pid_t pid;
+ char *prog;
+ void (*done) __P((void *));
+ void *arg;
+ struct subprocess *next;
+};
+
+static struct subprocess *children;
+
+/* Prototypes for procedures local to this file. */
+
+static void setup_signals __P((void));
+static void create_pidfile __P((void));
+static void create_linkpidfile __P((void));
+static void cleanup __P((void));
+static void get_input __P((void));
+static void calltimeout __P((void));
+static struct timeval *timeleft __P((struct timeval *));
+static void kill_my_pg __P((int));
+static void hup __P((int));
+static void term __P((int));
+static void chld __P((int));
+static void toggle_debug __P((int));
+static void open_ccp __P((int));
+static void bad_signal __P((int));
+static void holdoff_end __P((void *));
+static int reap_kids __P((int waitfor));
+static void update_db_entry __P((void));
+static void add_db_key __P((const char *));
+static void delete_db_key __P((const char *));
+static void cleanup_db __P((void));
+static void handle_events __P((void));
+
+extern char *ttyname __P((int));
+extern char *getlogin __P((void));
+int main __P((int, char *[]));
+
+#ifdef ultrix
+#undef O_NONBLOCK
+#define O_NONBLOCK O_NDELAY
+#endif
+
+#ifdef ULTRIX
+#define setlogmask(x)
+#endif
+
+/*
+ * PPP Data Link Layer "protocol" table.
+ * One entry per supported protocol.
+ * The last entry must be NULL.
+ */
+struct protent *protocols[] = {
+ &lcp_protent,
+ &pap_protent,
+ &chap_protent,
+#ifdef CBCP_SUPPORT
+ &cbcp_protent,
+#endif
+ &ipcp_protent,
+#ifdef INET6
+ &ipv6cp_protent,
+#endif
+ &ccp_protent,
+#ifdef IPX_CHANGE
+ &ipxcp_protent,
+#endif
+#ifdef AT_CHANGE
+ &atcp_protent,
+#endif
+ NULL
+};
+
+/*
+ * If PPP_DRV_NAME is not defined, use the default "ppp" as the device name.
+ */
+#if !defined(PPP_DRV_NAME)
+#define PPP_DRV_NAME "ppp"
+#endif /* !defined(PPP_DRV_NAME) */
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int i, t;
+ char *p;
+ struct passwd *pw;
+ struct protent *protp;
+ char numbuf[16];
+
+ new_phase(PHASE_INITIALIZE);
+
+ /*
+ * Ensure that fds 0, 1, 2 are open, to /dev/null if nowhere else.
+ * This way we can close 0, 1, 2 in detach() without clobbering
+ * a fd that we are using.
+ */
+ if ((i = open("/dev/null", O_RDWR)) >= 0) {
+ while (0 <= i && i <= 2)
+ i = dup(i);
+ if (i >= 0)
+ close(i);
+ }
+
+ script_env = NULL;
+
+ /* Initialize syslog facilities */
+ reopen_log();
+
+ if (gethostname(hostname, MAXNAMELEN) < 0 ) {
+ option_error("Couldn't get hostname: %m");
+ exit(1);
+ }
+ hostname[MAXNAMELEN-1] = 0;
+
+ /* make sure we don't create world or group writable files. */
+ umask(umask(0777) | 022);
+
+ uid = getuid();
+ privileged = uid == 0;
+ slprintf(numbuf, sizeof(numbuf), "%d", uid);
+ script_setenv("ORIG_UID", numbuf, 0);
+
+ ngroups = getgroups(NGROUPS_MAX, groups);
+
+ /*
+ * Initialize magic number generator now so that protocols may
+ * use magic numbers in initialization.
+ */
+ magic_init();
+
+ /*
+ * Initialize each protocol.
+ */
+ for (i = 0; (protp = protocols[i]) != NULL; ++i)
+ (*protp->init)(0);
+
+ /*
+ * Initialize the default channel.
+ */
+ tty_init();
+
+ progname = *argv;
+
+ /*
+ * Parse, in order, the system options file, the user's options file,
+ * and the command line arguments.
+ */
+ if (!options_from_file(_PATH_SYSOPTIONS, !privileged, 0, 1)
+ || !options_from_user()
+ || !parse_args(argc-1, argv+1))
+ exit(EXIT_OPTION_ERROR);
+ devnam_fixed = 1; /* can no longer change device name */
+
+ /*
+ * Work out the device name, if it hasn't already been specified,
+ * and parse the tty's options file.
+ */
+ if (the_channel->process_extra_options)
+ (*the_channel->process_extra_options)();
+
+ if (debug)
+ setlogmask(LOG_UPTO(LOG_DEBUG));
+
+ /*
+ * Check that we are running as root.
+ */
+ if (geteuid() != 0) {
+ option_error("must be root to run %s, since it is not setuid-root",
+ argv[0]);
+ exit(EXIT_NOT_ROOT);
+ }
+
+ if (!ppp_available()) {
+ option_error("%s", no_ppp_msg);
+ exit(EXIT_NO_KERNEL_SUPPORT);
+ }
+
+ /*
+ * Check that the options given are valid and consistent.
+ */
+ check_options();
+ if (!sys_check_options())
+ exit(EXIT_OPTION_ERROR);
+ auth_check_options();
+#ifdef HAVE_MULTILINK
+ mp_check_options();
+#endif
+ for (i = 0; (protp = protocols[i]) != NULL; ++i)
+ if (protp->check_options != NULL)
+ (*protp->check_options)();
+ if (the_channel->check_options)
+ (*the_channel->check_options)();
+
+
+ if (dump_options || dryrun) {
+ init_pr_log(NULL, LOG_INFO);
+ print_options(pr_log, NULL);
+ end_pr_log();
+ if (dryrun)
+ die(0);
+ }
+
+ /*
+ * Initialize system-dependent stuff.
+ */
+ sys_init();
+
+ pppdb = tdb_open(_PATH_PPPDB, 0, 0, O_RDWR|O_CREAT, 0644);
+ if (pppdb != NULL) {
+ slprintf(db_key, sizeof(db_key), "pppd%d", getpid());
+ update_db_entry();
+ } else {
+ warn("Warning: couldn't open ppp database %s", _PATH_PPPDB);
+ if (multilink) {
+ warn("Warning: disabling multilink");
+ multilink = 0;
+ }
+ }
+
+ /*
+ * Detach ourselves from the terminal, if required,
+ * and identify who is running us.
+ */
+ if (!nodetach && !updetach)
+ detach();
+ p = getlogin();
+ if (p == NULL) {
+ pw = getpwuid(uid);
+ if (pw != NULL && pw->pw_name != NULL)
+ p = pw->pw_name;
+ else
+ p = "(unknown)";
+ }
+ syslog(LOG_NOTICE, "pppd %s started by %s, uid %d", VERSION, p, uid);
+ script_setenv("PPPLOGNAME", p, 0);
+
+ if (devnam[0])
+ script_setenv("DEVICE", devnam, 1);
+ slprintf(numbuf, sizeof(numbuf), "%d", getpid());
+ script_setenv("PPPD_PID", numbuf, 1);
+
+ setup_signals();
+
+ waiting = 0;
+
+ create_linkpidfile();
+
+ /*
+ * If we're doing dial-on-demand, set up the interface now.
+ */
+ if (demand) {
+ /*
+ * Open the loopback channel and set it up to be the ppp interface.
+ */
+ tdb_writelock(pppdb);
+ fd_loop = open_ppp_loopback();
+ set_ifunit(1);
+ tdb_writeunlock(pppdb);
+
+ /*
+ * Configure the interface and mark it up, etc.
+ */
+ demand_conf();
+ }
+
+ do_callback = 0;
+ for (;;) {
+
+ listen_time = 0;
+ need_holdoff = 1;
+ devfd = -1;
+ status = EXIT_OK;
+ ++unsuccess;
+ doing_callback = do_callback;
+ do_callback = 0;
+
+ if (demand && !doing_callback) {
+ /*
+ * Don't do anything until we see some activity.
+ */
+ new_phase(PHASE_DORMANT);
+ demand_unblock();
+ add_fd(fd_loop);
+ for (;;) {
+ handle_events();
+ if (kill_link && !persist)
+ break;
+ if (get_loop_output())
+ break;
+ }
+ remove_fd(fd_loop);
+ if (kill_link && !persist)
+ break;
+
+ /*
+ * Now we want to bring up the link.
+ */
+ demand_block();
+ info("Starting link");
+ }
+
+ new_phase(PHASE_SERIALCONN);
+
+ devfd = the_channel->connect();
+ if (devfd < 0)
+ goto fail;
+
+ /* set up the serial device as a ppp interface */
+ tdb_writelock(pppdb);
+ fd_ppp = the_channel->establish_ppp(devfd);
+ if (fd_ppp < 0) {
+ tdb_writeunlock(pppdb);
+ status = EXIT_FATAL_ERROR;
+ goto disconnect;
+ }
+
+ if (!demand && ifunit >= 0)
+ set_ifunit(1);
+ tdb_writeunlock(pppdb);
+
+ /*
+ * Start opening the connection and wait for
+ * incoming events (reply, timeout, etc.).
+ */
+ notice("Connect: %s <--> %s", ifname, ppp_devnam);
+ gettimeofday(&start_time, NULL);
+ link_stats_valid = 0;
+ script_unsetenv("CONNECT_TIME");
+ script_unsetenv("BYTES_SENT");
+ script_unsetenv("BYTES_RCVD");
+ lcp_lowerup(0);
+
+ add_fd(fd_ppp);
+ lcp_open(0); /* Start protocol */
+ status = EXIT_NEGOTIATION_FAILED;
+ new_phase(PHASE_ESTABLISH);
+ while (phase != PHASE_DEAD) {
+ handle_events();
+ get_input();
+ if (kill_link)
+ lcp_close(0, "User request");
+ if (open_ccp_flag) {
+ if (phase == PHASE_NETWORK || phase == PHASE_RUNNING) {
+ ccp_fsm[0].flags = OPT_RESTART; /* clears OPT_SILENT */
+ (*ccp_protent.open)(0);
+ }
+ }
+ }
+
+ /*
+ * Print connect time and statistics.
+ */
+ if (link_stats_valid) {
+ int t = (link_connect_time + 5) / 6; /* 1/10ths of minutes */
+ info("Connect time %d.%d minutes.", t/10, t%10);
+ info("Sent %u bytes, received %u bytes.",
+ link_stats.bytes_out, link_stats.bytes_in);
+ }
+
+ /*
+ * Delete pid file before disestablishing ppp. Otherwise it
+ * can happen that another pppd gets the same unit and then
+ * we delete its pid file.
+ */
+ if (!demand) {
+ if (pidfilename[0] != 0
+ && unlink(pidfilename) < 0 && errno != ENOENT)
+ warn("unable to delete pid file %s: %m", pidfilename);
+ pidfilename[0] = 0;
+ }
+
+ /*
+ * If we may want to bring the link up again, transfer
+ * the ppp unit back to the loopback. Set the
+ * real serial device back to its normal mode of operation.
+ */
+ remove_fd(fd_ppp);
+ clean_check();
+ the_channel->disestablish_ppp(devfd);
+ fd_ppp = -1;
+ if (!hungup)
+ lcp_lowerdown(0);
+ if (!demand)
+ script_unsetenv("IFNAME");
+
+ /*
+ * Run disconnector script, if requested.
+ * XXX we may not be able to do this if the line has hung up!
+ */
+ disconnect:
+ new_phase(PHASE_DISCONNECT);
+ the_channel->disconnect();
+
+ fail:
+ if (the_channel->cleanup)
+ (*the_channel->cleanup)();
+
+ if (!demand) {
+ if (pidfilename[0] != 0
+ && unlink(pidfilename) < 0 && errno != ENOENT)
+ warn("unable to delete pid file %s: %m", pidfilename);
+ pidfilename[0] = 0;
+ }
+
+ if (!persist || (maxfail > 0 && unsuccess >= maxfail))
+ break;
+
+ if (demand)
+ demand_discard();
+ t = need_holdoff? holdoff: 0;
+ if (holdoff_hook)
+ t = (*holdoff_hook)();
+ if (t > 0) {
+ new_phase(PHASE_HOLDOFF);
+ TIMEOUT(holdoff_end, NULL, t);
+ do {
+ handle_events();
+ if (kill_link)
+ new_phase(PHASE_DORMANT); /* allow signal to end holdoff */
+ } while (phase == PHASE_HOLDOFF);
+ if (!persist)
+ break;
+ }
+ }
+
+ /* Wait for scripts to finish */
+ /* XXX should have a timeout here */
+ while (n_children > 0) {
+ if (debug) {
+ struct subprocess *chp;
+ dbglog("Waiting for %d child processes...", n_children);
+ for (chp = children; chp != NULL; chp = chp->next)
+ dbglog(" script %s, pid %d", chp->prog, chp->pid);
+ }
+ if (reap_kids(1) < 0)
+ break;
+ }
+
+ die(status);
+ return 0;
+}
+
+/*
+ * handle_events - wait for something to happen and respond to it.
+ */
+static void
+handle_events()
+{
+ struct timeval timo;
+ sigset_t mask;
+
+ kill_link = open_ccp_flag = 0;
+ if (sigsetjmp(sigjmp, 1) == 0) {
+ sigprocmask(SIG_BLOCK, &mask, NULL);
+ if (got_sighup || got_sigterm || got_sigusr2 || got_sigchld) {
+ sigprocmask(SIG_UNBLOCK, &mask, NULL);
+ } else {
+ waiting = 1;
+ sigprocmask(SIG_UNBLOCK, &mask, NULL);
+ wait_input(timeleft(&timo));
+ }
+ }
+ waiting = 0;
+ calltimeout();
+ if (got_sighup) {
+ kill_link = 1;
+ got_sighup = 0;
+ if (status != EXIT_HANGUP)
+ status = EXIT_USER_REQUEST;
+ }
+ if (got_sigterm) {
+ kill_link = 1;
+ persist = 0;
+ status = EXIT_USER_REQUEST;
+ got_sigterm = 0;
+ }
+ if (got_sigchld) {
+ reap_kids(0); /* Don't leave dead kids lying around */
+ got_sigchld = 0;
+ }
+ if (got_sigusr2) {
+ open_ccp_flag = 1;
+ got_sigusr2 = 0;
+ }
+}
+
+/*
+ * setup_signals - initialize signal handling.
+ */
+static void
+setup_signals()
+{
+ struct sigaction sa;
+ sigset_t mask;
+
+ /*
+ * Compute mask of all interesting signals and install signal handlers
+ * for each. Only one signal handler may be active at a time. Therefore,
+ * all other signals should be masked when any handler is executing.
+ */
+ sigemptyset(&mask);
+ sigaddset(&mask, SIGHUP);
+ sigaddset(&mask, SIGINT);
+ sigaddset(&mask, SIGTERM);
+ sigaddset(&mask, SIGCHLD);
+ sigaddset(&mask, SIGUSR2);
+
+#define SIGNAL(s, handler) do { \
+ sa.sa_handler = handler; \
+ if (sigaction(s, &sa, NULL) < 0) \
+ fatal("Couldn't establish signal handler (%d): %m", s); \
+ } while (0)
+
+ sa.sa_mask = mask;
+ sa.sa_flags = 0;
+ SIGNAL(SIGHUP, hup); /* Hangup */
+ SIGNAL(SIGINT, term); /* Interrupt */
+ SIGNAL(SIGTERM, term); /* Terminate */
+ SIGNAL(SIGCHLD, chld);
+
+ SIGNAL(SIGUSR1, toggle_debug); /* Toggle debug flag */
+ SIGNAL(SIGUSR2, open_ccp); /* Reopen CCP */
+
+ /*
+ * Install a handler for other signals which would otherwise
+ * cause pppd to exit without cleaning up.
+ */
+ SIGNAL(SIGABRT, bad_signal);
+ SIGNAL(SIGALRM, bad_signal);
+ SIGNAL(SIGFPE, bad_signal);
+ SIGNAL(SIGILL, bad_signal);
+ SIGNAL(SIGPIPE, bad_signal);
+ SIGNAL(SIGQUIT, bad_signal);
+ SIGNAL(SIGSEGV, bad_signal);
+#ifdef SIGBUS
+ SIGNAL(SIGBUS, bad_signal);
+#endif
+#ifdef SIGEMT
+ SIGNAL(SIGEMT, bad_signal);
+#endif
+#ifdef SIGPOLL
+ SIGNAL(SIGPOLL, bad_signal);
+#endif
+#ifdef SIGPROF
+ SIGNAL(SIGPROF, bad_signal);
+#endif
+#ifdef SIGSYS
+ SIGNAL(SIGSYS, bad_signal);
+#endif
+#ifdef SIGTRAP
+ SIGNAL(SIGTRAP, bad_signal);
+#endif
+#ifdef SIGVTALRM
+ SIGNAL(SIGVTALRM, bad_signal);
+#endif
+#ifdef SIGXCPU
+ SIGNAL(SIGXCPU, bad_signal);
+#endif
+#ifdef SIGXFSZ
+ SIGNAL(SIGXFSZ, bad_signal);
+#endif
+
+ /*
+ * Apparently we can get a SIGPIPE when we call syslog, if
+ * syslogd has died and been restarted. Ignoring it seems
+ * be sufficient.
+ */
+ signal(SIGPIPE, SIG_IGN);
+}
+
+/*
+ * set_ifunit - do things we need to do once we know which ppp
+ * unit we are using.
+ */
+void
+set_ifunit(iskey)
+ int iskey;
+{
+ info("Using interface %s%d", PPP_DRV_NAME, ifunit);
+ slprintf(ifname, sizeof(ifname), "%s%d", PPP_DRV_NAME, ifunit);
+ script_setenv("IFNAME", ifname, iskey);
+ if (iskey) {
+ create_pidfile(); /* write pid to file */
+ create_linkpidfile();
+ }
+}
+
+/*
+ * detach - detach us from the controlling terminal.
+ */
+void
+detach()
+{
+ int pid;
+ char numbuf[16];
+
+ if (detached)
+ return;
+ if ((pid = fork()) < 0) {
+ error("Couldn't detach (fork failed: %m)");
+ die(1); /* or just return? */
+ }
+ if (pid != 0) {
+ /* parent */
+ notify(pidchange, pid);
+ exit(0); /* parent dies */
+ }
+ setsid();
+ chdir("/");
+ close(0);
+ close(1);
+ close(2);
+ detached = 1;
+ if (log_default)
+ log_to_fd = -1;
+ /* update pid files if they have been written already */
+ if (pidfilename[0])
+ create_pidfile();
+ if (linkpidfile[0])
+ create_linkpidfile();
+ slprintf(numbuf, sizeof(numbuf), "%d", getpid());
+ script_setenv("PPPD_PID", numbuf, 1);
+}
+
+/*
+ * reopen_log - (re)open our connection to syslog.
+ */
+void
+reopen_log()
+{
+#ifdef ULTRIX
+ openlog("pppd", LOG_PID);
+#else
+ openlog("pppd", LOG_PID | LOG_NDELAY, LOG_PPP);
+ setlogmask(LOG_UPTO(LOG_INFO));
+#endif
+}
+
+/*
+ * Create a file containing our process ID.
+ */
+static void
+create_pidfile()
+{
+ FILE *pidfile;
+
+ slprintf(pidfilename, sizeof(pidfilename), "%s%s.pid",
+ _PATH_VARRUN, ifname);
+ if ((pidfile = fopen(pidfilename, "w")) != NULL) {
+ fprintf(pidfile, "%d\n", getpid());
+ (void) fclose(pidfile);
+ } else {
+ error("Failed to create pid file %s: %m", pidfilename);
+ pidfilename[0] = 0;
+ }
+}
+
+static void
+create_linkpidfile()
+{
+ FILE *pidfile;
+
+ if (linkname[0] == 0)
+ return;
+ script_setenv("LINKNAME", linkname, 1);
+ slprintf(linkpidfile, sizeof(linkpidfile), "%sppp-%s.pid",
+ _PATH_VARRUN, linkname);
+ if ((pidfile = fopen(linkpidfile, "w")) != NULL) {
+ fprintf(pidfile, "%d\n", getpid());
+ if (ifname[0])
+ fprintf(pidfile, "%s\n", ifname);
+ (void) fclose(pidfile);
+ } else {
+ error("Failed to create pid file %s: %m", linkpidfile);
+ linkpidfile[0] = 0;
+ }
+}
+
+/*
+ * holdoff_end - called via a timeout when the holdoff period ends.
+ */
+static void
+holdoff_end(arg)
+ void *arg;
+{
+ new_phase(PHASE_DORMANT);
+}
+
+/* List of protocol names, to make our messages a little more informative. */
+struct protocol_list {
+ u_short proto;
+ const char *name;
+} protocol_list[] = {
+ { 0x21, "IP" },
+ { 0x23, "OSI Network Layer" },
+ { 0x25, "Xerox NS IDP" },
+ { 0x27, "DECnet Phase IV" },
+ { 0x29, "Appletalk" },
+ { 0x2b, "Novell IPX" },
+ { 0x2d, "VJ compressed TCP/IP" },
+ { 0x2f, "VJ uncompressed TCP/IP" },
+ { 0x31, "Bridging PDU" },
+ { 0x33, "Stream Protocol ST-II" },
+ { 0x35, "Banyan Vines" },
+ { 0x39, "AppleTalk EDDP" },
+ { 0x3b, "AppleTalk SmartBuffered" },
+ { 0x3d, "Multi-Link" },
+ { 0x3f, "NETBIOS Framing" },
+ { 0x41, "Cisco Systems" },
+ { 0x43, "Ascom Timeplex" },
+ { 0x45, "Fujitsu Link Backup and Load Balancing (LBLB)" },
+ { 0x47, "DCA Remote Lan" },
+ { 0x49, "Serial Data Transport Protocol (PPP-SDTP)" },
+ { 0x4b, "SNA over 802.2" },
+ { 0x4d, "SNA" },
+ { 0x4f, "IP6 Header Compression" },
+ { 0x6f, "Stampede Bridging" },
+ { 0xfb, "single-link compression" },
+ { 0xfd, "1st choice compression" },
+ { 0x0201, "802.1d Hello Packets" },
+ { 0x0203, "IBM Source Routing BPDU" },
+ { 0x0205, "DEC LANBridge100 Spanning Tree" },
+ { 0x0231, "Luxcom" },
+ { 0x0233, "Sigma Network Systems" },
+ { 0x8021, "Internet Protocol Control Protocol" },
+ { 0x8023, "OSI Network Layer Control Protocol" },
+ { 0x8025, "Xerox NS IDP Control Protocol" },
+ { 0x8027, "DECnet Phase IV Control Protocol" },
+ { 0x8029, "Appletalk Control Protocol" },
+ { 0x802b, "Novell IPX Control Protocol" },
+ { 0x8031, "Bridging NCP" },
+ { 0x8033, "Stream Protocol Control Protocol" },
+ { 0x8035, "Banyan Vines Control Protocol" },
+ { 0x803d, "Multi-Link Control Protocol" },
+ { 0x803f, "NETBIOS Framing Control Protocol" },
+ { 0x8041, "Cisco Systems Control Protocol" },
+ { 0x8043, "Ascom Timeplex" },
+ { 0x8045, "Fujitsu LBLB Control Protocol" },
+ { 0x8047, "DCA Remote Lan Network Control Protocol (RLNCP)" },
+ { 0x8049, "Serial Data Control Protocol (PPP-SDCP)" },
+ { 0x804b, "SNA over 802.2 Control Protocol" },
+ { 0x804d, "SNA Control Protocol" },
+ { 0x804f, "IP6 Header Compression Control Protocol" },
+ { 0x006f, "Stampede Bridging Control Protocol" },
+ { 0x80fb, "Single Link Compression Control Protocol" },
+ { 0x80fd, "Compression Control Protocol" },
+ { 0xc021, "Link Control Protocol" },
+ { 0xc023, "Password Authentication Protocol" },
+ { 0xc025, "Link Quality Report" },
+ { 0xc027, "Shiva Password Authentication Protocol" },
+ { 0xc029, "CallBack Control Protocol (CBCP)" },
+ { 0xc081, "Container Control Protocol" },
+ { 0xc223, "Challenge Handshake Authentication Protocol" },
+ { 0xc281, "Proprietary Authentication Protocol" },
+ { 0, NULL },
+};
+
+/*
+ * protocol_name - find a name for a PPP protocol.
+ */
+const char *
+protocol_name(proto)
+ int proto;
+{
+ struct protocol_list *lp;
+
+ for (lp = protocol_list; lp->proto != 0; ++lp)
+ if (proto == lp->proto)
+ return lp->name;
+ return NULL;
+}
+
+/*
+ * get_input - called when incoming data is available.
+ */
+static void
+get_input()
+{
+ int len, i;
+ u_char *p;
+ u_short protocol;
+ struct protent *protp;
+
+ p = inpacket_buf; /* point to beginning of packet buffer */
+
+ len = read_packet(inpacket_buf);
+ if (len < 0)
+ return;
+
+ if (len == 0) {
+ notice("Modem hangup");
+ hungup = 1;
+ status = EXIT_HANGUP;
+ lcp_lowerdown(0); /* serial link is no longer available */
+ link_terminated(0);
+ return;
+ }
+
+ if (debug /*&& (debugflags & DBG_INPACKET)*/)
+ dbglog("rcvd %P", p, len);
+
+ if (len < PPP_HDRLEN) {
+ MAINDEBUG(("io(): Received short packet."));
+ return;
+ }
+
+ p += 2; /* Skip address and control */
+ GETSHORT(protocol, p);
+ len -= PPP_HDRLEN;
+
+ /*
+ * Toss all non-LCP packets unless LCP is OPEN.
+ */
+ if (protocol != PPP_LCP && lcp_fsm[0].state != OPENED) {
+ MAINDEBUG(("get_input: Received non-LCP packet when LCP not open."));
+ return;
+ }
+
+ /*
+ * Until we get past the authentication phase, toss all packets
+ * except LCP, LQR and authentication packets.
+ */
+ if (phase <= PHASE_AUTHENTICATE
+ && !(protocol == PPP_LCP || protocol == PPP_LQR
+ || protocol == PPP_PAP || protocol == PPP_CHAP)) {
+ MAINDEBUG(("get_input: discarding proto 0x%x in phase %d",
+ protocol, phase));
+ return;
+ }
+
+ /*
+ * Upcall the proper protocol input routine.
+ */
+ for (i = 0; (protp = protocols[i]) != NULL; ++i) {
+ if (protp->protocol == protocol && protp->enabled_flag) {
+ (*protp->input)(0, p, len);
+ return;
+ }
+ if (protocol == (protp->protocol & ~0x8000) && protp->enabled_flag
+ && protp->datainput != NULL) {
+ (*protp->datainput)(0, p, len);
+ return;
+ }
+ }
+
+ if (debug) {
+ const char *pname = protocol_name(protocol);
+ if (pname != NULL)
+ warn("Unsupported protocol '%s' (0x%x) received", pname, protocol);
+ else
+ warn("Unsupported protocol 0x%x received", protocol);
+ }
+ lcp_sprotrej(0, p - PPP_HDRLEN, len + PPP_HDRLEN);
+}
+
+/*
+ * new_phase - signal the start of a new phase of pppd's operation.
+ */
+void
+new_phase(p)
+ int p;
+{
+ phase = p;
+ if (new_phase_hook)
+ (*new_phase_hook)(p);
+ notify(phasechange, p);
+}
+
+/*
+ * die - clean up state and exit with the specified status.
+ */
+void
+die(status)
+ int status;
+{
+ cleanup();
+ notify(exitnotify, status);
+ syslog(LOG_INFO, "Exit.");
+ exit(status);
+}
+
+/*
+ * cleanup - restore anything which needs to be restored before we exit
+ */
+/* ARGSUSED */
+static void
+cleanup()
+{
+ sys_cleanup();
+
+ if (fd_ppp >= 0)
+ the_channel->disestablish_ppp(devfd);
+ if (the_channel->cleanup)
+ (*the_channel->cleanup)();
+
+ if (pidfilename[0] != 0 && unlink(pidfilename) < 0 && errno != ENOENT)
+ warn("unable to delete pid file %s: %m", pidfilename);
+ pidfilename[0] = 0;
+ if (linkpidfile[0] != 0 && unlink(linkpidfile) < 0 && errno != ENOENT)
+ warn("unable to delete pid file %s: %m", linkpidfile);
+ linkpidfile[0] = 0;
+
+ if (pppdb != NULL)
+ cleanup_db();
+}
+
+/*
+ * update_link_stats - get stats at link termination.
+ */
+void
+update_link_stats(u)
+ int u;
+{
+ struct timeval now;
+ char numbuf[32];
+
+ if (!get_ppp_stats(u, &link_stats)
+ || gettimeofday(&now, NULL) < 0)
+ return;
+ link_connect_time = now.tv_sec - start_time.tv_sec;
+ link_stats_valid = 1;
+
+ slprintf(numbuf, sizeof(numbuf), "%d", link_connect_time);
+ script_setenv("CONNECT_TIME", numbuf, 0);
+ slprintf(numbuf, sizeof(numbuf), "%d", link_stats.bytes_out);
+ script_setenv("BYTES_SENT", numbuf, 0);
+ slprintf(numbuf, sizeof(numbuf), "%d", link_stats.bytes_in);
+ script_setenv("BYTES_RCVD", numbuf, 0);
+}
+
+
+struct callout {
+ struct timeval c_time; /* time at which to call routine */
+ void *c_arg; /* argument to routine */
+ void (*c_func) __P((void *)); /* routine */
+ struct callout *c_next;
+};
+
+static struct callout *callout = NULL; /* Callout list */
+static struct timeval timenow; /* Current time */
+
+/*
+ * timeout - Schedule a timeout.
+ *
+ * Note that this timeout takes the number of milliseconds, NOT hz (as in
+ * the kernel).
+ */
+void
+timeout(func, arg, secs, usecs)
+ void (*func) __P((void *));
+ void *arg;
+ int secs, usecs;
+{
+ struct callout *newp, *p, **pp;
+
+ MAINDEBUG(("Timeout %p:%p in %d.%03d seconds.", func, arg,
+ time / 1000, time % 1000));
+
+ /*
+ * Allocate timeout.
+ */
+ if ((newp = (struct callout *) malloc(sizeof(struct callout))) == NULL)
+ fatal("Out of memory in timeout()!");
+ newp->c_arg = arg;
+ newp->c_func = func;
+ gettimeofday(&timenow, NULL);
+ newp->c_time.tv_sec = timenow.tv_sec + secs;
+ newp->c_time.tv_usec = timenow.tv_usec + usecs;
+ if (newp->c_time.tv_usec >= 1000000) {
+ newp->c_time.tv_sec += newp->c_time.tv_usec / 1000000;
+ newp->c_time.tv_usec %= 1000000;
+ }
+
+ /*
+ * Find correct place and link it in.
+ */
+ for (pp = &callout; (p = *pp); pp = &p->c_next)
+ if (newp->c_time.tv_sec < p->c_time.tv_sec
+ || (newp->c_time.tv_sec == p->c_time.tv_sec
+ && newp->c_time.tv_usec < p->c_time.tv_usec))
+ break;
+ newp->c_next = p;
+ *pp = newp;
+}
+
+
+/*
+ * untimeout - Unschedule a timeout.
+ */
+void
+untimeout(func, arg)
+ void (*func) __P((void *));
+ void *arg;
+{
+ struct callout **copp, *freep;
+
+ MAINDEBUG(("Untimeout %p:%p.", func, arg));
+
+ /*
+ * Find first matching timeout and remove it from the list.
+ */
+ for (copp = &callout; (freep = *copp); copp = &freep->c_next)
+ if (freep->c_func == func && freep->c_arg == arg) {
+ *copp = freep->c_next;
+ free((char *) freep);
+ break;
+ }
+}
+
+
+/*
+ * calltimeout - Call any timeout routines which are now due.
+ */
+static void
+calltimeout()
+{
+ struct callout *p;
+
+ while (callout != NULL) {
+ p = callout;
+
+ if (gettimeofday(&timenow, NULL) < 0)
+ fatal("Failed to get time of day: %m");
+ if (!(p->c_time.tv_sec < timenow.tv_sec
+ || (p->c_time.tv_sec == timenow.tv_sec
+ && p->c_time.tv_usec <= timenow.tv_usec)))
+ break; /* no, it's not time yet */
+
+ callout = p->c_next;
+ (*p->c_func)(p->c_arg);
+
+ free((char *) p);
+ }
+}
+
+
+/*
+ * timeleft - return the length of time until the next timeout is due.
+ */
+static struct timeval *
+timeleft(tvp)
+ struct timeval *tvp;
+{
+ if (callout == NULL)
+ return NULL;
+
+ gettimeofday(&timenow, NULL);
+ tvp->tv_sec = callout->c_time.tv_sec - timenow.tv_sec;
+ tvp->tv_usec = callout->c_time.tv_usec - timenow.tv_usec;
+ if (tvp->tv_usec < 0) {
+ tvp->tv_usec += 1000000;
+ tvp->tv_sec -= 1;
+ }
+ if (tvp->tv_sec < 0)
+ tvp->tv_sec = tvp->tv_usec = 0;
+
+ return tvp;
+}
+
+
+/*
+ * kill_my_pg - send a signal to our process group, and ignore it ourselves.
+ */
+static void
+kill_my_pg(sig)
+ int sig;
+{
+ struct sigaction act, oldact;
+
+ act.sa_handler = SIG_IGN;
+ act.sa_flags = 0;
+ kill(0, sig);
+ sigaction(sig, &act, &oldact);
+ sigaction(sig, &oldact, NULL);
+}
+
+
+/*
+ * hup - Catch SIGHUP signal.
+ *
+ * Indicates that the physical layer has been disconnected.
+ * We don't rely on this indication; if the user has sent this
+ * signal, we just take the link down.
+ */
+static void
+hup(sig)
+ int sig;
+{
+ info("Hangup (SIGHUP)");
+ got_sighup = 1;
+ if (conn_running)
+ /* Send the signal to the [dis]connector process(es) also */
+ kill_my_pg(sig);
+ notify(sigreceived, sig);
+ if (waiting)
+ siglongjmp(sigjmp, 1);
+}
+
+
+/*
+ * term - Catch SIGTERM signal and SIGINT signal (^C/del).
+ *
+ * Indicates that we should initiate a graceful disconnect and exit.
+ */
+/*ARGSUSED*/
+static void
+term(sig)
+ int sig;
+{
+ info("Terminating on signal %d.", sig);
+ got_sigterm = 1;
+ if (conn_running)
+ /* Send the signal to the [dis]connector process(es) also */
+ kill_my_pg(sig);
+ notify(sigreceived, sig);
+ if (waiting)
+ siglongjmp(sigjmp, 1);
+}
+
+
+/*
+ * chld - Catch SIGCHLD signal.
+ * Sets a flag so we will call reap_kids in the mainline.
+ */
+static void
+chld(sig)
+ int sig;
+{
+ got_sigchld = 1;
+ if (waiting)
+ siglongjmp(sigjmp, 1);
+}
+
+
+/*
+ * toggle_debug - Catch SIGUSR1 signal.
+ *
+ * Toggle debug flag.
+ */
+/*ARGSUSED*/
+static void
+toggle_debug(sig)
+ int sig;
+{
+ debug = !debug;
+ if (debug) {
+ setlogmask(LOG_UPTO(LOG_DEBUG));
+ } else {
+ setlogmask(LOG_UPTO(LOG_WARNING));
+ }
+}
+
+
+/*
+ * open_ccp - Catch SIGUSR2 signal.
+ *
+ * Try to (re)negotiate compression.
+ */
+/*ARGSUSED*/
+static void
+open_ccp(sig)
+ int sig;
+{
+ got_sigusr2 = 1;
+ if (waiting)
+ siglongjmp(sigjmp, 1);
+}
+
+
+/*
+ * bad_signal - We've caught a fatal signal. Clean up state and exit.
+ */
+static void
+bad_signal(sig)
+ int sig;
+{
+ static int crashed = 0;
+
+ if (crashed)
+ _exit(127);
+ crashed = 1;
+ error("Fatal signal %d", sig);
+ if (conn_running)
+ kill_my_pg(SIGTERM);
+ notify(sigreceived, sig);
+ die(127);
+}
+
+
+/*
+ * device_script - run a program to talk to the specified fds
+ * (e.g. to run the connector or disconnector script).
+ * stderr gets connected to the log fd or to the _PATH_CONNERRS file.
+ */
+int
+device_script(program, in, out, dont_wait)
+ char *program;
+ int in, out;
+ int dont_wait;
+{
+ int pid, fd;
+ int status = -1;
+ int errfd;
+
+ ++conn_running;
+ pid = fork();
+
+ if (pid < 0) {
+ --conn_running;
+ error("Failed to create child process: %m");
+ return -1;
+ }
+
+ if (pid != 0) {
+ if (dont_wait) {
+ record_child(pid, program, NULL, NULL);
+ status = 0;
+ } else {
+ while (waitpid(pid, &status, 0) < 0) {
+ if (errno == EINTR)
+ continue;
+ fatal("error waiting for (dis)connection process: %m");
+ }
+ --conn_running;
+ }
+ return (status == 0 ? 0 : -1);
+ }
+
+ /* here we are executing in the child */
+ /* make sure fds 0, 1, 2 are occupied */
+ while ((fd = dup(in)) >= 0) {
+ if (fd > 2) {
+ close(fd);
+ break;
+ }
+ }
+
+ /* dup in and out to fds > 2 */
+ in = dup(in);
+ out = dup(out);
+ if (log_to_fd >= 0) {
+ errfd = dup(log_to_fd);
+ } else {
+ errfd = open(_PATH_CONNERRS, O_WRONLY | O_APPEND | O_CREAT, 0600);
+ }
+
+ /* close fds 0 - 2 and any others we can think of */
+ close(0);
+ close(1);
+ close(2);
+ sys_close();
+ if (the_channel->close)
+ (*the_channel->close)();
+ closelog();
+
+ /* dup the in, out, err fds to 0, 1, 2 */
+ dup2(in, 0);
+ close(in);
+ dup2(out, 1);
+ close(out);
+ if (errfd >= 0) {
+ dup2(errfd, 2);
+ close(errfd);
+ }
+
+ setuid(uid);
+ if (getuid() != uid) {
+ error("setuid failed");
+ exit(1);
+ }
+ setgid(getgid());
+ {
+ int argc = 0;
+ char * argv[500];
+ char * ptr = program;
+ while (ptr != NULL) {
+ argv[argc] = ptr;
+ argc++;
+ ptr = strchr(ptr, ' ');
+ if (ptr) {
+ ptr[0] = '\0';
+ ptr++;
+ }
+ }
+ argv[argc] = NULL;
+ execv(argv[0], argv);
+ error("could not exec %s: %m", program);
+ exit(99);
+ }
+ /* NOTREACHED */
+}
+
+
+/*
+ * run-program - execute a program with given arguments,
+ * but don't wait for it.
+ * If the program can't be executed, logs an error unless
+ * must_exist is 0 and the program file doesn't exist.
+ * Returns -1 if it couldn't fork, 0 if the file doesn't exist
+ * or isn't an executable plain file, or the process ID of the child.
+ * If done != NULL, (*done)(arg) will be called later (within
+ * reap_kids) iff the return value is > 0.
+ */
+pid_t
+run_program(prog, args, must_exist, done, arg)
+ char *prog;
+ char **args;
+ int must_exist;
+ void (*done) __P((void *));
+ void *arg;
+{
+ int pid;
+ struct stat sbuf;
+
+ /*
+ * First check if the file exists and is executable.
+ * We don't use access() because that would use the
+ * real user-id, which might not be root, and the script
+ * might be accessible only to root.
+ */
+ errno = EINVAL;
+ if (stat(prog, &sbuf) < 0 || !S_ISREG(sbuf.st_mode)
+ || (sbuf.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0) {
+ if (must_exist || errno != ENOENT)
+ warn("Can't execute %s: %m", prog);
+ return 0;
+ }
+
+ pid = fork();
+ if (pid == -1) {
+ error("Failed to create child process for %s: %m", prog);
+ return -1;
+ }
+ if (pid == 0) {
+ int new_fd;
+
+ /* Leave the current location */
+ (void) setsid(); /* No controlling tty. */
+ (void) umask (S_IRWXG|S_IRWXO);
+ (void) chdir ("/"); /* no current directory. */
+ setuid(0); /* set real UID = root */
+ setgid(getegid());
+
+ /* Ensure that nothing of our device environment is inherited. */
+ sys_close();
+ closelog();
+ close (0);
+ close (1);
+ close (2);
+ if (the_channel->close)
+ (*the_channel->close)();
+
+ /* Don't pass handles to the PPP device, even by accident. */
+ new_fd = open (_PATH_DEVNULL, O_RDWR);
+ if (new_fd >= 0) {
+ if (new_fd != 0) {
+ dup2 (new_fd, 0); /* stdin <- /dev/null */
+ close (new_fd);
+ }
+ dup2 (0, 1); /* stdout -> /dev/null */
+ dup2 (0, 2); /* stderr -> /dev/null */
+ }
+
+#ifdef BSD
+ /* Force the priority back to zero if pppd is running higher. */
+ if (setpriority (PRIO_PROCESS, 0, 0) < 0)
+ warn("can't reset priority to 0: %m");
+#endif
+
+ /* SysV recommends a second fork at this point. */
+
+ /* run the program */
+ execve(prog, args, script_env);
+ if (must_exist || errno != ENOENT) {
+ /* have to reopen the log, there's nowhere else
+ for the message to go. */
+ reopen_log();
+ syslog(LOG_ERR, "Can't execute %s: %m", prog);
+ closelog();
+ }
+ _exit(-1);
+ }
+
+ if (debug)
+ dbglog("Script %s started (pid %d)", prog, pid);
+ record_child(pid, prog, done, arg);
+
+ return pid;
+}
+
+
+/*
+ * record_child - add a child process to the list for reap_kids
+ * to use.
+ */
+void
+record_child(pid, prog, done, arg)
+ int pid;
+ char *prog;
+ void (*done) __P((void *));
+ void *arg;
+{
+ struct subprocess *chp;
+
+ ++n_children;
+
+ chp = (struct subprocess *) malloc(sizeof(struct subprocess));
+ if (chp == NULL) {
+ warn("losing track of %s process", prog);
+ } else {
+ chp->pid = pid;
+ chp->prog = prog;
+ chp->done = done;
+ chp->arg = arg;
+ chp->next = children;
+ children = chp;
+ }
+}
+
+
+/*
+ * reap_kids - get status from any dead child processes,
+ * and log a message for abnormal terminations.
+ */
+static int
+reap_kids(waitfor)
+ int waitfor;
+{
+ int pid, status;
+ struct subprocess *chp, **prevp;
+
+ if (n_children == 0)
+ return 0;
+ while ((pid = waitpid(-1, &status, (waitfor? 0: WNOHANG))) != -1
+ && pid != 0) {
+ for (prevp = &children; (chp = *prevp) != NULL; prevp = &chp->next) {
+ if (chp->pid == pid) {
+ --n_children;
+ *prevp = chp->next;
+ break;
+ }
+ }
+ if (WIFSIGNALED(status)) {
+ warn("Child process %s (pid %d) terminated with signal %d",
+ (chp? chp->prog: "??"), pid, WTERMSIG(status));
+ } else if (debug)
+ dbglog("Script %s finished (pid %d), status = 0x%x",
+ (chp? chp->prog: "??"), pid, status);
+ if (chp && chp->done)
+ (*chp->done)(chp->arg);
+ if (chp)
+ free(chp);
+ }
+ if (pid == -1) {
+ if (errno == ECHILD)
+ return -1;
+ if (errno != EINTR)
+ error("Error waiting for child process: %m");
+ }
+ return 0;
+}
+
+/*
+ * add_notifier - add a new function to be called when something happens.
+ */
+void
+add_notifier(notif, func, arg)
+ struct notifier **notif;
+ notify_func func;
+ void *arg;
+{
+ struct notifier *np;
+
+ np = malloc(sizeof(struct notifier));
+ if (np == 0)
+ novm("notifier struct");
+ np->next = *notif;
+ np->func = func;
+ np->arg = arg;
+ *notif = np;
+}
+
+/*
+ * remove_notifier - remove a function from the list of things to
+ * be called when something happens.
+ */
+void
+remove_notifier(notif, func, arg)
+ struct notifier **notif;
+ notify_func func;
+ void *arg;
+{
+ struct notifier *np;
+
+ for (; (np = *notif) != 0; notif = &np->next) {
+ if (np->func == func && np->arg == arg) {
+ *notif = np->next;
+ free(np);
+ break;
+ }
+ }
+}
+
+/*
+ * notify - call a set of functions registered with add_notify.
+ */
+void
+notify(notif, val)
+ struct notifier *notif;
+ int val;
+{
+ struct notifier *np;
+
+ while ((np = notif) != 0) {
+ notif = np->next;
+ (*np->func)(np->arg, val);
+ }
+}
+
+/*
+ * novm - log an error message saying we ran out of memory, and die.
+ */
+void
+novm(msg)
+ char *msg;
+{
+ fatal("Virtual memory exhausted allocating %s\n", msg);
+}
+
+/*
+ * script_setenv - set an environment variable value to be used
+ * for scripts that we run (e.g. ip-up, auth-up, etc.)
+ */
+void
+script_setenv(var, value, iskey)
+ char *var, *value;
+ int iskey;
+{
+ size_t varl = strlen(var);
+ size_t vl = varl + strlen(value) + 2;
+ int i;
+ char *p, *newstring;
+
+ newstring = (char *) malloc(vl+1);
+ if (newstring == 0)
+ return;
+ *newstring++ = iskey;
+ slprintf(newstring, vl, "%s=%s", var, value);
+
+ /* check if this variable is already set */
+ if (script_env != 0) {
+ for (i = 0; (p = script_env[i]) != 0; ++i) {
+ if (strncmp(p, var, varl) == 0 && p[varl] == '=') {
+ if (p[-1] && pppdb != NULL)
+ delete_db_key(p);
+ free(p-1);
+ script_env[i] = newstring;
+ if (iskey && pppdb != NULL)
+ add_db_key(newstring);
+ update_db_entry();
+ return;
+ }
+ }
+ } else {
+ /* no space allocated for script env. ptrs. yet */
+ i = 0;
+ script_env = (char **) malloc(16 * sizeof(char *));
+ if (script_env == 0)
+ return;
+ s_env_nalloc = 16;
+ }
+
+ /* reallocate script_env with more space if needed */
+ if (i + 1 >= s_env_nalloc) {
+ int new_n = i + 17;
+ char **newenv = (char **) realloc((void *)script_env,
+ new_n * sizeof(char *));
+ if (newenv == 0)
+ return;
+ script_env = newenv;
+ s_env_nalloc = new_n;
+ }
+
+ script_env[i] = newstring;
+ script_env[i+1] = 0;
+
+ if (pppdb != NULL) {
+ if (iskey)
+ add_db_key(newstring);
+ update_db_entry();
+ }
+}
+
+/*
+ * script_unsetenv - remove a variable from the environment
+ * for scripts.
+ */
+void
+script_unsetenv(var)
+ char *var;
+{
+ int vl = strlen(var);
+ int i;
+ char *p;
+
+ if (script_env == 0)
+ return;
+ for (i = 0; (p = script_env[i]) != 0; ++i) {
+ if (strncmp(p, var, vl) == 0 && p[vl] == '=') {
+ if (p[-1] && pppdb != NULL)
+ delete_db_key(p);
+ free(p-1);
+ while ((script_env[i] = script_env[i+1]) != 0)
+ ++i;
+ break;
+ }
+ }
+ if (pppdb != NULL)
+ update_db_entry();
+}
+
+/*
+ * update_db_entry - update our entry in the database.
+ */
+static void
+update_db_entry()
+{
+ TDB_DATA key, dbuf;
+ int vlen, i;
+ char *p, *q, *vbuf;
+
+ if (script_env == NULL)
+ return;
+ vlen = 0;
+ for (i = 0; (p = script_env[i]) != 0; ++i)
+ vlen += strlen(p) + 1;
+ vbuf = malloc(vlen);
+ if (vbuf == 0)
+ novm("database entry");
+ q = vbuf;
+ for (i = 0; (p = script_env[i]) != 0; ++i)
+ q += slprintf(q, vbuf + vlen - q, "%s;", p);
+
+ key.dptr = db_key;
+ key.dsize = strlen(db_key);
+ dbuf.dptr = vbuf;
+ dbuf.dsize = vlen;
+ if (tdb_store(pppdb, key, dbuf, TDB_REPLACE))
+ error("tdb_store failed: %s", tdb_error(pppdb));
+
+}
+
+/*
+ * add_db_key - add a key that we can use to look up our database entry.
+ */
+static void
+add_db_key(str)
+ const char *str;
+{
+ TDB_DATA key, dbuf;
+
+ key.dptr = (char *) str;
+ key.dsize = strlen(str);
+ dbuf.dptr = db_key;
+ dbuf.dsize = strlen(db_key);
+ if (tdb_store(pppdb, key, dbuf, TDB_REPLACE))
+ error("tdb_store key failed: %s", tdb_error(pppdb));
+}
+
+/*
+ * delete_db_key - delete a key for looking up our database entry.
+ */
+static void
+delete_db_key(str)
+ const char *str;
+{
+ TDB_DATA key;
+
+ key.dptr = (char *) str;
+ key.dsize = strlen(str);
+ tdb_delete(pppdb, key);
+}
+
+/*
+ * cleanup_db - delete all the entries we put in the database.
+ */
+static void
+cleanup_db()
+{
+ TDB_DATA key;
+ int i;
+ char *p;
+
+ key.dptr = db_key;
+ key.dsize = strlen(db_key);
+ tdb_delete(pppdb, key);
+ for (i = 0; (p = script_env[i]) != 0; ++i)
+ if (p[-1])
+ delete_db_key(p);
+}
diff --git a/mdk-stage1/ppp/pppd/md4.c b/mdk-stage1/ppp/pppd/md4.c
new file mode 100644
index 000000000..cda9f943d
--- /dev/null
+++ b/mdk-stage1/ppp/pppd/md4.c
@@ -0,0 +1,298 @@
+/*
+** ********************************************************************
+** md4.c -- Implementation of MD4 Message Digest Algorithm **
+** Updated: 2/16/90 by Ronald L. Rivest **
+** (C) 1990 RSA Data Security, Inc. **
+** ********************************************************************
+*/
+
+/*
+** To use MD4:
+** -- Include md4.h in your program
+** -- Declare an MDstruct MD to hold the state of the digest
+** computation.
+** -- Initialize MD using MDbegin(&MD)
+** -- For each full block (64 bytes) X you wish to process, call
+** MD4Update(&MD,X,512)
+** (512 is the number of bits in a full block.)
+** -- For the last block (less than 64 bytes) you wish to process,
+** MD4Update(&MD,X,n)
+** where n is the number of bits in the partial block. A partial
+** block terminates the computation, so every MD computation
+** should terminate by processing a partial block, even if it
+** has n = 0.
+** -- The message digest is available in MD.buffer[0] ...
+** MD.buffer[3]. (Least-significant byte of each word
+** should be output first.)
+** -- You can print out the digest using MDprint(&MD)
+*/
+
+/* Implementation notes:
+** This implementation assumes that ints are 32-bit quantities.
+*/
+
+#define TRUE 1
+#define FALSE 0
+
+/* Compile-time includes
+*/
+#include <stdio.h>
+#include "md4.h"
+#include "pppd.h"
+
+/* Compile-time declarations of MD4 "magic constants".
+*/
+#define I0 0x67452301 /* Initial values for MD buffer */
+#define I1 0xefcdab89
+#define I2 0x98badcfe
+#define I3 0x10325476
+#define C2 013240474631 /* round 2 constant = sqrt(2) in octal */
+#define C3 015666365641 /* round 3 constant = sqrt(3) in octal */
+/* C2 and C3 are from Knuth, The Art of Programming, Volume 2
+** (Seminumerical Algorithms), Second Edition (1981), Addison-Wesley.
+** Table 2, page 660.
+*/
+
+#define fs1 3 /* round 1 shift amounts */
+#define fs2 7
+#define fs3 11
+#define fs4 19
+#define gs1 3 /* round 2 shift amounts */
+#define gs2 5
+#define gs3 9
+#define gs4 13
+#define hs1 3 /* round 3 shift amounts */
+#define hs2 9
+#define hs3 11
+#define hs4 15
+
+/* Compile-time macro declarations for MD4.
+** Note: The "rot" operator uses the variable "tmp".
+** It assumes tmp is declared as unsigned int, so that the >>
+** operator will shift in zeros rather than extending the sign bit.
+*/
+#define f(X,Y,Z) ((X&Y) | ((~X)&Z))
+#define g(X,Y,Z) ((X&Y) | (X&Z) | (Y&Z))
+#define h(X,Y,Z) (X^Y^Z)
+#define rot(X,S) (tmp=X,(tmp<<S) | (tmp>>(32-S)))
+#define ff(A,B,C,D,i,s) A = rot((A + f(B,C,D) + X[i]),s)
+#define gg(A,B,C,D,i,s) A = rot((A + g(B,C,D) + X[i] + C2),s)
+#define hh(A,B,C,D,i,s) A = rot((A + h(B,C,D) + X[i] + C3),s)
+
+/* MD4print(MDp)
+** Print message digest buffer MDp as 32 hexadecimal digits.
+** Order is from low-order byte of buffer[0] to high-order byte of
+** buffer[3].
+** Each byte is printed with high-order hexadecimal digit first.
+** This is a user-callable routine.
+*/
+void
+MD4Print(MDp)
+MD4_CTX *MDp;
+{
+ int i,j;
+ for (i=0;i<4;i++)
+ for (j=0;j<32;j=j+8)
+ printf("%02x",(MDp->buffer[i]>>j) & 0xFF);
+}
+
+/* MD4Init(MDp)
+** Initialize message digest buffer MDp.
+** This is a user-callable routine.
+*/
+void
+MD4Init(MDp)
+MD4_CTX *MDp;
+{
+ int i;
+ MDp->buffer[0] = I0;
+ MDp->buffer[1] = I1;
+ MDp->buffer[2] = I2;
+ MDp->buffer[3] = I3;
+ for (i=0;i<8;i++) MDp->count[i] = 0;
+ MDp->done = 0;
+}
+
+/* MDblock(MDp,X)
+** Update message digest buffer MDp->buffer using 16-word data block X.
+** Assumes all 16 words of X are full of data.
+** Does not update MDp->count.
+** This routine is not user-callable.
+*/
+static void
+MDblock(MDp,Xb)
+MD4_CTX *MDp;
+unsigned char *Xb;
+{
+ register unsigned int tmp, A, B, C, D;
+ unsigned int X[16];
+ int i;
+
+ for (i = 0; i < 16; ++i) {
+ X[i] = Xb[0] + (Xb[1] << 8) + (Xb[2] << 16) + (Xb[3] << 24);
+ Xb += 4;
+ }
+
+ A = MDp->buffer[0];
+ B = MDp->buffer[1];
+ C = MDp->buffer[2];
+ D = MDp->buffer[3];
+ /* Update the message digest buffer */
+ ff(A , B , C , D , 0 , fs1); /* Round 1 */
+ ff(D , A , B , C , 1 , fs2);
+ ff(C , D , A , B , 2 , fs3);
+ ff(B , C , D , A , 3 , fs4);
+ ff(A , B , C , D , 4 , fs1);
+ ff(D , A , B , C , 5 , fs2);
+ ff(C , D , A , B , 6 , fs3);
+ ff(B , C , D , A , 7 , fs4);
+ ff(A , B , C , D , 8 , fs1);
+ ff(D , A , B , C , 9 , fs2);
+ ff(C , D , A , B , 10 , fs3);
+ ff(B , C , D , A , 11 , fs4);
+ ff(A , B , C , D , 12 , fs1);
+ ff(D , A , B , C , 13 , fs2);
+ ff(C , D , A , B , 14 , fs3);
+ ff(B , C , D , A , 15 , fs4);
+ gg(A , B , C , D , 0 , gs1); /* Round 2 */
+ gg(D , A , B , C , 4 , gs2);
+ gg(C , D , A , B , 8 , gs3);
+ gg(B , C , D , A , 12 , gs4);
+ gg(A , B , C , D , 1 , gs1);
+ gg(D , A , B , C , 5 , gs2);
+ gg(C , D , A , B , 9 , gs3);
+ gg(B , C , D , A , 13 , gs4);
+ gg(A , B , C , D , 2 , gs1);
+ gg(D , A , B , C , 6 , gs2);
+ gg(C , D , A , B , 10 , gs3);
+ gg(B , C , D , A , 14 , gs4);
+ gg(A , B , C , D , 3 , gs1);
+ gg(D , A , B , C , 7 , gs2);
+ gg(C , D , A , B , 11 , gs3);
+ gg(B , C , D , A , 15 , gs4);
+ hh(A , B , C , D , 0 , hs1); /* Round 3 */
+ hh(D , A , B , C , 8 , hs2);
+ hh(C , D , A , B , 4 , hs3);
+ hh(B , C , D , A , 12 , hs4);
+ hh(A , B , C , D , 2 , hs1);
+ hh(D , A , B , C , 10 , hs2);
+ hh(C , D , A , B , 6 , hs3);
+ hh(B , C , D , A , 14 , hs4);
+ hh(A , B , C , D , 1 , hs1);
+ hh(D , A , B , C , 9 , hs2);
+ hh(C , D , A , B , 5 , hs3);
+ hh(B , C , D , A , 13 , hs4);
+ hh(A , B , C , D , 3 , hs1);
+ hh(D , A , B , C , 11 , hs2);
+ hh(C , D , A , B , 7 , hs3);
+ hh(B , C , D , A , 15 , hs4);
+ MDp->buffer[0] += A;
+ MDp->buffer[1] += B;
+ MDp->buffer[2] += C;
+ MDp->buffer[3] += D;
+}
+
+/* MD4Update(MDp,X,count)
+** Input: X -- a pointer to an array of unsigned characters.
+** count -- the number of bits of X to use.
+** (if not a multiple of 8, uses high bits of last byte.)
+** Update MDp using the number of bits of X given by count.
+** This is the basic input routine for an MD4 user.
+** The routine completes the MD computation when count < 512, so
+** every MD computation should end with one call to MD4Update with a
+** count less than 512. A call with count 0 will be ignored if the
+** MD has already been terminated (done != 0), so an extra call with
+** count 0 can be given as a "courtesy close" to force termination
+** if desired.
+*/
+void
+MD4Update(MDp,X,count)
+MD4_CTX *MDp;
+unsigned char *X;
+unsigned int count;
+{
+ unsigned int i, tmp, bit, byte, mask;
+ unsigned char XX[64];
+ unsigned char *p;
+
+ /* return with no error if this is a courtesy close with count
+ ** zero and MDp->done is true.
+ */
+ if (count == 0 && MDp->done) return;
+ /* check to see if MD is already done and report error */
+ if (MDp->done)
+ { printf("\nError: MD4Update MD already done."); return; }
+
+ /* Add count to MDp->count */
+ tmp = count;
+ p = MDp->count;
+ while (tmp)
+ { tmp += *p;
+ *p++ = tmp;
+ tmp = tmp >> 8;
+ }
+
+ /* Process data */
+ if (count == 512)
+ { /* Full block of data to handle */
+ MDblock(MDp,X);
+ }
+ else if (count > 512) /* Check for count too large */
+ {
+ printf("\nError: MD4Update called with illegal count value %d.",
+ count);
+ return;
+ }
+ else /* partial block -- must be last block so finish up */
+ {
+ /* Find out how many bytes and residual bits there are */
+ byte = count >> 3;
+ bit = count & 7;
+ /* Copy X into XX since we need to modify it */
+ for (i=0;i<=byte;i++) XX[i] = X[i];
+ for (i=byte+1;i<64;i++) XX[i] = 0;
+ /* Add padding '1' bit and low-order zeros in last byte */
+ mask = 1 << (7 - bit);
+ XX[byte] = (XX[byte] | mask) & ~( mask - 1);
+ /* If room for bit count, finish up with this block */
+ if (byte <= 55)
+ {
+ for (i=0;i<8;i++) XX[56+i] = MDp->count[i];
+ MDblock(MDp,XX);
+ }
+ else /* need to do two blocks to finish up */
+ {
+ MDblock(MDp,XX);
+ for (i=0;i<56;i++) XX[i] = 0;
+ for (i=0;i<8;i++) XX[56+i] = MDp->count[i];
+ MDblock(MDp,XX);
+ }
+ /* Set flag saying we're done with MD computation */
+ MDp->done = 1;
+ }
+}
+
+/*
+** Finish up MD4 computation and return message digest.
+*/
+void
+MD4Final(buf, MD)
+unsigned char *buf;
+MD4_CTX *MD;
+{
+ int i, j;
+ unsigned int w;
+
+ MD4Update(MD, NULL, 0);
+ for (i = 0; i < 4; ++i) {
+ w = MD->buffer[i];
+ for (j = 0; j < 4; ++j) {
+ *buf++ = w;
+ w >>= 8;
+ }
+ }
+}
+
+/*
+** End of md4.c
+****************************(cut)***********************************/
diff --git a/mdk-stage1/ppp/pppd/md4.h b/mdk-stage1/ppp/pppd/md4.h
new file mode 100644
index 000000000..80e8f9a2a
--- /dev/null
+++ b/mdk-stage1/ppp/pppd/md4.h
@@ -0,0 +1,64 @@
+
+/*
+** ********************************************************************
+** md4.h -- Header file for implementation of **
+** MD4 Message Digest Algorithm **
+** Updated: 2/13/90 by Ronald L. Rivest **
+** (C) 1990 RSA Data Security, Inc. **
+** ********************************************************************
+*/
+
+#ifndef __P
+# if defined(__STDC__) || defined(__GNUC__)
+# define __P(x) x
+# else
+# define __P(x) ()
+# endif
+#endif
+
+
+/* MDstruct is the data structure for a message digest computation.
+*/
+typedef struct {
+ unsigned int buffer[4]; /* Holds 4-word result of MD computation */
+ unsigned char count[8]; /* Number of bits processed so far */
+ unsigned int done; /* Nonzero means MD computation finished */
+} MD4_CTX;
+
+/* MD4Init(MD4_CTX *)
+** Initialize the MD4_CTX prepatory to doing a message digest
+** computation.
+*/
+extern void MD4Init __P((MD4_CTX *MD));
+
+/* MD4Update(MD,X,count)
+** Input: X -- a pointer to an array of unsigned characters.
+** count -- the number of bits of X to use (an unsigned int).
+** Updates MD using the first "count" bits of X.
+** The array pointed to by X is not modified.
+** If count is not a multiple of 8, MD4Update uses high bits of
+** last byte.
+** This is the basic input routine for a user.
+** The routine terminates the MD computation when count < 512, so
+** every MD computation should end with one call to MD4Update with a
+** count less than 512. Zero is OK for a count.
+*/
+extern void MD4Update __P((MD4_CTX *MD, unsigned char *X, unsigned int count));
+
+/* MD4Print(MD)
+** Prints message digest buffer MD as 32 hexadecimal digits.
+** Order is from low-order byte of buffer[0] to high-order byte
+** of buffer[3].
+** Each byte is printed with high-order hexadecimal digit first.
+*/
+extern void MD4Print __P((MD4_CTX *));
+
+/* MD4Final(buf, MD)
+** Returns message digest from MD and terminates the message
+** digest computation.
+*/
+extern void MD4Final __P((unsigned char *, MD4_CTX *));
+
+/*
+** End of md4.h
+****************************(cut)***********************************/
diff --git a/mdk-stage1/ppp/pppd/md5.c b/mdk-stage1/ppp/pppd/md5.c
new file mode 100644
index 000000000..0b8de3aae
--- /dev/null
+++ b/mdk-stage1/ppp/pppd/md5.c
@@ -0,0 +1,309 @@
+
+
+/*
+ ***********************************************************************
+ ** md5.c -- the source code for MD5 routines **
+ ** RSA Data Security, Inc. MD5 Message-Digest Algorithm **
+ ** Created: 2/17/90 RLR **
+ ** Revised: 1/91 SRD,AJ,BSK,JT Reference C ver., 7/10 constant corr. **
+ ***********************************************************************
+ */
+
+/*
+ ***********************************************************************
+ ** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved. **
+ ** **
+ ** License to copy and use this software is granted provided that **
+ ** it is identified as the "RSA Data Security, Inc. MD5 Message- **
+ ** Digest Algorithm" in all material mentioning or referencing this **
+ ** software or this function. **
+ ** **
+ ** License is also granted to make and use derivative works **
+ ** provided that such works are identified as "derived from the RSA **
+ ** Data Security, Inc. MD5 Message-Digest Algorithm" in all **
+ ** material mentioning or referencing the derived work. **
+ ** **
+ ** RSA Data Security, Inc. makes no representations concerning **
+ ** either the merchantability of this software or the suitability **
+ ** of this software for any particular purpose. It is provided "as **
+ ** is" without express or implied warranty of any kind. **
+ ** **
+ ** These notices must be retained in any copies of any part of this **
+ ** documentation and/or software. **
+ ***********************************************************************
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "md5.h"
+
+/*
+ ***********************************************************************
+ ** Message-digest routines: **
+ ** To form the message digest for a message M **
+ ** (1) Initialize a context buffer mdContext using MD5Init **
+ ** (2) Call MD5Update on mdContext and M **
+ ** (3) Call MD5Final on mdContext **
+ ** The message digest is now in mdContext->digest[0...15] **
+ ***********************************************************************
+ */
+
+/* forward declaration */
+static void Transform ();
+
+static unsigned char PADDING[64] = {
+ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+/* F, G, H and I are basic MD5 functions */
+#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
+#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define I(x, y, z) ((y) ^ ((x) | (~z)))
+
+/* ROTATE_LEFT rotates x left n bits */
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
+
+/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4 */
+/* Rotation is separate from addition to prevent recomputation */
+#define FF(a, b, c, d, x, s, ac) \
+ {(a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define GG(a, b, c, d, x, s, ac) \
+ {(a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define HH(a, b, c, d, x, s, ac) \
+ {(a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define II(a, b, c, d, x, s, ac) \
+ {(a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+
+#ifdef __STDC__
+#define UL(x) x##U
+#else
+#define UL(x) x
+#endif
+
+/* The routine MD5Init initializes the message-digest context
+ mdContext. All fields are set to zero.
+ */
+void MD5Init (mdContext)
+MD5_CTX *mdContext;
+{
+ mdContext->i[0] = mdContext->i[1] = (UINT4)0;
+
+ /* Load magic initialization constants.
+ */
+ mdContext->buf[0] = (UINT4)0x67452301;
+ mdContext->buf[1] = (UINT4)0xefcdab89;
+ mdContext->buf[2] = (UINT4)0x98badcfe;
+ mdContext->buf[3] = (UINT4)0x10325476;
+}
+
+/* The routine MD5Update updates the message-digest context to
+ account for the presence of each of the characters inBuf[0..inLen-1]
+ in the message whose digest is being computed.
+ */
+void MD5Update (mdContext, inBuf, inLen)
+MD5_CTX *mdContext;
+unsigned char *inBuf;
+unsigned int inLen;
+{
+ UINT4 in[16];
+ int mdi;
+ unsigned int i, ii;
+
+ /* compute number of bytes mod 64 */
+ mdi = (int)((mdContext->i[0] >> 3) & 0x3F);
+
+ /* update number of bits */
+ if ((mdContext->i[0] + ((UINT4)inLen << 3)) < mdContext->i[0])
+ mdContext->i[1]++;
+ mdContext->i[0] += ((UINT4)inLen << 3);
+ mdContext->i[1] += ((UINT4)inLen >> 29);
+
+ while (inLen--) {
+ /* add new character to buffer, increment mdi */
+ mdContext->in[mdi++] = *inBuf++;
+
+ /* transform if necessary */
+ if (mdi == 0x40) {
+ for (i = 0, ii = 0; i < 16; i++, ii += 4)
+ in[i] = (((UINT4)mdContext->in[ii+3]) << 24) |
+ (((UINT4)mdContext->in[ii+2]) << 16) |
+ (((UINT4)mdContext->in[ii+1]) << 8) |
+ ((UINT4)mdContext->in[ii]);
+ Transform (mdContext->buf, in);
+ mdi = 0;
+ }
+ }
+}
+
+/* The routine MD5Final terminates the message-digest computation and
+ ends with the desired message digest in mdContext->digest[0...15].
+ */
+void MD5Final (hash, mdContext)
+unsigned char hash[];
+MD5_CTX *mdContext;
+{
+ UINT4 in[16];
+ int mdi;
+ unsigned int i, ii;
+ unsigned int padLen;
+
+ /* save number of bits */
+ in[14] = mdContext->i[0];
+ in[15] = mdContext->i[1];
+
+ /* compute number of bytes mod 64 */
+ mdi = (int)((mdContext->i[0] >> 3) & 0x3F);
+
+ /* pad out to 56 mod 64 */
+ padLen = (mdi < 56) ? (56 - mdi) : (120 - mdi);
+ MD5Update (mdContext, PADDING, padLen);
+
+ /* append length in bits and transform */
+ for (i = 0, ii = 0; i < 14; i++, ii += 4)
+ in[i] = (((UINT4)mdContext->in[ii+3]) << 24) |
+ (((UINT4)mdContext->in[ii+2]) << 16) |
+ (((UINT4)mdContext->in[ii+1]) << 8) |
+ ((UINT4)mdContext->in[ii]);
+ Transform (mdContext->buf, in);
+
+ /* store buffer in digest */
+ for (i = 0, ii = 0; i < 4; i++, ii += 4) {
+ mdContext->digest[ii] = (unsigned char)(mdContext->buf[i] & 0xFF);
+ mdContext->digest[ii+1] =
+ (unsigned char)((mdContext->buf[i] >> 8) & 0xFF);
+ mdContext->digest[ii+2] =
+ (unsigned char)((mdContext->buf[i] >> 16) & 0xFF);
+ mdContext->digest[ii+3] =
+ (unsigned char)((mdContext->buf[i] >> 24) & 0xFF);
+ }
+ memcpy(hash, mdContext->digest, 16);
+}
+
+/* Basic MD5 step. Transforms buf based on in.
+ */
+static void Transform (buf, in)
+UINT4 *buf;
+UINT4 *in;
+{
+ UINT4 a = buf[0], b = buf[1], c = buf[2], d = buf[3];
+
+ /* Round 1 */
+#define S11 7
+#define S12 12
+#define S13 17
+#define S14 22
+ FF ( a, b, c, d, in[ 0], S11, UL(3614090360)); /* 1 */
+ FF ( d, a, b, c, in[ 1], S12, UL(3905402710)); /* 2 */
+ FF ( c, d, a, b, in[ 2], S13, UL( 606105819)); /* 3 */
+ FF ( b, c, d, a, in[ 3], S14, UL(3250441966)); /* 4 */
+ FF ( a, b, c, d, in[ 4], S11, UL(4118548399)); /* 5 */
+ FF ( d, a, b, c, in[ 5], S12, UL(1200080426)); /* 6 */
+ FF ( c, d, a, b, in[ 6], S13, UL(2821735955)); /* 7 */
+ FF ( b, c, d, a, in[ 7], S14, UL(4249261313)); /* 8 */
+ FF ( a, b, c, d, in[ 8], S11, UL(1770035416)); /* 9 */
+ FF ( d, a, b, c, in[ 9], S12, UL(2336552879)); /* 10 */
+ FF ( c, d, a, b, in[10], S13, UL(4294925233)); /* 11 */
+ FF ( b, c, d, a, in[11], S14, UL(2304563134)); /* 12 */
+ FF ( a, b, c, d, in[12], S11, UL(1804603682)); /* 13 */
+ FF ( d, a, b, c, in[13], S12, UL(4254626195)); /* 14 */
+ FF ( c, d, a, b, in[14], S13, UL(2792965006)); /* 15 */
+ FF ( b, c, d, a, in[15], S14, UL(1236535329)); /* 16 */
+
+ /* Round 2 */
+#define S21 5
+#define S22 9
+#define S23 14
+#define S24 20
+ GG ( a, b, c, d, in[ 1], S21, UL(4129170786)); /* 17 */
+ GG ( d, a, b, c, in[ 6], S22, UL(3225465664)); /* 18 */
+ GG ( c, d, a, b, in[11], S23, UL( 643717713)); /* 19 */
+ GG ( b, c, d, a, in[ 0], S24, UL(3921069994)); /* 20 */
+ GG ( a, b, c, d, in[ 5], S21, UL(3593408605)); /* 21 */
+ GG ( d, a, b, c, in[10], S22, UL( 38016083)); /* 22 */
+ GG ( c, d, a, b, in[15], S23, UL(3634488961)); /* 23 */
+ GG ( b, c, d, a, in[ 4], S24, UL(3889429448)); /* 24 */
+ GG ( a, b, c, d, in[ 9], S21, UL( 568446438)); /* 25 */
+ GG ( d, a, b, c, in[14], S22, UL(3275163606)); /* 26 */
+ GG ( c, d, a, b, in[ 3], S23, UL(4107603335)); /* 27 */
+ GG ( b, c, d, a, in[ 8], S24, UL(1163531501)); /* 28 */
+ GG ( a, b, c, d, in[13], S21, UL(2850285829)); /* 29 */
+ GG ( d, a, b, c, in[ 2], S22, UL(4243563512)); /* 30 */
+ GG ( c, d, a, b, in[ 7], S23, UL(1735328473)); /* 31 */
+ GG ( b, c, d, a, in[12], S24, UL(2368359562)); /* 32 */
+
+ /* Round 3 */
+#define S31 4
+#define S32 11
+#define S33 16
+#define S34 23
+ HH ( a, b, c, d, in[ 5], S31, UL(4294588738)); /* 33 */
+ HH ( d, a, b, c, in[ 8], S32, UL(2272392833)); /* 34 */
+ HH ( c, d, a, b, in[11], S33, UL(1839030562)); /* 35 */
+ HH ( b, c, d, a, in[14], S34, UL(4259657740)); /* 36 */
+ HH ( a, b, c, d, in[ 1], S31, UL(2763975236)); /* 37 */
+ HH ( d, a, b, c, in[ 4], S32, UL(1272893353)); /* 38 */
+ HH ( c, d, a, b, in[ 7], S33, UL(4139469664)); /* 39 */
+ HH ( b, c, d, a, in[10], S34, UL(3200236656)); /* 40 */
+ HH ( a, b, c, d, in[13], S31, UL( 681279174)); /* 41 */
+ HH ( d, a, b, c, in[ 0], S32, UL(3936430074)); /* 42 */
+ HH ( c, d, a, b, in[ 3], S33, UL(3572445317)); /* 43 */
+ HH ( b, c, d, a, in[ 6], S34, UL( 76029189)); /* 44 */
+ HH ( a, b, c, d, in[ 9], S31, UL(3654602809)); /* 45 */
+ HH ( d, a, b, c, in[12], S32, UL(3873151461)); /* 46 */
+ HH ( c, d, a, b, in[15], S33, UL( 530742520)); /* 47 */
+ HH ( b, c, d, a, in[ 2], S34, UL(3299628645)); /* 48 */
+
+ /* Round 4 */
+#define S41 6
+#define S42 10
+#define S43 15
+#define S44 21
+ II ( a, b, c, d, in[ 0], S41, UL(4096336452)); /* 49 */
+ II ( d, a, b, c, in[ 7], S42, UL(1126891415)); /* 50 */
+ II ( c, d, a, b, in[14], S43, UL(2878612391)); /* 51 */
+ II ( b, c, d, a, in[ 5], S44, UL(4237533241)); /* 52 */
+ II ( a, b, c, d, in[12], S41, UL(1700485571)); /* 53 */
+ II ( d, a, b, c, in[ 3], S42, UL(2399980690)); /* 54 */
+ II ( c, d, a, b, in[10], S43, UL(4293915773)); /* 55 */
+ II ( b, c, d, a, in[ 1], S44, UL(2240044497)); /* 56 */
+ II ( a, b, c, d, in[ 8], S41, UL(1873313359)); /* 57 */
+ II ( d, a, b, c, in[15], S42, UL(4264355552)); /* 58 */
+ II ( c, d, a, b, in[ 6], S43, UL(2734768916)); /* 59 */
+ II ( b, c, d, a, in[13], S44, UL(1309151649)); /* 60 */
+ II ( a, b, c, d, in[ 4], S41, UL(4149444226)); /* 61 */
+ II ( d, a, b, c, in[11], S42, UL(3174756917)); /* 62 */
+ II ( c, d, a, b, in[ 2], S43, UL( 718787259)); /* 63 */
+ II ( b, c, d, a, in[ 9], S44, UL(3951481745)); /* 64 */
+
+ buf[0] += a;
+ buf[1] += b;
+ buf[2] += c;
+ buf[3] += d;
+}
+
+/*
+ ***********************************************************************
+ ** End of md5.c **
+ ******************************** (cut) ********************************
+ */
diff --git a/mdk-stage1/ppp/pppd/md5.h b/mdk-stage1/ppp/pppd/md5.h
new file mode 100644
index 000000000..7492b2228
--- /dev/null
+++ b/mdk-stage1/ppp/pppd/md5.h
@@ -0,0 +1,58 @@
+/*
+ ***********************************************************************
+ ** md5.h -- header file for implementation of MD5 **
+ ** RSA Data Security, Inc. MD5 Message-Digest Algorithm **
+ ** Created: 2/17/90 RLR **
+ ** Revised: 12/27/90 SRD,AJ,BSK,JT Reference C version **
+ ** Revised (for MD5): RLR 4/27/91 **
+ ** -- G modified to have y&~z instead of y&z **
+ ** -- FF, GG, HH modified to add in last register done **
+ ** -- Access pattern: round 2 works mod 5, round 3 works mod 3 **
+ ** -- distinct additive constant for each step **
+ ** -- round 4 added, working mod 7 **
+ ***********************************************************************
+ */
+
+/*
+ ***********************************************************************
+ ** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved. **
+ ** **
+ ** License to copy and use this software is granted provided that **
+ ** it is identified as the "RSA Data Security, Inc. MD5 Message- **
+ ** Digest Algorithm" in all material mentioning or referencing this **
+ ** software or this function. **
+ ** **
+ ** License is also granted to make and use derivative works **
+ ** provided that such works are identified as "derived from the RSA **
+ ** Data Security, Inc. MD5 Message-Digest Algorithm" in all **
+ ** material mentioning or referencing the derived work. **
+ ** **
+ ** RSA Data Security, Inc. makes no representations concerning **
+ ** either the merchantability of this software or the suitability **
+ ** of this software for any particular purpose. It is provided "as **
+ ** is" without express or implied warranty of any kind. **
+ ** **
+ ** These notices must be retained in any copies of any part of this **
+ ** documentation and/or software. **
+ ***********************************************************************
+ */
+
+#ifndef __MD5_INCLUDE__
+
+/* typedef a 32-bit type */
+typedef unsigned int UINT4;
+
+/* Data structure for MD5 (Message-Digest) computation */
+typedef struct {
+ UINT4 i[2]; /* number of _bits_ handled mod 2^64 */
+ UINT4 buf[4]; /* scratch buffer */
+ unsigned char in[64]; /* input buffer */
+ unsigned char digest[16]; /* actual digest after MD5Final call */
+} MD5_CTX;
+
+void MD5Init ();
+void MD5Update ();
+void MD5Final ();
+
+#define __MD5_INCLUDE__
+#endif /* __MD5_INCLUDE__ */
diff --git a/mdk-stage1/ppp/pppd/multilink.c b/mdk-stage1/ppp/pppd/multilink.c
new file mode 100644
index 000000000..c30b07e0a
--- /dev/null
+++ b/mdk-stage1/ppp/pppd/multilink.c
@@ -0,0 +1,397 @@
+/*
+ * multilink.c - support routines for multilink.
+ *
+ * Copyright (c) 2000 Paul Mackerras.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms. The name of the author may not be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <ctype.h>
+#include <netdb.h>
+#include <errno.h>
+#include <signal.h>
+#include <netinet/in.h>
+
+#include "pppd.h"
+#include "fsm.h"
+#include "lcp.h"
+#include "tdb.h"
+
+bool endpoint_specified; /* user gave explicit endpoint discriminator */
+char *bundle_id; /* identifier for our bundle */
+
+extern TDB_CONTEXT *pppdb;
+extern char db_key[];
+
+static int get_default_epdisc __P((struct epdisc *));
+static int parse_num __P((char *str, const char *key, int *valp));
+static int owns_unit __P((TDB_DATA pid, int unit));
+
+#define set_ip_epdisc(ep, addr) do { \
+ ep->length = 4; \
+ ep->value[0] = addr >> 24; \
+ ep->value[1] = addr >> 16; \
+ ep->value[2] = addr >> 8; \
+ ep->value[3] = addr; \
+} while (0)
+
+#define LOCAL_IP_ADDR(addr) \
+ (((addr) & 0xff000000) == 0x0a000000 /* 10.x.x.x */ \
+ || ((addr) & 0xfff00000) == 0xac100000 /* 172.16.x.x */ \
+ || ((addr) & 0xffff0000) == 0xc0a80000) /* 192.168.x.x */
+
+#define process_exists(n) (kill((n), 0) == 0 || errno != ESRCH)
+
+void
+mp_check_options()
+{
+ lcp_options *wo = &lcp_wantoptions[0];
+ lcp_options *ao = &lcp_allowoptions[0];
+
+ if (!multilink)
+ return;
+ /* if we're doing multilink, we have to negotiate MRRU */
+ if (!wo->neg_mrru) {
+ /* mrru not specified, default to mru */
+ wo->mrru = wo->mru;
+ wo->neg_mrru = 1;
+ }
+ ao->mrru = ao->mru;
+ ao->neg_mrru = 1;
+
+ if (!wo->neg_endpoint && !noendpoint) {
+ /* get a default endpoint value */
+ wo->neg_endpoint = get_default_epdisc(&wo->endpoint);
+ }
+}
+
+/*
+ * Make a new bundle or join us to an existing bundle
+ * if we are doing multilink.
+ */
+int
+mp_join_bundle()
+{
+ lcp_options *go = &lcp_gotoptions[0];
+ lcp_options *ho = &lcp_hisoptions[0];
+ lcp_options *ao = &lcp_allowoptions[0];
+ int unit, pppd_pid;
+ int l, mtu;
+ char *p;
+ TDB_DATA key, pid, rec;
+
+ if (!go->neg_mrru || !ho->neg_mrru) {
+ /* not doing multilink */
+ if (go->neg_mrru)
+ notice("oops, multilink negotiated only for receive");
+ mtu = ho->neg_mru? ho->mru: PPP_MRU;
+ if (mtu > ao->mru)
+ mtu = ao->mru;
+ if (demand) {
+ /* already have a bundle */
+ cfg_bundle(0, 0, 0, 0);
+ netif_set_mtu(0, mtu);
+ return 0;
+ }
+ make_new_bundle(0, 0, 0, 0);
+ set_ifunit(1);
+ netif_set_mtu(0, mtu);
+ return 0;
+ }
+
+ /*
+ * Find the appropriate bundle or join a new one.
+ * First we make up a name for the bundle.
+ * The length estimate is worst-case assuming every
+ * character has to be quoted.
+ */
+ l = 4 * strlen(peer_authname) + 10;
+ if (ho->neg_endpoint)
+ l += 3 * ho->endpoint.length + 8;
+ if (bundle_name)
+ l += 3 * strlen(bundle_name) + 2;
+ bundle_id = malloc(l);
+ if (bundle_id == 0)
+ novm("bundle identifier");
+
+ p = bundle_id;
+ p += slprintf(p, l-1, "BUNDLE=\"%q\"", peer_authname);
+ if (ho->neg_endpoint || bundle_name)
+ *p++ = '/';
+ if (ho->neg_endpoint)
+ p += slprintf(p, bundle_id+l-p, "%s",
+ epdisc_to_str(&ho->endpoint));
+ if (bundle_name)
+ p += slprintf(p, bundle_id+l-p, "/%v", bundle_name);
+
+ /*
+ * For demand mode, we only need to configure the bundle
+ * and attach the link.
+ */
+ mtu = MIN(ho->mrru, ao->mru);
+ if (demand) {
+ cfg_bundle(go->mrru, ho->mrru, go->neg_ssnhf, ho->neg_ssnhf);
+ netif_set_mtu(0, mtu);
+ script_setenv("BUNDLE", bundle_id + 7, 1);
+ return 0;
+ }
+
+ /*
+ * Check if the bundle ID is already in the database.
+ */
+ unit = -1;
+ tdb_writelock(pppdb);
+ key.dptr = bundle_id;
+ key.dsize = p - bundle_id;
+ pid = tdb_fetch(pppdb, key);
+ if (pid.dptr != NULL) {
+ /* bundle ID exists, see if the pppd record exists */
+ rec = tdb_fetch(pppdb, pid);
+ if (rec.dptr != NULL) {
+ /* it is, parse the interface number */
+ parse_num(rec.dptr, "IFNAME=ppp", &unit);
+ /* check the pid value */
+ if (!parse_num(rec.dptr, "PPPD_PID=", &pppd_pid)
+ || !process_exists(pppd_pid)
+ || !owns_unit(pid, unit))
+ unit = -1;
+ free(rec.dptr);
+ }
+ free(pid.dptr);
+ }
+
+ if (unit >= 0) {
+ /* attach to existing unit */
+ if (bundle_attach(unit)) {
+ set_ifunit(0);
+ script_setenv("BUNDLE", bundle_id + 7, 0);
+ tdb_writeunlock(pppdb);
+ info("Link attached to %s", ifname);
+ return 1;
+ }
+ /* attach failed because bundle doesn't exist */
+ }
+
+ /* we have to make a new bundle */
+ make_new_bundle(go->mrru, ho->mrru, go->neg_ssnhf, ho->neg_ssnhf);
+ set_ifunit(1);
+ netif_set_mtu(0, mtu);
+ script_setenv("BUNDLE", bundle_id + 7, 1);
+ tdb_writeunlock(pppdb);
+ info("New bundle %s created", ifname);
+ return 0;
+}
+
+static int
+parse_num(str, key, valp)
+ char *str;
+ const char *key;
+ int *valp;
+{
+ char *p, *endp;
+ int i;
+
+ p = strstr(str, key);
+ if (p != 0) {
+ p += strlen(key);
+ i = strtol(p, &endp, 10);
+ if (endp != p && (*endp == 0 || *endp == ';')) {
+ *valp = i;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/*
+ * Check whether the pppd identified by `key' still owns ppp unit `unit'.
+ */
+static int
+owns_unit(key, unit)
+ TDB_DATA key;
+ int unit;
+{
+ char ifkey[32];
+ TDB_DATA kd, vd;
+ int ret = 0;
+
+ slprintf(ifkey, sizeof(ifkey), "IFNAME=ppp%d", unit);
+ kd.dptr = ifkey;
+ kd.dsize = strlen(ifkey);
+ vd = tdb_fetch(pppdb, kd);
+ if (vd.dptr != NULL) {
+ ret = vd.dsize == key.dsize
+ && memcmp(vd.dptr, key.dptr, vd.dsize) == 0;
+ free(vd.dptr);
+ }
+ return ret;
+}
+
+static int
+get_default_epdisc(ep)
+ struct epdisc *ep;
+{
+ char *p;
+ struct hostent *hp;
+ u_int32_t addr;
+
+ /* First try for an ethernet MAC address */
+ p = get_first_ethernet();
+ if (p != 0 && get_if_hwaddr(ep->value, p) >= 0) {
+ ep->class = EPD_MAC;
+ ep->length = 6;
+ return 1;
+ }
+
+ /* see if our hostname corresponds to a reasonable IP address */
+ hp = gethostbyname(hostname);
+ if (hp != NULL) {
+ addr = *(u_int32_t *)hp->h_addr;
+ if (!bad_ip_adrs(addr)) {
+ addr = ntohl(addr);
+ if (!LOCAL_IP_ADDR(addr)) {
+ ep->class = EPD_IP;
+ set_ip_epdisc(ep, addr);
+ return 1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * epdisc_to_str - make a printable string from an endpoint discriminator.
+ */
+
+static char *endp_class_names[] = {
+ "null", "local", "IP", "MAC", "magic", "phone"
+};
+
+char *
+epdisc_to_str(ep)
+ struct epdisc *ep;
+{
+ static char str[MAX_ENDP_LEN*3+8];
+ u_char *p = ep->value;
+ int i, mask = 0;
+ char *q, c, c2;
+
+ if (ep->class == EPD_NULL && ep->length == 0)
+ return "null";
+ if (ep->class == EPD_IP && ep->length == 4) {
+ u_int32_t addr;
+
+ GETLONG(addr, p);
+ slprintf(str, sizeof(str), "IP:%I", htonl(addr));
+ return str;
+ }
+
+ c = ':';
+ c2 = '.';
+ if (ep->class == EPD_MAC && ep->length == 6)
+ c2 = ':';
+ else if (ep->class == EPD_MAGIC && (ep->length % 4) == 0)
+ mask = 3;
+ q = str;
+ if (ep->class <= EPD_PHONENUM)
+ q += slprintf(q, sizeof(str)-1, "%s",
+ endp_class_names[ep->class]);
+ else
+ q += slprintf(q, sizeof(str)-1, "%d", ep->class);
+ c = ':';
+ for (i = 0; i < ep->length && i < MAX_ENDP_LEN; ++i) {
+ if ((i & mask) == 0) {
+ *q++ = c;
+ c = c2;
+ }
+ q += slprintf(q, str + sizeof(str) - q, "%.2x", ep->value[i]);
+ }
+ return str;
+}
+
+static int hexc_val(int c)
+{
+ if (c >= 'a')
+ return c - 'a' + 10;
+ if (c >= 'A')
+ return c - 'A' + 10;
+ return c - '0';
+}
+
+int
+str_to_epdisc(ep, str)
+ struct epdisc *ep;
+ char *str;
+{
+ int i, l;
+ char *p, *endp;
+
+ for (i = EPD_NULL; i <= EPD_PHONENUM; ++i) {
+ int sl = strlen(endp_class_names[i]);
+ if (strncasecmp(str, endp_class_names[i], sl) == 0) {
+ str += sl;
+ break;
+ }
+ }
+ if (i > EPD_PHONENUM) {
+ /* not a class name, try a decimal class number */
+ i = strtol(str, &endp, 10);
+ if (endp == str)
+ return 0; /* can't parse class number */
+ str = endp;
+ }
+ ep->class = i;
+ if (*str == 0) {
+ ep->length = 0;
+ return 1;
+ }
+ if (*str != ':' && *str != '.')
+ return 0;
+ ++str;
+
+ if (i == EPD_IP) {
+ u_int32_t addr;
+ i = parse_dotted_ip(str, &addr);
+ if (i == 0 || str[i] != 0)
+ return 0;
+ set_ip_epdisc(ep, addr);
+ return 1;
+ }
+ if (i == EPD_MAC && get_if_hwaddr(ep->value, str) >= 0) {
+ ep->length = 6;
+ return 1;
+ }
+
+ p = str;
+ for (l = 0; l < MAX_ENDP_LEN; ++l) {
+ if (*str == 0)
+ break;
+ if (p <= str)
+ for (p = str; isxdigit(*p); ++p)
+ ;
+ i = p - str;
+ if (i == 0)
+ return 0;
+ ep->value[l] = hexc_val(*str++);
+ if ((i & 1) == 0)
+ ep->value[l] = (ep->value[l] << 4) + hexc_val(*str++);
+ if (*str == ':' || *str == '.')
+ ++str;
+ }
+ if (*str != 0 || (ep->class == EPD_MAC && l != 6))
+ return 0;
+ ep->length = l;
+ return 1;
+}
+
diff --git a/mdk-stage1/ppp/pppd/options.c b/mdk-stage1/ppp/pppd/options.c
new file mode 100644
index 000000000..018dbd006
--- /dev/null
+++ b/mdk-stage1/ppp/pppd/options.c
@@ -0,0 +1,1513 @@
+/*
+ * options.c - handles option processing for PPP.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#define RCSID "$Id: options.c 195734 2001-06-11 14:46:02Z gc $"
+
+#include <ctype.h>
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <syslog.h>
+#include <string.h>
+#include <pwd.h>
+#ifdef PLUGIN
+#include <dlfcn.h>
+#endif
+#ifdef PPP_FILTER
+#include <pcap.h>
+#include <pcap-int.h> /* XXX: To get struct pcap */
+#endif
+
+#include "pppd.h"
+#include "pathnames.h"
+
+#if defined(ultrix) || defined(NeXT)
+char *strdup __P((char *));
+#endif
+
+static const char rcsid[] = RCSID;
+
+struct option_value {
+ struct option_value *next;
+ const char *source;
+ char value[1];
+};
+
+/*
+ * Option variables and default values.
+ */
+#ifdef PPP_FILTER
+int dflag = 0; /* Tell libpcap we want debugging */
+#endif
+int debug = 0; /* Debug flag */
+int kdebugflag = 0; /* Tell kernel to print debug messages */
+int default_device = 1; /* Using /dev/tty or equivalent */
+char devnam[MAXPATHLEN]; /* Device name */
+bool nodetach = 0; /* Don't detach from controlling tty */
+bool updetach = 0; /* Detach once link is up */
+int maxconnect = 0; /* Maximum connect time */
+char user[MAXNAMELEN]; /* Username for PAP */
+char passwd[MAXSECRETLEN]; /* Password for PAP */
+bool persist = 0; /* Reopen link after it goes down */
+char our_name[MAXNAMELEN]; /* Our name for authentication purposes */
+bool demand = 0; /* do dial-on-demand */
+char *ipparam = NULL; /* Extra parameter for ip up/down scripts */
+int idle_time_limit = 0; /* Disconnect if idle for this many seconds */
+int holdoff = 30; /* # seconds to pause before reconnecting */
+bool holdoff_specified; /* true if a holdoff value has been given */
+int log_to_fd = 1; /* send log messages to this fd too */
+bool log_default = 1; /* log_to_fd is default (stdout) */
+int maxfail = 10; /* max # of unsuccessful connection attempts */
+char linkname[MAXPATHLEN]; /* logical name for link */
+bool tune_kernel; /* may alter kernel settings */
+int connect_delay = 1000; /* wait this many ms after connect script */
+int req_unit = -1; /* requested interface unit */
+bool multilink = 0; /* Enable multilink operation */
+char *bundle_name = NULL; /* bundle name for multilink */
+bool dump_options; /* print out option values */
+bool dryrun; /* print out option values and exit */
+char *domain; /* domain name set by domain option */
+
+extern option_t auth_options[];
+extern struct stat devstat;
+
+#ifdef PPP_FILTER
+struct bpf_program pass_filter;/* Filter program for packets to pass */
+struct bpf_program active_filter; /* Filter program for link-active pkts */
+pcap_t pc; /* Fake struct pcap so we can compile expr */
+#endif
+
+char *current_option; /* the name of the option being parsed */
+int privileged_option; /* set iff the current option came from root */
+char *option_source; /* string saying where the option came from */
+int option_priority = OPRIO_CFGFILE; /* priority of the current options */
+bool devnam_fixed; /* can no longer change device name */
+
+static int logfile_fd = -1; /* fd opened for log file */
+static char logfile_name[MAXPATHLEN]; /* name of log file */
+
+/*
+ * Prototypes
+ */
+static int setdomain __P((char **));
+static int readfile __P((char **));
+static int callfile __P((char **));
+static int showversion __P((char **));
+static int showhelp __P((char **));
+static void usage __P((void));
+static int setlogfile __P((char **));
+#ifdef PLUGIN
+static int loadplugin __P((char **));
+#endif
+
+#ifdef PPP_FILTER
+static int setpassfilter __P((char **));
+static int setactivefilter __P((char **));
+#endif
+
+static option_t *find_option __P((const char *name));
+static int process_option __P((option_t *, char *, char **));
+static int n_arguments __P((option_t *));
+static int number_option __P((char *, u_int32_t *, int));
+
+/*
+ * Structure to store extra lists of options.
+ */
+struct option_list {
+ option_t *options;
+ struct option_list *next;
+};
+
+static struct option_list *extra_options = NULL;
+
+/*
+ * Valid arguments.
+ */
+option_t general_options[] = {
+ { "debug", o_int, &debug,
+ "Increase debugging level", OPT_INC | OPT_NOARG | 1 },
+ { "-d", o_int, &debug,
+ "Increase debugging level",
+ OPT_ALIAS | OPT_INC | OPT_NOARG | 1 },
+
+ { "kdebug", o_int, &kdebugflag,
+ "Set kernel driver debug level", OPT_PRIO },
+
+ { "nodetach", o_bool, &nodetach,
+ "Don't detach from controlling tty", OPT_PRIO | 1 },
+ { "-detach", o_bool, &nodetach,
+ "Don't detach from controlling tty", OPT_ALIAS | OPT_PRIOSUB | 1 },
+ { "updetach", o_bool, &updetach,
+ "Detach from controlling tty once link is up",
+ OPT_PRIOSUB | OPT_A2CLR | 1, &nodetach },
+
+ { "holdoff", o_int, &holdoff,
+ "Set time in seconds before retrying connection", OPT_PRIO },
+
+ { "idle", o_int, &idle_time_limit,
+ "Set time in seconds before disconnecting idle link", OPT_PRIO },
+
+ { "maxconnect", o_int, &maxconnect,
+ "Set connection time limit",
+ OPT_PRIO | OPT_LLIMIT | OPT_NOINCR | OPT_ZEROINF },
+
+ { "domain", o_special, (void *)setdomain,
+ "Add given domain name to hostname",
+ OPT_PRIO | OPT_PRIV | OPT_A2STRVAL, &domain },
+
+ { "file", o_special, (void *)readfile,
+ "Take options from a file", OPT_NOPRINT },
+ { "call", o_special, (void *)callfile,
+ "Take options from a privileged file", OPT_NOPRINT },
+
+ { "persist", o_bool, &persist,
+ "Keep on reopening connection after close", OPT_PRIO | 1 },
+ { "nopersist", o_bool, &persist,
+ "Turn off persist option", OPT_PRIOSUB },
+
+ { "demand", o_bool, &demand,
+ "Dial on demand", OPT_INITONLY | 1, &persist },
+
+ { "--version", o_special_noarg, (void *)showversion,
+ "Show version number" },
+ { "--help", o_special_noarg, (void *)showhelp,
+ "Show brief listing of options" },
+ { "-h", o_special_noarg, (void *)showhelp,
+ "Show brief listing of options", OPT_ALIAS },
+
+ { "logfile", o_special, (void *)setlogfile,
+ "Append log messages to this file",
+ OPT_PRIO | OPT_A2STRVAL | OPT_STATIC, &logfile_name },
+ { "logfd", o_int, &log_to_fd,
+ "Send log messages to this file descriptor",
+ OPT_PRIOSUB | OPT_A2CLR, &log_default },
+ { "nolog", o_int, &log_to_fd,
+ "Don't send log messages to any file",
+ OPT_PRIOSUB | OPT_NOARG | OPT_VAL(-1) },
+ { "nologfd", o_int, &log_to_fd,
+ "Don't send log messages to any file descriptor",
+ OPT_PRIOSUB | OPT_ALIAS | OPT_NOARG | OPT_VAL(-1) },
+
+ { "linkname", o_string, linkname,
+ "Set logical name for link",
+ OPT_PRIO | OPT_PRIV | OPT_STATIC, NULL, MAXPATHLEN },
+
+ { "maxfail", o_int, &maxfail,
+ "Maximum number of unsuccessful connection attempts to allow",
+ OPT_PRIO },
+
+ { "ktune", o_bool, &tune_kernel,
+ "Alter kernel settings as necessary", OPT_PRIO | 1 },
+ { "noktune", o_bool, &tune_kernel,
+ "Don't alter kernel settings", OPT_PRIOSUB },
+
+ { "connect-delay", o_int, &connect_delay,
+ "Maximum time (in ms) to wait after connect script finishes",
+ OPT_PRIO },
+
+ { "unit", o_int, &req_unit,
+ "PPP interface unit number to use if possible",
+ OPT_PRIO | OPT_LLIMIT, 0, 0 },
+
+ { "dump", o_bool, &dump_options,
+ "Print out option values after parsing all options", 1 },
+ { "dryrun", o_bool, &dryrun,
+ "Stop after parsing, printing, and checking options", 1 },
+
+#ifdef HAVE_MULTILINK
+ { "multilink", o_bool, &multilink,
+ "Enable multilink operation", OPT_PRIO | 1 },
+ { "mp", o_bool, &multilink,
+ "Enable multilink operation", OPT_PRIOSUB | OPT_ALIAS | 1 },
+ { "nomultilink", o_bool, &multilink,
+ "Disable multilink operation", OPT_PRIOSUB | 0 },
+ { "nomp", o_bool, &multilink,
+ "Disable multilink operation", OPT_PRIOSUB | OPT_ALIAS | 0 },
+
+ { "bundle", o_string, &bundle_name,
+ "Bundle name for multilink", OPT_PRIO },
+#endif /* HAVE_MULTILINK */
+
+#ifdef PLUGIN
+ { "plugin", o_special, (void *)loadplugin,
+ "Load a plug-in module into pppd", OPT_PRIV | OPT_A2LIST },
+#endif
+
+#ifdef PPP_FILTER
+ { "pdebug", o_int, &dflag,
+ "libpcap debugging", OPT_PRIO },
+
+ { "pass-filter", 1, setpassfilter,
+ "set filter for packets to pass", OPT_PRIO },
+
+ { "active-filter", 1, setactivefilter,
+ "set filter for active pkts", OPT_PRIO },
+#endif
+
+ { NULL }
+};
+
+#ifndef IMPLEMENTATION
+#define IMPLEMENTATION ""
+#endif
+
+static char *usage_string = "\
+pppd version %s\n\
+Usage: %s [ options ], where options are:\n\
+ <device> Communicate over the named device\n\
+ <speed> Set the baud rate to <speed>\n\
+ <loc>:<rem> Set the local and/or remote interface IP\n\
+ addresses. Either one may be omitted.\n\
+ asyncmap <n> Set the desired async map to hex <n>\n\
+ auth Require authentication from peer\n\
+ connect <p> Invoke shell command <p> to set up the serial line\n\
+ crtscts Use hardware RTS/CTS flow control\n\
+ defaultroute Add default route through interface\n\
+ file <f> Take options from file <f>\n\
+ modem Use modem control lines\n\
+ mru <n> Set MRU value to <n> for negotiation\n\
+See pppd(8) for more options.\n\
+";
+
+/*
+ * parse_args - parse a string of arguments from the command line.
+ */
+int
+parse_args(argc, argv)
+ int argc;
+ char **argv;
+{
+ char *arg;
+ option_t *opt;
+ int n;
+
+ privileged_option = privileged;
+ option_source = "command line";
+ option_priority = OPRIO_CMDLINE;
+ while (argc > 0) {
+ arg = *argv++;
+ --argc;
+ opt = find_option(arg);
+ if (opt == NULL) {
+ option_error("unrecognized option '%s'", arg);
+ usage();
+ return 0;
+ }
+ n = n_arguments(opt);
+ if (argc < n) {
+ option_error("too few parameters for option %s", arg);
+ return 0;
+ }
+ if (!process_option(opt, arg, argv))
+ return 0;
+ argc -= n;
+ argv += n;
+ }
+ return 1;
+}
+
+/*
+ * options_from_file - Read a string of options from a file,
+ * and interpret them.
+ */
+int
+options_from_file(filename, must_exist, check_prot, priv)
+ char *filename;
+ int must_exist;
+ int check_prot;
+ int priv;
+{
+ FILE *f;
+ int i, newline, ret, err;
+ option_t *opt;
+ int oldpriv, n;
+ char *oldsource;
+ char *argv[MAXARGS];
+ char args[MAXARGS][MAXWORDLEN];
+ char cmd[MAXWORDLEN];
+
+ if (check_prot)
+ seteuid(getuid());
+ f = fopen(filename, "r");
+ err = errno;
+ if (check_prot)
+ seteuid(0);
+ if (f == NULL) {
+ errno = err;
+ if (!must_exist) {
+ if (err != ENOENT && err != ENOTDIR)
+ warn("Warning: can't open options file %s: %m", filename);
+ return 1;
+ }
+ option_error("Can't open options file %s: %m", filename);
+ return 0;
+ }
+
+ oldpriv = privileged_option;
+ privileged_option = priv;
+ oldsource = option_source;
+ option_source = strdup(filename);
+ if (option_source == NULL)
+ option_source = "file";
+ ret = 0;
+ while (getword(f, cmd, &newline, filename)) {
+ opt = find_option(cmd);
+ if (opt == NULL) {
+ option_error("In file %s: unrecognized option '%s'",
+ filename, cmd);
+ goto err;
+ }
+ n = n_arguments(opt);
+ for (i = 0; i < n; ++i) {
+ if (!getword(f, args[i], &newline, filename)) {
+ option_error(
+ "In file %s: too few parameters for option '%s'",
+ filename, cmd);
+ goto err;
+ }
+ argv[i] = args[i];
+ }
+ if (!process_option(opt, cmd, argv))
+ goto err;
+ }
+ ret = 1;
+
+err:
+ fclose(f);
+ privileged_option = oldpriv;
+ option_source = oldsource;
+ return ret;
+}
+
+/*
+ * options_from_user - See if the use has a ~/.ppprc file,
+ * and if so, interpret options from it.
+ */
+int
+options_from_user()
+{
+ char *user, *path, *file;
+ int ret;
+ struct passwd *pw;
+ size_t pl;
+
+ pw = getpwuid(getuid());
+ if (pw == NULL || (user = pw->pw_dir) == NULL || user[0] == 0)
+ return 1;
+ file = _PATH_USEROPT;
+ pl = strlen(user) + strlen(file) + 2;
+ path = malloc(pl);
+ if (path == NULL)
+ novm("init file name");
+ slprintf(path, pl, "%s/%s", user, file);
+ option_priority = OPRIO_CFGFILE;
+ ret = options_from_file(path, 0, 1, privileged);
+ free(path);
+ return ret;
+}
+
+/*
+ * options_for_tty - See if an options file exists for the serial
+ * device, and if so, interpret options from it.
+ * We only allow the per-tty options file to override anything from
+ * the command line if it is something that the user can't override
+ * once it has been set by root; this is done by giving configuration
+ * files a lower priority than the command line.
+ */
+int
+options_for_tty()
+{
+ char *dev, *path, *p;
+ int ret;
+ size_t pl;
+
+ dev = devnam;
+ if (strncmp(dev, "/dev/", 5) == 0)
+ dev += 5;
+ if (dev[0] == 0 || strcmp(dev, "tty") == 0)
+ return 1; /* don't look for /etc/ppp/options.tty */
+ pl = strlen(_PATH_TTYOPT) + strlen(dev) + 1;
+ path = malloc(pl);
+ if (path == NULL)
+ novm("tty init file name");
+ slprintf(path, pl, "%s%s", _PATH_TTYOPT, dev);
+ /* Turn slashes into dots, for Solaris case (e.g. /dev/term/a) */
+ for (p = path + strlen(_PATH_TTYOPT); *p != 0; ++p)
+ if (*p == '/')
+ *p = '.';
+ option_priority = OPRIO_CFGFILE;
+ ret = options_from_file(path, 0, 0, 1);
+ free(path);
+ return ret;
+}
+
+/*
+ * options_from_list - process a string of options in a wordlist.
+ */
+int
+options_from_list(w, priv)
+ struct wordlist *w;
+ int priv;
+{
+ char *argv[MAXARGS];
+ option_t *opt;
+ int i, n, ret = 0;
+ struct wordlist *w0;
+
+ privileged_option = priv;
+ option_source = "secrets file";
+ option_priority = OPRIO_SECFILE;
+
+ while (w != NULL) {
+ opt = find_option(w->word);
+ if (opt == NULL) {
+ option_error("In secrets file: unrecognized option '%s'",
+ w->word);
+ goto err;
+ }
+ n = n_arguments(opt);
+ w0 = w;
+ for (i = 0; i < n; ++i) {
+ w = w->next;
+ if (w == NULL) {
+ option_error(
+ "In secrets file: too few parameters for option '%s'",
+ w0->word);
+ goto err;
+ }
+ argv[i] = w->word;
+ }
+ if (!process_option(opt, w0->word, argv))
+ goto err;
+ w = w->next;
+ }
+ ret = 1;
+
+err:
+ return ret;
+}
+
+/*
+ * match_option - see if this option matches an option_t structure.
+ */
+static int
+match_option(name, opt, dowild)
+ char *name;
+ option_t *opt;
+ int dowild;
+{
+ int (*match) __P((char *, char **, int));
+
+ if (dowild != (opt->type == o_wild))
+ return 0;
+ if (!dowild)
+ return strcmp(name, opt->name) == 0;
+ match = (int (*) __P((char *, char **, int))) opt->addr;
+ return (*match)(name, NULL, 0);
+}
+
+/*
+ * find_option - scan the option lists for the various protocols
+ * looking for an entry with the given name.
+ * This could be optimized by using a hash table.
+ */
+static option_t *
+find_option(name)
+ const char *name;
+{
+ option_t *opt;
+ struct option_list *list;
+ int i, dowild;
+
+ for (dowild = 0; dowild <= 1; ++dowild) {
+ for (opt = general_options; opt->name != NULL; ++opt)
+ if (match_option(name, opt, dowild))
+ return opt;
+ for (opt = auth_options; opt->name != NULL; ++opt)
+ if (match_option(name, opt, dowild))
+ return opt;
+ for (list = extra_options; list != NULL; list = list->next)
+ for (opt = list->options; opt->name != NULL; ++opt)
+ if (match_option(name, opt, dowild))
+ return opt;
+ for (opt = the_channel->options; opt->name != NULL; ++opt)
+ if (match_option(name, opt, dowild))
+ return opt;
+ for (i = 0; protocols[i] != NULL; ++i)
+ if ((opt = protocols[i]->options) != NULL)
+ for (; opt->name != NULL; ++opt)
+ if (match_option(name, opt, dowild))
+ return opt;
+ }
+ return NULL;
+}
+
+/*
+ * process_option - process one new-style option.
+ */
+static int
+process_option(opt, cmd, argv)
+ option_t *opt;
+ char *cmd;
+ char **argv;
+{
+ u_int32_t v;
+ int iv, a;
+ char *sv;
+ int (*parser) __P((char **));
+ int (*wildp) __P((char *, char **, int));
+ char *optopt = (opt->type == o_wild)? "": " option";
+ int prio = option_priority;
+ option_t *mainopt = opt;
+
+ if ((opt->flags & OPT_PRIVFIX) && privileged_option)
+ prio += OPRIO_ROOT;
+ while (mainopt->flags & OPT_PRIOSUB)
+ --mainopt;
+ if (mainopt->flags & OPT_PRIO) {
+ if (prio < mainopt->priority) {
+ /* new value doesn't override old */
+ if (prio == OPRIO_CMDLINE && mainopt->priority > OPRIO_ROOT) {
+ option_error("%s%s set in %s cannot be overridden\n",
+ opt->name, optopt, mainopt->source);
+ return 0;
+ }
+ return 1;
+ }
+ if (prio > OPRIO_ROOT && mainopt->priority == OPRIO_CMDLINE)
+ warn("%s%s from %s overrides command line",
+ opt->name, optopt, option_source);
+ }
+
+ if ((opt->flags & OPT_INITONLY) && phase != PHASE_INITIALIZE) {
+ option_error("%s%s cannot be changed after initialization",
+ opt->name, optopt);
+ return 0;
+ }
+ if ((opt->flags & OPT_PRIV) && !privileged_option) {
+ option_error("using the %s%s requires root privilege",
+ opt->name, optopt);
+ return 0;
+ }
+ if ((opt->flags & OPT_ENABLE) && *(bool *)(opt->addr2) == 0) {
+ option_error("%s%s is disabled", opt->name, optopt);
+ return 0;
+ }
+ if ((opt->flags & OPT_DEVEQUIV) && devnam_fixed) {
+ option_error("the %s%s may not be changed in %s",
+ opt->name, optopt, option_source);
+ return 0;
+ }
+
+ switch (opt->type) {
+ case o_bool:
+ v = opt->flags & OPT_VALUE;
+ *(bool *)(opt->addr) = v;
+ if (opt->addr2 && (opt->flags & OPT_A2COPY))
+ *(bool *)(opt->addr2) = v;
+ break;
+
+ case o_int:
+ iv = 0;
+ if ((opt->flags & OPT_NOARG) == 0) {
+ if (!int_option(*argv, &iv))
+ return 0;
+ if ((((opt->flags & OPT_LLIMIT) && iv < opt->lower_limit)
+ || ((opt->flags & OPT_ULIMIT) && iv > opt->upper_limit))
+ && !((opt->flags & OPT_ZEROOK && iv == 0))) {
+ char *zok = (opt->flags & OPT_ZEROOK)? " zero or": "";
+ switch (opt->flags & OPT_LIMITS) {
+ case OPT_LLIMIT:
+ option_error("%s value must be%s >= %d",
+ opt->name, zok, opt->lower_limit);
+ break;
+ case OPT_ULIMIT:
+ option_error("%s value must be%s <= %d",
+ opt->name, zok, opt->upper_limit);
+ break;
+ case OPT_LIMITS:
+ option_error("%s value must be%s between %d and %d",
+ opt->name, opt->lower_limit, opt->upper_limit);
+ break;
+ }
+ return 0;
+ }
+ }
+ a = opt->flags & OPT_VALUE;
+ if (a >= 128)
+ a -= 256; /* sign extend */
+ iv += a;
+ if (opt->flags & OPT_INC)
+ iv += *(int *)(opt->addr);
+ if ((opt->flags & OPT_NOINCR) && !privileged_option) {
+ int oldv = *(int *)(opt->addr);
+ if ((opt->flags & OPT_ZEROINF) ?
+ (oldv != 0 && (iv == 0 || iv > oldv)) : (iv > oldv)) {
+ option_error("%s value cannot be increased", opt->name);
+ return 0;
+ }
+ }
+ *(int *)(opt->addr) = iv;
+ if (opt->addr2 && (opt->flags & OPT_A2COPY))
+ *(int *)(opt->addr2) = iv;
+ break;
+
+ case o_uint32:
+ if (opt->flags & OPT_NOARG) {
+ v = opt->flags & OPT_VALUE;
+ if (v & 0x80)
+ v |= 0xffffff00U;
+ } else if (!number_option(*argv, &v, 16))
+ return 0;
+ if (opt->flags & OPT_OR)
+ v |= *(u_int32_t *)(opt->addr);
+ *(u_int32_t *)(opt->addr) = v;
+ if (opt->addr2 && (opt->flags & OPT_A2COPY))
+ *(u_int32_t *)(opt->addr2) = v;
+ break;
+
+ case o_string:
+ if (opt->flags & OPT_STATIC) {
+ strlcpy((char *)(opt->addr), *argv, opt->upper_limit);
+ } else {
+ sv = strdup(*argv);
+ if (sv == NULL)
+ novm("option argument");
+ *(char **)(opt->addr) = sv;
+ }
+ break;
+
+ case o_special_noarg:
+ case o_special:
+ parser = (int (*) __P((char **))) opt->addr;
+ if (!(*parser)(argv))
+ return 0;
+ if (opt->flags & OPT_A2LIST) {
+ struct option_value *ovp, **pp;
+
+ ovp = malloc(sizeof(*ovp) + strlen(*argv));
+ if (ovp != 0) {
+ strcpy(ovp->value, *argv);
+ ovp->source = option_source;
+ ovp->next = NULL;
+ pp = (struct option_value **) &opt->addr2;
+ while (*pp != 0)
+ pp = &(*pp)->next;
+ *pp = ovp;
+ }
+ }
+ break;
+
+ case o_wild:
+ wildp = (int (*) __P((char *, char **, int))) opt->addr;
+ if (!(*wildp)(cmd, argv, 1))
+ return 0;
+ break;
+ }
+
+ if (opt->addr2 && (opt->flags & (OPT_A2COPY|OPT_ENABLE
+ |OPT_A2PRINTER|OPT_A2STRVAL|OPT_A2LIST)) == 0)
+ *(bool *)(opt->addr2) = !(opt->flags & OPT_A2CLR);
+
+ mainopt->source = option_source;
+ mainopt->priority = prio;
+ mainopt->winner = opt - mainopt;
+
+ return 1;
+}
+
+/*
+ * override_value - if the option priorities would permit us to
+ * override the value of option, return 1 and update the priority
+ * and source of the option value. Otherwise returns 0.
+ */
+int
+override_value(option, priority, source)
+ const char *option;
+ int priority;
+ const char *source;
+{
+ option_t *opt;
+
+ opt = find_option(option);
+ if (opt == NULL)
+ return 0;
+ while (opt->flags & OPT_PRIOSUB)
+ --opt;
+ if ((opt->flags & OPT_PRIO) && priority < opt->priority)
+ return 0;
+ opt->priority = priority;
+ opt->source = source;
+ opt->winner = -1;
+ return 1;
+}
+
+/*
+ * n_arguments - tell how many arguments an option takes
+ */
+static int
+n_arguments(opt)
+ option_t *opt;
+{
+ return (opt->type == o_bool || opt->type == o_special_noarg
+ || (opt->flags & OPT_NOARG))? 0: 1;
+}
+
+/*
+ * add_options - add a list of options to the set we grok.
+ */
+void
+add_options(opt)
+ option_t *opt;
+{
+ struct option_list *list;
+
+ list = malloc(sizeof(*list));
+ if (list == 0)
+ novm("option list entry");
+ list->options = opt;
+ list->next = extra_options;
+ extra_options = list;
+}
+
+/*
+ * check_options - check that options are valid and consistent.
+ */
+void
+check_options()
+{
+ if (logfile_fd >= 0 && logfile_fd != log_to_fd)
+ close(logfile_fd);
+}
+
+/*
+ * print_option - print out an option and its value
+ */
+static void
+print_option(opt, mainopt, printer, arg)
+ option_t *opt, *mainopt;
+ void (*printer) __P((void *, char *, ...));
+ void *arg;
+{
+ int i, v;
+ char *p;
+
+ if (opt->flags & OPT_NOPRINT)
+ return;
+ switch (opt->type) {
+ case o_bool:
+ v = opt->flags & OPT_VALUE;
+ if (*(bool *)opt->addr != v)
+ /* this can happen legitimately, e.g. lock
+ option turned off for default device */
+ break;
+ printer(arg, "%s", opt->name);
+ break;
+ case o_int:
+ v = opt->flags & OPT_VALUE;
+ if (v >= 128)
+ v -= 256;
+ i = *(int *)opt->addr;
+ if (opt->flags & OPT_NOARG) {
+ printer(arg, "%s", opt->name);
+ if (i != v) {
+ if (opt->flags & OPT_INC) {
+ for (; i > v; i -= v)
+ printer(arg, " %s", opt->name);
+ } else
+ printer(arg, " # oops: %d not %d\n",
+ i, v);
+ }
+ } else {
+ printer(arg, "%s %d", opt->name, i);
+ }
+ break;
+ case o_uint32:
+ printer(arg, "%s", opt->name);
+ if ((opt->flags & OPT_NOARG) == 0)
+ printer(arg, " %x", *(u_int32_t *)opt->addr);
+ break;
+
+ case o_string:
+ if (opt->flags & OPT_HIDE) {
+ p = "??????";
+ } else {
+ p = (char *) opt->addr;
+ if ((opt->flags & OPT_STATIC) == 0)
+ p = *(char **)p;
+ }
+ printer(arg, "%s %q", opt->name, p);
+ break;
+
+ case o_special:
+ case o_special_noarg:
+ case o_wild:
+ if (opt->type != o_wild) {
+ printer(arg, "%s", opt->name);
+ if (n_arguments(opt) == 0)
+ break;
+ printer(arg, " ");
+ }
+ if (opt->flags & OPT_A2PRINTER) {
+ void (*oprt) __P((option_t *,
+ void ((*)__P((void *, char *, ...))),
+ void *));
+ oprt = opt->addr2;
+ (*oprt)(opt, printer, arg);
+ } else if (opt->flags & OPT_A2STRVAL) {
+ p = (char *) opt->addr2;
+ if ((opt->flags & OPT_STATIC) == 0)
+ p = *(char **)p;
+ printer("%q", p);
+ } else if (opt->flags & OPT_A2LIST) {
+ struct option_value *ovp;
+
+ ovp = (struct option_value *) opt->addr2;
+ for (;;) {
+ printer(arg, "%q", ovp->value);
+ if ((ovp = ovp->next) == NULL)
+ break;
+ printer(arg, "\t\t# (from %s)\n%s ",
+ ovp->source, opt->name);
+ }
+ } else {
+ printer(arg, "xxx # [don't know how to print value]");
+ }
+ break;
+
+ default:
+ printer(arg, "# %s value (type %d)", opt->name, opt->type);
+ break;
+ }
+ printer(arg, "\t\t# (from %s)\n", mainopt->source);
+}
+
+/*
+ * print_option_list - print out options in effect from an
+ * array of options.
+ */
+static void
+print_option_list(opt, printer, arg)
+ option_t *opt;
+ void (*printer) __P((void *, char *, ...));
+ void *arg;
+{
+ while (opt->name != NULL) {
+ if (opt->priority != OPRIO_DEFAULT
+ && opt->winner != (short int) -1)
+ print_option(opt + opt->winner, opt, printer, arg);
+ do {
+ ++opt;
+ } while (opt->flags & OPT_PRIOSUB);
+ }
+}
+
+/*
+ * print_options - print out what options are in effect.
+ */
+void
+print_options(printer, arg)
+ void (*printer) __P((void *, char *, ...));
+ void *arg;
+{
+ struct option_list *list;
+ int i;
+
+ printer(arg, "pppd options in effect:\n");
+ print_option_list(general_options, printer, arg);
+ print_option_list(auth_options, printer, arg);
+ for (list = extra_options; list != NULL; list = list->next)
+ print_option_list(list->options, printer, arg);
+ print_option_list(the_channel->options, printer, arg);
+ for (i = 0; protocols[i] != NULL; ++i)
+ print_option_list(protocols[i]->options, printer, arg);
+}
+
+/*
+ * usage - print out a message telling how to use the program.
+ */
+static void
+usage()
+{
+ if (phase == PHASE_INITIALIZE)
+ fprintf(stderr, usage_string, VERSION, progname);
+}
+
+/*
+ * showhelp - print out usage message and exit.
+ */
+static int
+showhelp(argv)
+ char **argv;
+{
+ if (phase == PHASE_INITIALIZE) {
+ usage();
+ exit(0);
+ }
+ return 0;
+}
+
+/*
+ * showversion - print out the version number and exit.
+ */
+static int
+showversion(argv)
+ char **argv;
+{
+ if (phase == PHASE_INITIALIZE) {
+ fprintf(stderr, "pppd version %s\n", VERSION);
+ exit(0);
+ }
+ return 0;
+}
+
+/*
+ * option_error - print a message about an error in an option.
+ * The message is logged, and also sent to
+ * stderr if phase == PHASE_INITIALIZE.
+ */
+void
+option_error __V((char *fmt, ...))
+{
+ va_list args;
+ char buf[1024];
+
+#if defined(__STDC__)
+ va_start(args, fmt);
+#else
+ char *fmt;
+ va_start(args);
+ fmt = va_arg(args, char *);
+#endif
+ vslprintf(buf, sizeof(buf), fmt, args);
+ va_end(args);
+ if (phase == PHASE_INITIALIZE)
+ fprintf(stderr, "%s: %s\n", progname, buf);
+ syslog(LOG_ERR, "%s", buf);
+}
+
+#if 0
+/*
+ * readable - check if a file is readable by the real user.
+ */
+int
+readable(fd)
+ int fd;
+{
+ uid_t uid;
+ int i;
+ struct stat sbuf;
+
+ uid = getuid();
+ if (uid == 0)
+ return 1;
+ if (fstat(fd, &sbuf) != 0)
+ return 0;
+ if (sbuf.st_uid == uid)
+ return sbuf.st_mode & S_IRUSR;
+ if (sbuf.st_gid == getgid())
+ return sbuf.st_mode & S_IRGRP;
+ for (i = 0; i < ngroups; ++i)
+ if (sbuf.st_gid == groups[i])
+ return sbuf.st_mode & S_IRGRP;
+ return sbuf.st_mode & S_IROTH;
+}
+#endif
+
+/*
+ * Read a word from a file.
+ * Words are delimited by white-space or by quotes (" or ').
+ * Quotes, white-space and \ may be escaped with \.
+ * \<newline> is ignored.
+ */
+int
+getword(f, word, newlinep, filename)
+ FILE *f;
+ char *word;
+ int *newlinep;
+ char *filename;
+{
+ int c, len, escape;
+ int quoted, comment;
+ int value, digit, got, n;
+
+#define isoctal(c) ((c) >= '0' && (c) < '8')
+
+ *newlinep = 0;
+ len = 0;
+ escape = 0;
+ comment = 0;
+
+ /*
+ * First skip white-space and comments.
+ */
+ for (;;) {
+ c = getc(f);
+ if (c == EOF)
+ break;
+
+ /*
+ * A newline means the end of a comment; backslash-newline
+ * is ignored. Note that we cannot have escape && comment.
+ */
+ if (c == '\n') {
+ if (!escape) {
+ *newlinep = 1;
+ comment = 0;
+ } else
+ escape = 0;
+ continue;
+ }
+
+ /*
+ * Ignore characters other than newline in a comment.
+ */
+ if (comment)
+ continue;
+
+ /*
+ * If this character is escaped, we have a word start.
+ */
+ if (escape)
+ break;
+
+ /*
+ * If this is the escape character, look at the next character.
+ */
+ if (c == '\\') {
+ escape = 1;
+ continue;
+ }
+
+ /*
+ * If this is the start of a comment, ignore the rest of the line.
+ */
+ if (c == '#') {
+ comment = 1;
+ continue;
+ }
+
+ /*
+ * A non-whitespace character is the start of a word.
+ */
+ if (!isspace(c))
+ break;
+ }
+
+ /*
+ * Save the delimiter for quoted strings.
+ */
+ if (!escape && (c == '"' || c == '\'')) {
+ quoted = c;
+ c = getc(f);
+ } else
+ quoted = 0;
+
+ /*
+ * Process characters until the end of the word.
+ */
+ while (c != EOF) {
+ if (escape) {
+ /*
+ * This character is escaped: backslash-newline is ignored,
+ * various other characters indicate particular values
+ * as for C backslash-escapes.
+ */
+ escape = 0;
+ if (c == '\n') {
+ c = getc(f);
+ continue;
+ }
+
+ got = 0;
+ switch (c) {
+ case 'a':
+ value = '\a';
+ break;
+ case 'b':
+ value = '\b';
+ break;
+ case 'f':
+ value = '\f';
+ break;
+ case 'n':
+ value = '\n';
+ break;
+ case 'r':
+ value = '\r';
+ break;
+ case 's':
+ value = ' ';
+ break;
+ case 't':
+ value = '\t';
+ break;
+
+ default:
+ if (isoctal(c)) {
+ /*
+ * \ddd octal sequence
+ */
+ value = 0;
+ for (n = 0; n < 3 && isoctal(c); ++n) {
+ value = (value << 3) + (c & 07);
+ c = getc(f);
+ }
+ got = 1;
+ break;
+ }
+
+ if (c == 'x') {
+ /*
+ * \x<hex_string> sequence
+ */
+ value = 0;
+ c = getc(f);
+ for (n = 0; n < 2 && isxdigit(c); ++n) {
+ digit = toupper(c) - '0';
+ if (digit > 10)
+ digit += '0' + 10 - 'A';
+ value = (value << 4) + digit;
+ c = getc (f);
+ }
+ got = 1;
+ break;
+ }
+
+ /*
+ * Otherwise the character stands for itself.
+ */
+ value = c;
+ break;
+ }
+
+ /*
+ * Store the resulting character for the escape sequence.
+ */
+ if (len < MAXWORDLEN-1)
+ word[len] = value;
+ ++len;
+
+ if (!got)
+ c = getc(f);
+ continue;
+
+ }
+
+ /*
+ * Not escaped: see if we've reached the end of the word.
+ */
+ if (quoted) {
+ if (c == quoted)
+ break;
+ } else {
+ if (isspace(c) || c == '#') {
+ ungetc (c, f);
+ break;
+ }
+ }
+
+ /*
+ * Backslash starts an escape sequence.
+ */
+ if (c == '\\') {
+ escape = 1;
+ c = getc(f);
+ continue;
+ }
+
+ /*
+ * An ordinary character: store it in the word and get another.
+ */
+ if (len < MAXWORDLEN-1)
+ word[len] = c;
+ ++len;
+
+ c = getc(f);
+ }
+
+ /*
+ * End of the word: check for errors.
+ */
+ if (c == EOF) {
+ if (ferror(f)) {
+ if (errno == 0)
+ errno = EIO;
+ option_error("Error reading %s: %m", filename);
+ die(1);
+ }
+ /*
+ * If len is zero, then we didn't find a word before the
+ * end of the file.
+ */
+ if (len == 0)
+ return 0;
+ }
+
+ /*
+ * Warn if the word was too long, and append a terminating null.
+ */
+ if (len >= MAXWORDLEN) {
+ option_error("warning: word in file %s too long (%.20s...)",
+ filename, word);
+ len = MAXWORDLEN - 1;
+ }
+ word[len] = 0;
+
+ return 1;
+
+#undef isoctal
+
+}
+
+/*
+ * number_option - parse an unsigned numeric parameter for an option.
+ */
+static int
+number_option(str, valp, base)
+ char *str;
+ u_int32_t *valp;
+ int base;
+{
+ char *ptr;
+
+ *valp = strtoul(str, &ptr, base);
+ if (ptr == str) {
+ option_error("invalid numeric parameter '%s' for %s option",
+ str, current_option);
+ return 0;
+ }
+ return 1;
+}
+
+
+/*
+ * int_option - like number_option, but valp is int *,
+ * the base is assumed to be 0, and *valp is not changed
+ * if there is an error.
+ */
+int
+int_option(str, valp)
+ char *str;
+ int *valp;
+{
+ u_int32_t v;
+
+ if (!number_option(str, &v, 0))
+ return 0;
+ *valp = (int) v;
+ return 1;
+}
+
+
+/*
+ * The following procedures parse options.
+ */
+
+/*
+ * readfile - take commands from a file.
+ */
+static int
+readfile(argv)
+ char **argv;
+{
+ return options_from_file(*argv, 1, 1, privileged_option);
+}
+
+/*
+ * callfile - take commands from /etc/ppp/peers/<name>.
+ * Name may not contain /../, start with / or ../, or end in /..
+ */
+static int
+callfile(argv)
+ char **argv;
+{
+ char *fname, *arg, *p;
+ int l, ok;
+
+ arg = *argv;
+ ok = 1;
+ if (arg[0] == '/' || arg[0] == 0)
+ ok = 0;
+ else {
+ for (p = arg; *p != 0; ) {
+ if (p[0] == '.' && p[1] == '.' && (p[2] == '/' || p[2] == 0)) {
+ ok = 0;
+ break;
+ }
+ while (*p != '/' && *p != 0)
+ ++p;
+ if (*p == '/')
+ ++p;
+ }
+ }
+ if (!ok) {
+ option_error("call option value may not contain .. or start with /");
+ return 0;
+ }
+
+ l = strlen(arg) + strlen(_PATH_PEERFILES) + 1;
+ if ((fname = (char *) malloc(l)) == NULL)
+ novm("call file name");
+ slprintf(fname, l, "%s%s", _PATH_PEERFILES, arg);
+
+ ok = options_from_file(fname, 1, 1, 1);
+
+ free(fname);
+ return ok;
+}
+
+#ifdef PPP_FILTER
+/*
+ * setpassfilter - Set the pass filter for packets
+ */
+static int
+setpassfilter(argv)
+ char **argv;
+{
+ pc.linktype = DLT_PPP;
+ pc.snapshot = PPP_HDRLEN;
+
+ if (pcap_compile(&pc, &pass_filter, *argv, 1, netmask) == 0)
+ return 1;
+ option_error("error in pass-filter expression: %s\n", pcap_geterr(&pc));
+ return 0;
+}
+
+/*
+ * setactivefilter - Set the active filter for packets
+ */
+static int
+setactivefilter(argv)
+ char **argv;
+{
+ pc.linktype = DLT_PPP;
+ pc.snapshot = PPP_HDRLEN;
+
+ if (pcap_compile(&pc, &active_filter, *argv, 1, netmask) == 0)
+ return 1;
+ option_error("error in active-filter expression: %s\n", pcap_geterr(&pc));
+ return 0;
+}
+#endif
+
+/*
+ * setdomain - Set domain name to append to hostname
+ */
+static int
+setdomain(argv)
+ char **argv;
+{
+ gethostname(hostname, MAXNAMELEN);
+ if (**argv != 0) {
+ if (**argv != '.')
+ strncat(hostname, ".", MAXNAMELEN - strlen(hostname));
+ domain = hostname + strlen(hostname);
+ strncat(hostname, *argv, MAXNAMELEN - strlen(hostname));
+ }
+ hostname[MAXNAMELEN-1] = 0;
+ return (1);
+}
+
+
+static int
+setlogfile(argv)
+ char **argv;
+{
+ int fd, err;
+
+ if (!privileged_option)
+ seteuid(getuid());
+ fd = open(*argv, O_WRONLY | O_APPEND | O_CREAT | O_EXCL, 0644);
+ if (fd < 0 && errno == EEXIST)
+ fd = open(*argv, O_WRONLY | O_APPEND);
+ err = errno;
+ if (!privileged_option)
+ seteuid(0);
+ if (fd < 0) {
+ errno = err;
+ option_error("Can't open log file %s: %m", *argv);
+ return 0;
+ }
+ strlcpy(logfile_name, *argv, sizeof(logfile_name));
+ if (logfile_fd >= 0)
+ close(logfile_fd);
+ logfile_fd = fd;
+ log_to_fd = fd;
+ log_default = 0;
+ return 1;
+}
+
+#ifdef PLUGIN
+static int
+loadplugin(argv)
+ char **argv;
+{
+ char *arg = *argv;
+ void *handle;
+ const char *err;
+ void (*init) __P((void));
+ char *path = arg;
+ const char *vers;
+
+ if (strchr(arg, '/') == 0) {
+ const char *base = _PATH_PLUGIN;
+ int l = strlen(base) + strlen(arg) + 2;
+ path = malloc(l);
+ if (path == 0)
+ novm("plugin file path");
+ strlcpy(path, base, l);
+ strlcat(path, "/", l);
+ strlcat(path, arg, l);
+ }
+ handle = dlopen(path, RTLD_GLOBAL | RTLD_NOW);
+ if (handle == 0) {
+ err = dlerror();
+ if (err != 0)
+ option_error("%s", err);
+ option_error("Couldn't load plugin %s", arg);
+ goto err;
+ }
+ init = (void (*)(void))dlsym(handle, "plugin_init");
+ if (init == 0) {
+ option_error("%s has no initialization entry point", arg);
+ goto errclose;
+ }
+ vers = (const char *) dlsym(handle, "pppd_version");
+ if (vers == 0) {
+ warn("Warning: plugin %s has no version information", arg);
+ } else if (strcmp(vers, VERSION) != 0) {
+ option_error("Plugin %s is for pppd version %s, this is %s",
+ vers, VERSION);
+ goto errclose;
+ }
+ info("Plugin %s loaded.", arg);
+ (*init)();
+ return 1;
+
+ errclose:
+ dlclose(handle);
+ err:
+ if (path != arg)
+ free(path);
+ return 0;
+}
+#endif /* PLUGIN */
diff --git a/mdk-stage1/ppp/pppd/patchlevel.h b/mdk-stage1/ppp/pppd/patchlevel.h
new file mode 100644
index 000000000..c16f01dba
--- /dev/null
+++ b/mdk-stage1/ppp/pppd/patchlevel.h
@@ -0,0 +1,4 @@
+/* $Id: patchlevel.h 195720 2001-06-11 11:44:34Z gc $ */
+
+#define VERSION "2.4.1"
+#define DATE "25 March 2001"
diff --git a/mdk-stage1/ppp/pppd/pathnames.h b/mdk-stage1/ppp/pppd/pathnames.h
new file mode 100644
index 000000000..7e3b77f82
--- /dev/null
+++ b/mdk-stage1/ppp/pppd/pathnames.h
@@ -0,0 +1,25 @@
+/*
+ * define path names
+ *
+ * $Id: pathnames.h 195734 2001-06-11 14:46:02Z gc $
+ */
+
+#define _PATH_VARRUN "/var/run/"
+#define _PATH_DEVNULL "/dev/null"
+#define _ROOT_PATH
+
+#define _PATH_UPAPFILE _ROOT_PATH "/etc/ppp/pap-secrets"
+#define _PATH_CHAPFILE _ROOT_PATH "/etc/ppp/chap-secrets"
+#define _PATH_SYSOPTIONS _ROOT_PATH "/etc/ppp/options"
+#define _PATH_IPUP _ROOT_PATH "/etc/ppp/ip-up"
+#define _PATH_IPDOWN _ROOT_PATH "/etc/ppp/ip-down"
+#define _PATH_AUTHUP _ROOT_PATH "/etc/ppp/auth-up"
+#define _PATH_AUTHDOWN _ROOT_PATH "/etc/ppp/auth-down"
+#define _PATH_TTYOPT _ROOT_PATH "/etc/ppp/options."
+#define _PATH_CONNERRS _ROOT_PATH "/etc/ppp/connect-errors"
+#define _PATH_PEERFILES _ROOT_PATH "/etc/ppp/peers/"
+#define _PATH_RESOLV _ROOT_PATH "/etc/resolv.conf"
+
+#define _PATH_USEROPT ".ppprc"
+
+#define _PATH_PPPDB _ROOT_PATH _PATH_VARRUN "pppd.tdb"
diff --git a/mdk-stage1/ppp/pppd/plugins/Makefile.linux b/mdk-stage1/ppp/pppd/plugins/Makefile.linux
new file mode 100644
index 000000000..a64256461
--- /dev/null
+++ b/mdk-stage1/ppp/pppd/plugins/Makefile.linux
@@ -0,0 +1,19 @@
+CC = gcc
+CFLAGS = -g -O2 -I.. -I../../include -fPIC
+LDFLAGS = -shared
+INSTALL = install
+
+all: minconn.so passprompt.so
+
+minconn.so: minconn.c
+ $(CC) -o $@ $(LDFLAGS) $(CFLAGS) minconn.c
+
+passprompt.so: passprompt.c
+ $(CC) -o $@ $(LDFLAGS) $(CFLAGS) passprompt.c
+
+LIBDIR = /usr/lib/pppd
+
+install: minconn.so passprompt.so
+ version=`awk -F '"' '/VERSION/ { print $$2; }' ../patchlevel.h`; \
+ $(INSTALL) -d $(LIBDIR)/$$version; \
+ $(INSTALL) $? $(LIBDIR)/$$version \ No newline at end of file
diff --git a/mdk-stage1/ppp/pppd/plugins/Makefile.sol2 b/mdk-stage1/ppp/pppd/plugins/Makefile.sol2
new file mode 100644
index 000000000..5e110201c
--- /dev/null
+++ b/mdk-stage1/ppp/pppd/plugins/Makefile.sol2
@@ -0,0 +1,27 @@
+#
+# Makefile for plugins on Solaris 2
+#
+# $Id: Makefile.sol2 195720 2001-06-11 11:44:34Z gc $
+#
+
+include ../../svr4/Makedefs
+
+CFLAGS = -c -O -I.. -I../../include $(COPTS)
+LDFLAGS = -G
+
+all: minconn.so
+
+minconn.so: minconn.o
+ ld -o $@ $(LDFLAGS) -h $@ minconn.o
+
+minconn.o: minconn.c
+ $(CC) $(CFLAGS) -c $?
+
+passprompt.so: passprompt.o
+ ld -o $@ $(LDFLAGS) -h $@ passprompt.o
+
+passprompt.o: passprompt.c
+ $(CC) $(CFLAGS) -c $?
+
+clean:
+ rm -f *.o *.so
diff --git a/mdk-stage1/ppp/pppd/plugins/minconn.c b/mdk-stage1/ppp/pppd/plugins/minconn.c
new file mode 100644
index 000000000..02ea34bf6
--- /dev/null
+++ b/mdk-stage1/ppp/pppd/plugins/minconn.c
@@ -0,0 +1,46 @@
+/*
+ * minconn.c - pppd plugin to implement a `minconnect' option.
+ *
+ * Copyright 1999 Paul Mackerras.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms. The name of the author
+ * may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+#include <stddef.h>
+#include <time.h>
+#include "pppd.h"
+
+char pppd_version[] = VERSION;
+
+static int minconnect = 0;
+
+static option_t my_options[] = {
+ { "minconnect", o_int, &minconnect,
+ "Set minimum connect time before idle timeout applies" },
+ { NULL }
+};
+
+static int my_get_idle(struct ppp_idle *idle)
+{
+ time_t t;
+
+ if (idle == NULL)
+ return minconnect? minconnect: idle_time_limit;
+ t = idle->xmit_idle;
+ if (idle->recv_idle < t)
+ t = idle->recv_idle;
+ return idle_time_limit - t;
+}
+
+void plugin_init(void)
+{
+ info("plugin_init");
+ add_options(my_options);
+ idle_time_hook = my_get_idle;
+}
diff --git a/mdk-stage1/ppp/pppd/plugins/passprompt.c b/mdk-stage1/ppp/pppd/plugins/passprompt.c
new file mode 100644
index 000000000..5e6a7f90b
--- /dev/null
+++ b/mdk-stage1/ppp/pppd/plugins/passprompt.c
@@ -0,0 +1,108 @@
+/*
+ * passprompt.c - pppd plugin to invoke an external PAP password prompter
+ *
+ * Copyright 1999 Paul Mackerras, Alan Curry.
+ *
+ * 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.
+ */
+#include <errno.h>
+#include <unistd.h>
+#include <sys/wait.h>
+#include <syslog.h>
+#include "pppd.h"
+
+char pppd_version[] = VERSION;
+
+static char promptprog[PATH_MAX+1];
+
+static option_t options[] = {
+ { "promptprog", o_string, promptprog,
+ "External PAP password prompting program",
+ OPT_STATIC, NULL, PATH_MAX },
+ { NULL }
+};
+
+static int promptpass(char *user, char *passwd)
+{
+ int p[2];
+ pid_t kid;
+ int readgood, wstat;
+ size_t red;
+
+ if (promptprog[0] == 0 || access(promptprog, X_OK) < 0)
+ return -1; /* sorry, can't help */
+
+ if (!passwd)
+ return 1;
+
+ if (pipe(p)) {
+ warn("Can't make a pipe for %s", promptprog);
+ return 0;
+ }
+ if ((kid = fork()) == (pid_t) -1) {
+ warn("Can't fork to run %s", promptprog);
+ close(p[0]);
+ close(p[1]);
+ return 0;
+ }
+ if (!kid) {
+ /* we are the child, exec the program */
+ char *argv[4], fdstr[32];
+ sys_close();
+ closelog();
+ close(p[0]);
+ seteuid(getuid());
+ setegid(getgid());
+ argv[0] = promptprog;
+ argv[1] = user;
+ argv[2] = remote_name;
+ sprintf(fdstr, "%d", p[1]);
+ argv[3] = fdstr;
+ argv[4] = 0;
+ execv(*argv, argv);
+ _exit(127);
+ }
+
+ /* we are the parent, read the password from the pipe */
+ close(p[1]);
+ readgood = 0;
+ do {
+ red = read(p[0], passwd + readgood, MAXSECRETLEN-1 - readgood);
+ if (red == 0)
+ break;
+ if (red < 0) {
+ error("Can't read secret from %s: %m", promptprog);
+ readgood = -1;
+ break;
+ }
+ readgood += red;
+ } while (readgood < MAXSECRETLEN - 1);
+ passwd[readgood] = 0;
+ close(p[0]);
+
+ /* now wait for child to exit */
+ while (waitpid(kid, &wstat, 0) < 0) {
+ if (errno != EINTR) {
+ warn("error waiting for %s: %m", promptprog);
+ break;
+ }
+ }
+
+ if (readgood < 0)
+ return 0;
+ if (!WIFEXITED(wstat))
+ warn("%s terminated abnormally", promptprog);
+ if (WEXITSTATUS(wstat))
+ warn("%s exited with code %d", promptprog, WEXITSTATUS(status));
+
+ return 1;
+}
+
+void plugin_init(void)
+{
+ add_options(options);
+ pap_passwd_hook = promptpass;
+}
diff --git a/mdk-stage1/ppp/pppd/ppp.pam b/mdk-stage1/ppp/pppd/ppp.pam
new file mode 100644
index 000000000..475a4bc88
--- /dev/null
+++ b/mdk-stage1/ppp/pppd/ppp.pam
@@ -0,0 +1,6 @@
+#%PAM-1.0
+# Information for the PPPD process with the 'login' option.
+auth required pam_nologin.so
+auth required pam_unix.so
+account required pam_unix.so
+session required pam_unix.so \ No newline at end of file
diff --git a/mdk-stage1/ppp/pppd/pppd.8 b/mdk-stage1/ppp/pppd/pppd.8
new file mode 100644
index 000000000..cded59872
--- /dev/null
+++ b/mdk-stage1/ppp/pppd/pppd.8
@@ -0,0 +1,1591 @@
+.\" manual page [] for pppd 2.4
+.\" $Id: pppd.8 195720 2001-06-11 11:44:34Z gc $
+.\" SH section heading
+.\" SS subsection heading
+.\" LP paragraph
+.\" IP indented paragraph
+.\" TP hanging label
+.TH PPPD 8
+.SH NAME
+pppd \- Point to Point Protocol daemon
+.SH SYNOPSIS
+.B pppd
+[
+.I tty_name
+] [
+.I speed
+] [
+.I options
+]
+.SH DESCRIPTION
+.LP
+The Point-to-Point Protocol (PPP) provides a method for transmitting
+datagrams over serial point-to-point links. PPP
+is composed of three parts: a method for encapsulating datagrams over
+serial links, an extensible Link Control Protocol (LCP), and
+a family of Network Control Protocols (NCP) for establishing
+and configuring different network-layer protocols.
+.LP
+The encapsulation scheme is provided by driver code in the kernel.
+Pppd provides the basic LCP, authentication support, and an NCP for
+establishing and configuring the Internet Protocol (IP) (called the IP
+Control Protocol, IPCP).
+.SH FREQUENTLY USED OPTIONS
+.TP
+.I <tty_name>
+Communicate over the named device. The string "/dev/" is prepended if
+necessary. If no device name is given, or if the name of the terminal
+connected to the standard input is given, pppd will use that terminal,
+and will not fork to put itself in the background. A value for this
+option from a privileged source cannot be overridden by a
+non-privileged user.
+.TP
+.I <speed>
+Set the baud rate to <speed> (a decimal number). On systems such as
+4.4BSD and NetBSD, any speed can be specified. Other systems
+(e.g. SunOS) allow only a limited set of speeds.
+.TP
+.B asyncmap \fI<map>
+Set the async character map to <map>. This map describes which
+control characters cannot be successfully received over the serial
+line. Pppd will ask the peer to send these characters as a 2-byte
+escape sequence. The argument is a 32 bit hex number with each bit
+representing a character to escape. Bit 0 (00000001) represents the
+character 0x00; bit 31 (80000000) represents the character 0x1f or ^_.
+If multiple \fIasyncmap\fR options are given, the values are ORed
+together. If no \fIasyncmap\fR option is given, no async character
+map will be negotiated for the receive direction; the peer should then
+escape \fIall\fR control characters. To escape transmitted
+characters, use the \fIescape\fR option.
+.TP
+.B auth
+Require the peer to authenticate itself before allowing network
+packets to be sent or received. This option is the default if the
+system has a default route. If neither this option nor the
+\fInoauth\fR option is specified, pppd will only allow the peer to use
+IP addresses to which the system does not already have a route.
+.TP
+.B call \fIname
+Read options from the file /etc/ppp/peers/\fIname\fR. This file may
+contain privileged options, such as \fInoauth\fR, even if pppd
+is not being run by root. The \fIname\fR string may not begin with /
+or include .. as a pathname component. The format of the options file
+is described below.
+.TP
+.B connect \fIscript
+Use the executable or shell command specified by \fIscript\fR to set
+up the serial line. This script would typically use the chat(8)
+program to dial the modem and start the remote ppp session. A value
+for this option from a privileged source cannot be overridden by a
+non-privileged user.
+.TP
+.B crtscts
+Use hardware flow control (i.e. RTS/CTS) to control the flow of
+data on the serial port. If neither the \fIcrtscts\fR, the
+\fInocrtscts\fR, the \fIcdtrcts\fR nor the \fInocdtrcts\fR option
+is given, the hardware flow control setting for the serial port is
+left unchanged.
+Some serial ports (such as Macintosh serial ports) lack a true
+RTS output. Such serial ports use this mode to implement
+unidirectional flow control. The serial port will
+suspend transmission when requested by the modem (via CTS)
+but will be unable to request the modem stop sending to the
+computer. This mode retains the ability to use DTR as
+a modem control line.
+.TP
+.B defaultroute
+Add a default route to the system routing tables, using the peer as
+the gateway, when IPCP negotiation is successfully completed.
+This entry is removed when the PPP connection is broken. This option
+is privileged if the \fInodefaultroute\fR option has been specified.
+.TP
+.B disconnect \fIscript
+Run the executable or shell command specified by \fIscript\fR after
+pppd has terminated the link. This script could, for example, issue
+commands to the modem to cause it to hang up if hardware modem control
+signals were not available. The disconnect script is not run if the
+modem has already hung up. A value for this option from a privileged
+source cannot be overridden by a non-privileged user.
+.TP
+.B escape \fIxx,yy,...
+Specifies that certain characters should be escaped on transmission
+(regardless of whether the peer requests them to be escaped with its
+async control character map). The characters to be escaped are
+specified as a list of hex numbers separated by commas. Note that
+almost any character can be specified for the \fIescape\fR option,
+unlike the \fIasyncmap\fR option which only allows control characters
+to be specified. The characters which may not be escaped are those
+with hex values 0x20 - 0x3f or 0x5e.
+.TP
+.B file \fIname
+Read options from file \fIname\fR (the format is described below).
+The file must be readable by the user who has invoked pppd.
+.TP
+.B init \fIscript
+Run the executable or shell command specified by \fIscript\fR to
+initialize the serial line. This script would typically use the
+chat(8) program to configure the modem to enable auto answer. A value
+for this option from a privileged source cannot be overridden by a
+non-privileged user.
+.TP
+.B lock
+Specifies that pppd should create a UUCP-style lock file for the
+serial device to ensure exclusive access to the device.
+.TP
+.B mru \fIn
+Set the MRU [Maximum Receive Unit] value to \fIn\fR. Pppd
+will ask the peer to send packets of no more than \fIn\fR bytes. The
+minimum MRU value is 128. The default MRU value is 1500. A value of
+296 is recommended for slow links (40 bytes for TCP/IP header + 256
+bytes of data). (Note that for IPv6 MRU must be at least 1280)
+.TP
+.B mtu \fIn
+Set the MTU [Maximum Transmit Unit] value to \fIn\fR. Unless the
+peer requests a smaller value via MRU negotiation, pppd will
+request that the kernel networking code send data packets of no more
+than \fIn\fR bytes through the PPP network interface. (Note that for
+IPv6 MTU must be at least 1280)
+.TP
+.B passive
+Enables the "passive" option in the LCP. With this option, pppd will
+attempt to initiate a connection; if no reply is received from the
+peer, pppd will then just wait passively for a valid LCP packet from
+the peer, instead of exiting, as it would without this option.
+.SH OPTIONS
+.TP
+.I <local_IP_address>\fB:\fI<remote_IP_address>
+Set the local and/or remote interface IP addresses. Either one may be
+omitted. The IP addresses can be specified with a host name or in
+decimal dot notation (e.g. 150.234.56.78). The default local
+address is the (first) IP address of the system (unless the
+\fInoipdefault\fR
+option is given). The remote address will be obtained from the peer
+if not specified in any option. Thus, in simple cases, this option is
+not required. If a local and/or remote IP address is specified with
+this option, pppd
+will not accept a different value from the peer in the IPCP
+negotiation, unless the \fIipcp-accept-local\fR and/or
+\fIipcp-accept-remote\fR options are given, respectively.
+.TP
+.B ipv6 \fI<local_interface_identifier>\fR,\fI<remote_interface_identifier>
+Set the local and/or remote 64-bit interface identifier. Either one may be
+omitted. The identifier must be specified in standard ascii notation of
+IPv6 addresses (e.g. ::dead:beef). If the
+\fIipv6cp-use-ipaddr\fR
+option is given, the local identifier is the local IPv4 address (see above).
+On systems which supports a unique persistent id, such as EUI-48 derived
+from the Ethernet MAC address, \fIipv6cp-use-persistent\fR option can be
+used to replace the \fIipv6 <local>,<remote>\fR option. Otherwise the
+identifier is randomized.
+.TP
+.B active-filter \fIfilter-expression
+Specifies a packet filter to be applied to data packets to determine
+which packets are to be regarded as link activity, and therefore reset
+the idle timer, or cause the link to be brought up in demand-dialling
+mode. This option is useful in conjunction with the
+\fBidle\fR option if there are packets being sent or received
+regularly over the link (for example, routing information packets)
+which would otherwise prevent the link from ever appearing to be idle.
+The \fIfilter-expression\fR syntax is as described for tcpdump(1),
+except that qualifiers which are inappropriate for a PPP link, such as
+\fBether\fR and \fBarp\fR, are not permitted. Generally the filter
+expression should be enclosed in single-quotes to prevent whitespace
+in the expression from being interpreted by the shell. This option
+is currently only available under NetBSD, and then only
+if both the kernel and pppd were compiled with PPP_FILTER defined.
+.TP
+.B allow-ip \fIaddress(es)
+Allow peers to use the given IP address or subnet without
+authenticating themselves. The parameter is parsed as for each
+element of the list of allowed IP addresses in the secrets files (see
+the AUTHENTICATION section below).
+.TP
+.B bsdcomp \fInr,nt
+Request that the peer compress packets that it sends, using the
+BSD-Compress scheme, with a maximum code size of \fInr\fR bits, and
+agree to compress packets sent to the peer with a maximum code size of
+\fInt\fR bits. If \fInt\fR is not specified, it defaults to the value
+given for \fInr\fR. Values in the range 9 to 15 may be used for
+\fInr\fR and \fInt\fR; larger values give better compression but
+consume more kernel memory for compression dictionaries.
+Alternatively, a value of 0 for \fInr\fR or \fInt\fR disables
+compression in the corresponding direction. Use \fInobsdcomp\fR or
+\fIbsdcomp 0\fR to disable BSD-Compress compression entirely.
+.TP
+.B cdtrcts
+Use a non-standard hardware flow control (i.e. DTR/CTS) to control
+the flow of data on the serial port. If neither the \fIcrtscts\fR,
+the \fInocrtscts\fR, the \fIcdtrcts\fR nor the \fInocdtrcts\fR
+option is given, the hardware flow control setting for the serial
+port is left unchanged.
+Some serial ports (such as Macintosh serial ports) lack a true
+RTS output. Such serial ports use this mode to implement true
+bi-directional flow control. The sacrifice is that this flow
+control mode does not permit using DTR as a modem control line.
+.TP
+.B chap-interval \fIn
+If this option is given, pppd will rechallenge the peer every \fIn\fR
+seconds.
+.TP
+.B chap-max-challenge \fIn
+Set the maximum number of CHAP challenge transmissions to \fIn\fR
+(default 10).
+.TP
+.B chap-restart \fIn
+Set the CHAP restart interval (retransmission timeout for challenges)
+to \fIn\fR seconds (default 3).
+.TP
+.B connect-delay \fIn
+Wait for up \fIn\fR milliseconds after the connect script finishes for
+a valid PPP packet from the peer. At the end of this time, or when a
+valid PPP packet is received from the peer, pppd will commence
+negotiation by sending its first LCP packet. The default value is
+1000 (1 second). This wait period only applies if the \fBconnect\fR
+or \fBpty\fR option is used.
+.TP
+.B debug
+Enables connection debugging facilities.
+If this option is given, pppd will log the contents of all
+control packets sent or received in a readable form. The packets are
+logged through syslog with facility \fIdaemon\fR and level
+\fIdebug\fR. This information can be directed to a file by setting up
+/etc/syslog.conf appropriately (see syslog.conf(5)).
+.TP
+.B default-asyncmap
+Disable asyncmap negotiation, forcing all control characters to be
+escaped for both the transmit and the receive direction.
+.TP
+.B default-mru
+Disable MRU [Maximum Receive Unit] negotiation. With this option,
+pppd will use the default MRU value of 1500 bytes for both the
+transmit and receive direction.
+.TP
+.B deflate \fInr,nt
+Request that the peer compress packets that it sends, using the
+Deflate scheme, with a maximum window size of \fI2**nr\fR bytes, and
+agree to compress packets sent to the peer with a maximum window size
+of \fI2**nt\fR bytes. If \fInt\fR is not specified, it defaults to
+the value given for \fInr\fR. Values in the range 9 to 15 may be used
+for \fInr\fR and \fInt\fR; larger values give better compression but
+consume more kernel memory for compression dictionaries.
+Alternatively, a value of 0 for \fInr\fR or \fInt\fR disables
+compression in the corresponding direction. Use \fInodeflate\fR or
+\fIdeflate 0\fR to disable Deflate compression entirely. (Note: pppd
+requests Deflate compression in preference to BSD-Compress if the peer
+can do either.)
+.TP
+.B demand
+Initiate the link only on demand, i.e. when data traffic is present.
+With this option, the remote IP address must be specified by the user
+on the command line or in an options file. Pppd will initially
+configure the interface and enable it for IP traffic without
+connecting to the peer. When traffic is available, pppd will
+connect to the peer and perform negotiation, authentication, etc.
+When this is completed, pppd will commence passing data packets
+(i.e., IP packets) across the link.
+
+The \fIdemand\fR option implies the \fIpersist\fR option. If this
+behaviour is not desired, use the \fInopersist\fR option after the
+\fIdemand\fR option. The \fIidle\fR and \fIholdoff\fR
+options are also useful in conjuction with the \fIdemand\fR option.
+.TP
+.B domain \fId
+Append the domain name \fId\fR to the local host name for authentication
+purposes. For example, if gethostname() returns the name porsche, but
+the fully qualified domain name is porsche.Quotron.COM, you could
+specify \fIdomain Quotron.COM\fR. Pppd would then use the name
+\fIporsche.Quotron.COM\fR for looking up secrets in the secrets file,
+and as the default name to send to the peer when authenticating itself
+to the peer. This option is privileged.
+.TP
+.B dryrun
+With the \fBdryrun\fR option, pppd will print out all the option
+values which have been set and then exit, after parsing the command
+line and options files and checking the option values, but before
+initiating the link. The option values are logged at level info, and
+also printed to standard output unless the device on standard output
+is the device that pppd would be using to communicate with the peer.
+.TP
+.B dump
+With the \fBdump\fR option, pppd will print out all the option values
+which have been set. This option is like the \fBdryrun\fR option
+except that pppd proceeds as normal rather than exiting.
+.TP
+.B endpoint \fI<epdisc>
+Sets the endpoint discriminator sent by the local machine to the peer
+during multilink negotiation to \fI<epdisc>\fR. The default is to use
+the MAC address of the first ethernet interface on the system, if any,
+otherwise the IPv4 address corresponding to the hostname, if any,
+provided it is not in the multicast or locally-assigned IP address
+ranges, or the localhost address. The endpoint discriminator can be
+the string \fBnull\fR or of the form \fItype\fR:\fIvalue\fR, where
+type is a decimal number or one of the strings \fBlocal\fR, \fBIP\fR,
+\fBMAC\fR, \fBmagic\fR, or \fBphone\fR. The value is an IP address in
+dotted-decimal notation for the \fBIP\fR type, or a string of bytes in
+hexadecimal, separated by periods or colons for the other types. For
+the MAC type, the value may also be the name of an ethernet or similar
+network interface. This option is currently only available under
+Linux.
+.TP
+.B hide-password
+When logging the contents of PAP packets, this option causes pppd to
+exclude the password string from the log. This is the default.
+.TP
+.B holdoff \fIn
+Specifies how many seconds to wait before re-initiating the link after
+it terminates. This option only has any effect if the \fIpersist\fR
+or \fIdemand\fR option is used. The holdoff period is not applied if
+the link was terminated because it was idle.
+.TP
+.B idle \fIn
+Specifies that pppd should disconnect if the link is idle for \fIn\fR
+seconds. The link is idle when no data packets (i.e. IP packets) are
+being sent or received. Note: it is not advisable to use this option
+with the \fIpersist\fR option without the \fIdemand\fR option.
+If the \fBactive-filter\fR
+option is given, data packets which are rejected by the specified
+activity filter also count as the link being idle.
+.TP
+.B ipcp-accept-local
+With this option, pppd will accept the peer's idea of our local IP
+address, even if the local IP address was specified in an option.
+.TP
+.B ipcp-accept-remote
+With this option, pppd will accept the peer's idea of its (remote) IP
+address, even if the remote IP address was specified in an option.
+.TP
+.B ipcp-max-configure \fIn
+Set the maximum number of IPCP configure-request transmissions to
+\fIn\fR (default 10).
+.TP
+.B ipcp-max-failure \fIn
+Set the maximum number of IPCP configure-NAKs returned before starting
+to send configure-Rejects instead to \fIn\fR (default 10).
+.TP
+.B ipcp-max-terminate \fIn
+Set the maximum number of IPCP terminate-request transmissions to
+\fIn\fR (default 3).
+.TP
+.B ipcp-restart \fIn
+Set the IPCP restart interval (retransmission timeout) to \fIn\fR
+seconds (default 3).
+.TP
+.B ipparam \fIstring
+Provides an extra parameter to the ip-up and ip-down scripts. If this
+option is given, the \fIstring\fR supplied is given as the 6th
+parameter to those scripts.
+.TP
+.B ipv6cp-max-configure \fIn
+Set the maximum number of IPv6CP configure-request transmissions to
+\fIn\fR (default 10).
+.TP
+.B ipv6cp-max-failure \fIn
+Set the maximum number of IPv6CP configure-NAKs returned before starting
+to send configure-Rejects instead to \fIn\fR (default 10).
+.TP
+.B ipv6cp-max-terminate \fIn
+Set the maximum number of IPv6CP terminate-request transmissions to
+\fIn\fR (default 3).
+.TP
+.B ipv6cp-restart \fIn
+Set the IPv6CP restart interval (retransmission timeout) to \fIn\fR
+seconds (default 3).
+.TP
+.B ipx
+Enable the IPXCP and IPX protocols. This option is presently only
+supported under Linux, and only if your kernel has been configured to
+include IPX support.
+.TP
+.B ipx-network \fIn
+Set the IPX network number in the IPXCP configure request frame to
+\fIn\fR, a hexadecimal number (without a leading 0x). There is no
+valid default. If this option is not specified, the network number is
+obtained from the peer. If the peer does not have the network number,
+the IPX protocol will not be started.
+.TP
+.B ipx-node \fIn\fB:\fIm
+Set the IPX node numbers. The two node numbers are separated from each
+other with a colon character. The first number \fIn\fR is the local
+node number. The second number \fIm\fR is the peer's node number. Each
+node number is a hexadecimal number, at most 10 digits long. The node
+numbers on the ipx-network must be unique. There is no valid
+default. If this option is not specified then the node numbers are
+obtained from the peer.
+.TP
+.B ipx-router-name \fI<string>
+Set the name of the router. This is a string and is sent to the peer
+as information data.
+.TP
+.B ipx-routing \fIn
+Set the routing protocol to be received by this option. More than one
+instance of \fIipx-routing\fR may be specified. The '\fInone\fR'
+option (0) may be specified as the only instance of ipx-routing. The
+values may be \fI0\fR for \fINONE\fR, \fI2\fR for \fIRIP/SAP\fR, and
+\fI4\fR for \fINLSP\fR.
+.TP
+.B ipxcp-accept-local
+Accept the peer's NAK for the node number specified in the ipx-node
+option. If a node number was specified, and non-zero, the default is
+to insist that the value be used. If you include this option then you
+will permit the peer to override the entry of the node number.
+.TP
+.B ipxcp-accept-network
+Accept the peer's NAK for the network number specified in the
+ipx-network option. If a network number was specified, and non-zero, the
+default is to insist that the value be used. If you include this
+option then you will permit the peer to override the entry of the node
+number.
+.TP
+.B ipxcp-accept-remote
+Use the peer's network number specified in the configure request
+frame. If a node number was specified for the peer and this option was
+not specified, the peer will be forced to use the value which you have
+specified.
+.TP
+.B ipxcp-max-configure \fIn
+Set the maximum number of IPXCP configure request frames which the
+system will send to \fIn\fR. The default is 10.
+.TP
+.B ipxcp-max-failure \fIn
+Set the maximum number of IPXCP NAK frames which the local system will
+send before it rejects the options. The default value is 3.
+.TP
+.B ipxcp-max-terminate \fIn
+Set the maximum nuber of IPXCP terminate request frames before the
+local system considers that the peer is not listening to them. The
+default value is 3.
+.TP
+.B kdebug \fIn
+Enable debugging code in the kernel-level PPP driver. The argument
+values depend on the specific kernel driver, but in general a value of
+1 will enable general kernel debug messages. (Note that these
+messages are usually only useful for debugging the kernel driver
+itself.) For the Linux 2.2.x kernel driver, the value is a sum of
+bits: 1 to
+enable general debug messages, 2 to request that the contents of
+received packets be printed, and 4 to request that the contents of
+transmitted packets be printed. On most systems, messages printed by
+the kernel are logged by syslog(1) to a file as directed in the
+/etc/syslog.conf configuration file.
+.TP
+.B ktune
+Enables pppd to alter kernel settings as appropriate. Under Linux,
+pppd will enable IP forwarding (i.e. set /proc/sys/net/ipv4/ip_forward
+to 1) if the \fIproxyarp\fR option is used, and will enable the
+dynamic IP address option (i.e. set /proc/sys/net/ipv4/ip_dynaddr to
+1) in demand mode if the local address changes.
+.TP
+.B lcp-echo-failure \fIn
+If this option is given, pppd will presume the peer to be dead
+if \fIn\fR LCP echo-requests are sent without receiving a valid LCP
+echo-reply. If this happens, pppd will terminate the
+connection. Use of this option requires a non-zero value for the
+\fIlcp-echo-interval\fR parameter. This option can be used to enable
+pppd to terminate after the physical connection has been broken
+(e.g., the modem has hung up) in situations where no hardware modem
+control lines are available.
+.TP
+.B lcp-echo-interval \fIn
+If this option is given, pppd will send an LCP echo-request frame to
+the peer every \fIn\fR seconds. Normally the peer should respond to
+the echo-request by sending an echo-reply. This option can be used
+with the \fIlcp-echo-failure\fR option to detect that the peer is no
+longer connected.
+.TP
+.B lcp-max-configure \fIn
+Set the maximum number of LCP configure-request transmissions to
+\fIn\fR (default 10).
+.TP
+.B lcp-max-failure \fIn
+Set the maximum number of LCP configure-NAKs returned before starting
+to send configure-Rejects instead to \fIn\fR (default 10).
+.TP
+.B lcp-max-terminate \fIn
+Set the maximum number of LCP terminate-request transmissions to
+\fIn\fR (default 3).
+.TP
+.B lcp-restart \fIn
+Set the LCP restart interval (retransmission timeout) to \fIn\fR
+seconds (default 3).
+.TP
+.B linkname \fIname\fR
+Sets the logical name of the link to \fIname\fR. Pppd will create a
+file named \fBppp-\fIname\fB.pid\fR in /var/run (or /etc/ppp on some
+systems) containing its process ID. This can be useful in determining
+which instance of pppd is responsible for the link to a given peer
+system. This is a privileged option.
+.TP
+.B local
+Don't use the modem control lines. With this option, pppd will ignore
+the state of the CD (Carrier Detect) signal from the modem and will
+not change the state of the DTR (Data Terminal Ready) signal.
+.TP
+.B logfd \fIn
+Send log messages to file descriptor \fIn\fR. Pppd will send log
+messages to at most one file or file descriptor (as well as sending
+the log messages to syslog), so this option and the \fBlogfile\fR
+option are mutually exclusive. The default is for pppd to send log
+messages to stdout (file descriptor 1), unless the serial port is
+already open on stdout.
+.TP
+.B logfile \fIfilename
+Append log messages to the file \fIfilename\fR (as well as sending the
+log messages to syslog). The file is opened with the privileges of
+the user who invoked pppd, in append mode.
+.TP
+.B login
+Use the system password database for authenticating the peer using
+PAP, and record the user in the system wtmp file. Note that the peer
+must have an entry in the /etc/ppp/pap-secrets file as well as the
+system password database to be allowed access.
+.TP
+.B maxconnect \fIn
+Terminate the connection when it has been available for network
+traffic for \fIn\fR seconds (i.e. \fIn\fR seconds after the first
+network control protocol comes up).
+.TP
+.B maxfail \fIn
+Terminate after \fIn\fR consecutive failed connection attempts. A
+value of 0 means no limit. The default value is 10.
+.TP
+.B modem
+Use the modem control lines. This option is the default. With this
+option, pppd will wait for the CD (Carrier Detect) signal from the
+modem to be asserted when opening the serial device (unless a connect
+script is specified), and it will drop the DTR (Data Terminal Ready)
+signal briefly when the connection is terminated and before executing
+the connect script. On Ultrix, this option implies hardware flow
+control, as for the \fIcrtscts\fR option.
+.TP
+.B mp
+Enables the use of PPP multilink; this is an alias for the `multilink'
+option. This option is currently only available under Linux.
+.TP
+.B mpshortseq
+Enables the use of short (12-bit) sequence numbers in multilink
+headers, as opposed to 24-bit sequence numbers. This option is only
+available under Linux, and only has any effect if multilink is
+enabled (see the multilink option).
+.TP
+.B mrru \fIn
+Sets the Maximum Reconstructed Receive Unit to \fIn\fR. The MRRU is
+the maximum size for a received packet on a multilink bundle, and is
+analogous to the MRU for the individual links. This option is
+currently only available under Linux, and only has any effect if
+multilink is enabled (see the multilink option).
+.TP
+.B ms-dns \fI<addr>
+If pppd is acting as a server for Microsoft Windows clients, this
+option allows pppd to supply one or two DNS (Domain Name Server)
+addresses to the clients. The first instance of this option specifies
+the primary DNS address; the second instance (if given) specifies the
+secondary DNS address. (This option was present in some older
+versions of pppd under the name \fBdns-addr\fR.)
+.TP
+.B ms-wins \fI<addr>
+If pppd is acting as a server for Microsoft Windows or "Samba"
+clients, this option allows pppd to supply one or two WINS (Windows
+Internet Name Services) server addresses to the clients. The first
+instance of this option specifies the primary WINS address; the second
+instance (if given) specifies the secondary WINS address.
+.TP
+.B multilink
+Enables the use of the PPP multilink protocol. If the peer also
+supports multilink, then this link can become part of a bundle between
+the local system and the peer. If there is an existing bundle to the
+peer, pppd will join this link to that bundle, otherwise pppd will
+create a new bundle. See the MULTILINK section below. This option is
+currently only available under Linux.
+.TP
+.B name \fIname
+Set the name of the local system for authentication purposes to
+\fIname\fR. This is a privileged option. With this option, pppd will
+use lines in the secrets files which have \fIname\fR as the second
+field when looking for a secret to use in authenticating the peer. In
+addition, unless overridden with the \fIuser\fR option, \fIname\fR
+will be used as the name to send to the peer when authenticating the
+local system to the peer. (Note that pppd does not append the domain
+name to \fIname\fR.)
+.TP
+.B netmask \fIn
+Set the interface netmask to \fIn\fR, a 32 bit netmask in "decimal dot"
+notation (e.g. 255.255.255.0). If this option is given, the value
+specified is ORed with the default netmask. The default netmask is
+chosen based on the negotiated remote IP address; it is the
+appropriate network mask for the class of the remote IP address, ORed
+with the netmasks for any non point-to-point network interfaces in the
+system which are on the same network. (Note: on some platforms, pppd
+will always use 255.255.255.255 for the netmask, if that is the only
+appropriate value for a point-to-point interface.)
+.TP
+.B noaccomp
+Disable Address/Control compression in both directions (send and
+receive).
+.TP
+.B noauth
+Do not require the peer to authenticate itself. This option is
+privileged.
+.TP
+.B nobsdcomp
+Disables BSD-Compress compression; \fBpppd\fR will not request or
+agree to compress packets using the BSD-Compress scheme.
+.TP
+.B noccp
+Disable CCP (Compression Control Protocol) negotiation. This option
+should only be required if the peer is buggy and gets confused by
+requests from pppd for CCP negotiation.
+.TP
+.B nocrtscts
+Disable hardware flow control (i.e. RTS/CTS) on the serial port.
+If neither the \fIcrtscts\fR nor the \fInocrtscts\fR nor the
+\fIcdtrcts\fR nor the \fInocdtrcts\fR option is given, the hardware
+flow control setting for the serial port is left unchanged.
+.TP
+.B nocdtrcts
+This option is a synonym for \fInocrtscts\fR. Either of these options will
+disable both forms of hardware flow control.
+.TP
+.B nodefaultroute
+Disable the \fIdefaultroute\fR option. The system administrator who
+wishes to prevent users from creating default routes with pppd
+can do so by placing this option in the /etc/ppp/options file.
+.TP
+.B nodeflate
+Disables Deflate compression; pppd will not request or agree to
+compress packets using the Deflate scheme.
+.TP
+.B nodetach
+Don't detach from the controlling terminal. Without this option, if a
+serial device other than the terminal on the standard input is
+specified, pppd will fork to become a background process.
+.TP
+.B noendpoint
+Disables pppd from sending an endpoint discriminator to the peer or
+accepting one from the peer (see the MULTILINK section below). This
+option should only be required if the peer is buggy.
+.TP
+.B noip
+Disable IPCP negotiation and IP communication. This option should
+only be required if the peer is buggy and gets confused by requests
+from pppd for IPCP negotiation.
+.TP
+.B noipv6
+Disable IPv6CP negotiation and IPv6 communication. This option should
+only be required if the peer is buggy and gets confused by requests
+from pppd for IPv6CP negotiation.
+.TP
+.B noipdefault
+Disables the default behaviour when no local IP address is specified,
+which is to determine (if possible) the local IP address from the
+hostname. With this option, the peer will have to supply the local IP
+address during IPCP negotiation (unless it specified explicitly on the
+command line or in an options file).
+.TP
+.B noipx
+Disable the IPXCP and IPX protocols. This option should only be
+required if the peer is buggy and gets confused by requests from pppd
+for IPXCP negotiation.
+.TP
+.B noktune
+Opposite of the \fIktune\fR option; disables pppd from changing system
+settings.
+.TP
+.B nolog
+Do not send log messages to a file or file descriptor. This option
+cancels the \fBlogfd\fR and \fBlogfile\fR options.
+.TP
+.B nomagic
+Disable magic number negotiation. With this option, pppd cannot
+detect a looped-back line. This option should only be needed if the
+peer is buggy.
+.TP
+.B nomp
+Disables the use of PPP multilink. This option is currently only
+available under Linux.
+.TP
+.B nompshortseq
+Disables the use of short (12-bit) sequence numbers in the PPP
+multilink protocol, forcing the use of 24-bit sequence numbers. This
+option is currently only available under Linux, and only has any
+effect if multilink is enabled.
+.TP
+.B nomultilink
+Disables the use of PPP multilink. This option is currently only
+available under Linux.
+.TP
+.B nopcomp
+Disable protocol field compression negotiation in both the receive and
+the transmit direction.
+.TP
+.B nopersist
+Exit once a connection has been made and terminated. This is the
+default unless the \fIpersist\fR or \fIdemand\fR option has been
+specified.
+.TP
+.B nopredictor1
+Do not accept or agree to Predictor-1 compression.
+.TP
+.B noproxyarp
+Disable the \fIproxyarp\fR option. The system administrator who
+wishes to prevent users from creating proxy ARP entries with pppd can
+do so by placing this option in the /etc/ppp/options file.
+.TP
+.B notty
+Normally, pppd requires a terminal device. With this option, pppd
+will allocate itself a pseudo-tty master/slave pair and use the slave
+as its terminal device. Pppd will create a child process to act as a
+`character shunt' to transfer characters between the pseudo-tty master
+and its standard input and output. Thus pppd will transmit characters
+on its standard output and receive characters on its standard input
+even if they are not terminal devices. This option increases the
+latency and CPU overhead of transferring data over the ppp interface
+as all of the characters sent and received must flow through the
+character shunt process. An explicit device name may not be given if
+this option is used.
+.TP
+.B novj
+Disable Van Jacobson style TCP/IP header compression in both the
+transmit and the receive direction.
+.TP
+.B novjccomp
+Disable the connection-ID compression option in Van Jacobson style
+TCP/IP header compression. With this option, pppd will not omit the
+connection-ID byte from Van Jacobson compressed TCP/IP headers, nor
+ask the peer to do so.
+.TP
+.B papcrypt
+Indicates that all secrets in the /etc/ppp/pap-secrets file which are
+used for checking the identity of the peer are encrypted, and thus
+pppd should not accept a password which, before encryption, is
+identical to the secret from the /etc/ppp/pap-secrets file.
+.TP
+.B pap-max-authreq \fIn
+Set the maximum number of PAP authenticate-request transmissions to
+\fIn\fR (default 10).
+.TP
+.B pap-restart \fIn
+Set the PAP restart interval (retransmission timeout) to \fIn\fR
+seconds (default 3).
+.TP
+.B pap-timeout \fIn
+Set the maximum time that pppd will wait for the peer to authenticate
+itself with PAP to \fIn\fR seconds (0 means no limit).
+.TP
+.B pass-filter \fIfilter-expression
+Specifies a packet filter to applied to data packets being sent or
+received to determine which packets should be allowed to pass.
+Packets which are rejected by the filter are silently discarded. This
+option can be used to prevent specific network daemons (such as
+routed) using up link bandwidth, or to provide a basic firewall
+capability.
+The \fIfilter-expression\fR syntax is as described for tcpdump(1),
+except that qualifiers which are inappropriate for a PPP link, such as
+\fBether\fR and \fBarp\fR, are not permitted. Generally the filter
+expression should be enclosed in single-quotes to prevent whitespace
+in the expression from being interpreted by the shell. Note that it
+is possible to apply different constraints to incoming and outgoing
+packets using the \fBinbound\fR and \fBoutbound\fR qualifiers. This
+option is currently only available under NetBSD, and then only if both
+the kernel and pppd were compiled with PPP_FILTER defined.
+.TP
+.B persist
+Do not exit after a connection is terminated; instead try to reopen
+the connection.
+.TP
+.B plugin \fIfilename
+Load the shared library object file \fIfilename\fR as a plugin. This
+is a privileged option.
+.TP
+.B predictor1
+Request that the peer compress frames that it sends using Predictor-1
+compression, and agree to compress transmitted frames with Predictor-1
+if requested. This option has no effect unless the kernel driver
+supports Predictor-1 compression.
+.TP
+.B privgroup \fIgroup-name
+Allows members of group \fIgroup-name\fR to use privileged options.
+This is a privileged option. Use of this option requires care as
+there is no guarantee that members of \fIgroup-name\fR cannot use pppd
+to become root themselves. Consider it equivalent to putting the
+members of \fIgroup-name\fR in the kmem or disk group.
+.TP
+.B proxyarp
+Add an entry to this system's ARP [Address Resolution Protocol] table
+with the IP address of the peer and the Ethernet address of this
+system. This will have the effect of making the peer appear to other
+systems to be on the local ethernet.
+.TP
+.B pty \fIscript
+Specifies that the command \fIscript\fR is to be used to communicate
+rather than a specific terminal device. Pppd will allocate itself a
+pseudo-tty master/slave pair and use the slave as its terminal
+device. The \fIscript\fR will be run in a child process with the
+pseudo-tty master as its standard input and output. An explicit
+device name may not be given if this option is used. (Note: if the
+\fIrecord\fR option is used in conjuction with the \fIpty\fR option,
+the child process will have pipes on its standard input and output.)
+.TP
+.B receive-all
+With this option, pppd will accept all control characters from the
+peer, including those marked in the receive asyncmap. Without this
+option, pppd will discard those characters as specified in RFC1662.
+This option should only be needed if the peer is buggy.
+.TP
+.B record \fIfilename
+Specifies that pppd should record all characters sent and received to
+a file named \fIfilename\fR. This file is opened in append mode,
+using the user's user-ID and permissions. This option is implemented
+using a pseudo-tty and a process to transfer characters between the
+pseudo-tty and the real serial device, so it will increase the latency
+and CPU overhead of transferring data over the ppp interface. The
+characters are stored in a tagged format with timestamps, which can be
+displayed in readable form using the pppdump(8) program.
+.TP
+.B remotename \fIname
+Set the assumed name of the remote system for authentication purposes
+to \fIname\fR.
+.TP
+.B refuse-chap
+With this option, pppd will not agree to authenticate itself to the
+peer using CHAP.
+.TP
+.B refuse-pap
+With this option, pppd will not agree to authenticate itself to the
+peer using PAP.
+.TP
+.B require-chap
+Require the peer to authenticate itself using CHAP [Challenge
+Handshake Authentication Protocol] authentication.
+.TP
+.B require-pap
+Require the peer to authenticate itself using PAP [Password
+Authentication Protocol] authentication.
+.TP
+.B show-password
+When logging the contents of PAP packets, this option causes pppd to
+show the password string in the log message.
+.TP
+.B silent
+With this option, pppd will not transmit LCP packets to initiate a
+connection until a valid LCP packet is received from the peer (as for
+the `passive' option with ancient versions of pppd).
+.TP
+.B sync
+Use synchronous HDLC serial encoding instead of asynchronous.
+The device used by pppd with this option must have sync support.
+Currently supports Microgate SyncLink adapters
+under Linux and FreeBSD 2.2.8 and later.
+.TP
+.B updetach
+With this option, pppd will detach from its controlling terminal once
+it has successfully established the ppp connection (to the point where
+the first network control protocol, usually the IP control protocol,
+has come up).
+.TP
+.B usehostname
+Enforce the use of the hostname (with domain name appended, if given)
+as the name of the local system for authentication purposes (overrides
+the \fIname\fR option). This option is not normally needed since the
+\fIname\fR option is privileged.
+.TP
+.B usepeerdns
+Ask the peer for up to 2 DNS server addresses. The addresses supplied
+by the peer (if any) are passed to the /etc/ppp/ip-up script in the
+environment variables DNS1 and DNS2. In addition, pppd will create an
+/etc/ppp/resolv.conf file containing one or two nameserver lines with
+the address(es) supplied by the peer.
+.TP
+.B user \fIname
+Sets the name used for authenticating the local system to the peer to
+\fIname\fR.
+.TP
+.B vj-max-slots \fIn
+Sets the number of connection slots to be used by the Van Jacobson
+TCP/IP header compression and decompression code to \fIn\fR, which
+must be between 2 and 16 (inclusive).
+.TP
+.B welcome \fIscript
+Run the executable or shell command specified by \fIscript\fR before
+initiating PPP negotiation, after the connect script (if any) has
+completed. A value for this option from a privileged source cannot be
+overridden by a non-privileged user.
+.TP
+.B xonxoff
+Use software flow control (i.e. XON/XOFF) to control the flow of data on
+the serial port.
+.SH OPTIONS FILES
+Options can be taken from files as well as the command line. Pppd
+reads options from the files /etc/ppp/options, ~/.ppprc and
+/etc/ppp/options.\fIttyname\fR (in that order) before processing the
+options on the command line. (In fact, the command-line options are
+scanned to find the terminal name before the options.\fIttyname\fR
+file is read.) In forming the name of the options.\fIttyname\fR file,
+the initial /dev/ is removed from the terminal name, and any remaining
+/ characters are replaced with dots.
+.PP
+An options file is parsed into a series of words, delimited by
+whitespace. Whitespace can be included in a word by enclosing the
+word in double-quotes ("). A backslash (\\) quotes the following character.
+A hash (#) starts a comment, which continues until the end of the
+line. There is no restriction on using the \fIfile\fR or \fIcall\fR
+options within an options file.
+.SH SECURITY
+.I pppd
+provides system administrators with sufficient access control that PPP
+access to a server machine can be provided to legitimate users without
+fear of compromising the security of the server or the network it's
+on. This control is provided through restrictions on which IP
+addresses the peer may use, based on its authenticated identity (if
+any), and through restrictions on which options a non-privileged user
+may use. Several of pppd's options are privileged, in particular
+those which permit potentially insecure configurations; these options
+are only accepted in files which are under the control of the system
+administrator, or if pppd is being run by root.
+.PP
+The default behaviour of pppd is to allow an unauthenticated peer to
+use a given IP address only if the system does not already have a
+route to that IP address. For example, a system with a
+permanent connection to the wider internet will normally have a
+default route, and thus all peers will have to authenticate themselves
+in order to set up a connection. On such a system, the \fIauth\fR
+option is the default. On the other hand, a system where the
+PPP link is the only connection to the internet will not normally have
+a default route, so the peer will be able to use almost any IP address
+without authenticating itself.
+.PP
+As indicated above, some security-sensitive options are privileged,
+which means that they may not be used by an ordinary non-privileged
+user running a setuid-root pppd, either on the command line, in the
+user's ~/.ppprc file, or in an options file read using the \fIfile\fR
+option. Privileged options may be used in /etc/ppp/options file or in
+an options file read using the \fIcall\fR option. If pppd is being
+run by the root user, privileged options can be used without
+restriction.
+.PP
+When opening the device, pppd uses either the invoking user's user ID
+or the root UID (that is, 0), depending on whether the device name was
+specified by the user or the system administrator. If the device name
+comes from a privileged source, that is, /etc/ppp/options or an
+options file read using the \fIcall\fR option, pppd uses full root
+privileges when opening the device. Thus, by creating an appropriate
+file under /etc/ppp/peers, the system administrator can allow users to
+establish a ppp connection via a device which they would not normally
+have permission to access. Otherwise pppd uses the invoking user's
+real UID when opening the device.
+.SH AUTHENTICATION
+Authentication is the process whereby one peer convinces the other of
+its identity. This involves the first peer sending its name to the
+other, together with some kind of secret information which could only
+come from the genuine authorized user of that name. In such an
+exchange, we will call the first peer the "client" and the other the
+"server". The client has a name by which it identifies itself to the
+server, and the server also has a name by which it identifies itself
+to the client. Generally the genuine client shares some secret (or
+password) with the server, and authenticates itself by proving that it
+knows that secret. Very often, the names used for authentication
+correspond to the internet hostnames of the peers, but this is not
+essential.
+.LP
+At present, pppd supports two authentication protocols: the Password
+Authentication Protocol (PAP) and the Challenge Handshake
+Authentication Protocol (CHAP). PAP involves the client sending its
+name and a cleartext password to the server to authenticate itself.
+In contrast, the server initiates the CHAP authentication exchange by
+sending a challenge to the client (the challenge packet includes the
+server's name). The client must respond with a response which
+includes its name plus a hash value derived from the shared secret and
+the challenge, in order to prove that it knows the secret.
+.LP
+The PPP protocol, being symmetrical, allows both peers to require the
+other to authenticate itself. In that case, two separate and
+independent authentication exchanges will occur. The two exchanges
+could use different authentication protocols, and in principle,
+different names could be used in the two exchanges.
+.LP
+The default behaviour of pppd is to agree to authenticate if
+requested, and to not require authentication from the peer. However,
+pppd will not agree to authenticate itself with a particular protocol
+if it has no secrets which could be used to do so.
+.LP
+Pppd stores secrets for use in authentication in secrets
+files (/etc/ppp/pap-secrets for PAP, /etc/ppp/chap-secrets for CHAP).
+Both secrets files have the same format. The secrets files can
+contain secrets for pppd to use in authenticating itself to other
+systems, as well as secrets for pppd to use when authenticating other
+systems to itself.
+.LP
+Each line in a secrets file contains one secret. A given secret is
+specific to a particular combination of client and server - it can
+only be used by that client to authenticate itself to that server.
+Thus each line in a secrets file has at least 3 fields: the name of
+the client, the name of the server, and the secret. These fields may
+be followed by a list of the IP addresses that the specified client
+may use when connecting to the specified server.
+.LP
+A secrets file is parsed into words as for a options file, so the
+client name, server name and secrets fields must each be one word,
+with any embedded spaces or other special characters quoted or
+escaped. Note that case is significant in the client and server names
+and in the secret.
+.LP
+If the secret starts with an `@', what follows is assumed to be the
+name of a file from which to read the secret. A "*" as the client or
+server name matches any name. When selecting a secret, pppd takes the
+best match, i.e. the match with the fewest wildcards.
+.LP
+Any following words on the same line are taken to be a list of
+acceptable IP addresses for that client. If there are only 3 words on
+the line, or if the first word is "-", then all IP addresses are
+disallowed. To allow any address, use "*". A word starting with "!"
+indicates that the specified address is \fInot\fR acceptable. An
+address may be followed by "/" and a number \fIn\fR, to indicate a
+whole subnet, i.e. all addresses which have the same value in the most
+significant \fIn\fR bits. In this form, the address may be followed
+by a plus sign ("+") to indicate that one address from the subnet is
+authorized, based on the ppp network interface unit number in use.
+In this case, the host part of the address will be set to the unit
+number plus one.
+.LP
+Thus a secrets file contains both secrets for use in authenticating
+other hosts, plus secrets which we use for authenticating ourselves to
+others. When pppd is authenticating the peer (checking the peer's
+identity), it chooses a secret with the peer's name in the first
+field and the name of the local system in the second field. The
+name of the local system defaults to the hostname, with the domain
+name appended if the \fIdomain\fR option is used. This default can be
+overridden with the \fIname\fR option, except when the
+\fIusehostname\fR option is used.
+.LP
+When pppd is choosing a secret to use in authenticating itself to the
+peer, it first determines what name it is going to use to identify
+itself to the peer. This name can be specified by the user with the
+\fIuser\fR option. If this option is not used, the name defaults to
+the name of the local system, determined as described in the previous
+paragraph. Then pppd looks for a secret with this name in the first
+field and the peer's name in the second field. Pppd will know the
+name of the peer if CHAP authentication is being used, because the
+peer will have sent it in the challenge packet. However, if PAP is being
+used, pppd will have to determine the peer's name from the options
+specified by the user. The user can specify the peer's name directly
+with the \fIremotename\fR option. Otherwise, if the remote IP address
+was specified by a name (rather than in numeric form), that name will
+be used as the peer's name. Failing that, pppd will use the null
+string as the peer's name.
+.LP
+When authenticating the peer with PAP, the supplied password is first
+compared with the secret from the secrets file. If the password
+doesn't match the secret, the password is encrypted using crypt() and
+checked against the secret again. Thus secrets for authenticating the
+peer can be stored in encrypted form if desired. If the
+\fIpapcrypt\fR option is given, the first (unencrypted) comparison is
+omitted, for better security.
+.LP
+Furthermore, if the \fIlogin\fR option was specified, the username and
+password are also checked against the system password database. Thus,
+the system administrator can set up the pap-secrets file to allow PPP
+access only to certain users, and to restrict the set of IP addresses
+that each user can use. Typically, when using the \fIlogin\fR option,
+the secret in /etc/ppp/pap-secrets would be "", which will match any
+password supplied by the peer. This avoids the need to have the same
+secret in two places.
+.LP
+Authentication must be satisfactorily completed before IPCP (or any
+other Network Control Protocol) can be started. If the peer is
+required to authenticate itself, and fails to do so, pppd will
+terminated the link (by closing LCP). If IPCP negotiates an
+unacceptable IP address for the remote host, IPCP will be closed. IP
+packets can only be sent or received when IPCP is open.
+.LP
+In some cases it is desirable to allow some hosts which can't
+authenticate themselves to connect and use one of a restricted set of
+IP addresses, even when the local host generally requires
+authentication. If the peer refuses to authenticate itself when
+requested, pppd takes that as equivalent to authenticating with PAP
+using the empty string for the username and password. Thus, by adding
+a line to the pap-secrets file which specifies the empty string for
+the client and password, it is possible to allow restricted access to
+hosts which refuse to authenticate themselves.
+.SH ROUTING
+.LP
+When IPCP negotiation is completed successfully, pppd will inform the
+kernel of the local and remote IP addresses for the ppp interface.
+This is sufficient to create a host route to the remote end of the
+link, which will enable the peers to exchange IP packets.
+Communication with other machines generally requires further
+modification to routing tables and/or ARP (Address Resolution
+Protocol) tables. In most cases the \fIdefaultroute\fR and/or
+\fIproxyarp\fR options are sufficient for this, but in some cases
+further intervention is required. The /etc/ppp/ip-up script can be
+used for this.
+.LP
+Sometimes it is desirable to add a default route through the remote
+host, as in the case of a machine whose only connection to the
+Internet is through the ppp interface. The \fIdefaultroute\fR option
+causes pppd to create such a default route when IPCP comes up, and
+delete it when the link is terminated.
+.LP
+In some cases it is desirable to use proxy ARP, for example on a
+server machine connected to a LAN, in order to allow other hosts to
+communicate with the remote host. The \fIproxyarp\fR option causes
+pppd to look for a network interface on the same subnet as the remote
+host (an interface supporting broadcast and ARP, which is up and not a
+point-to-point or loopback interface). If found, pppd creates a
+permanent, published ARP entry with the IP address of the remote host
+and the hardware address of the network interface found.
+.LP
+When the \fIdemand\fR option is used, the interface IP addresses have
+already been set at the point when IPCP comes up. If pppd has not
+been able to negotiate the same addresses that it used to configure
+the interface (for example when the peer is an ISP that uses dynamic
+IP address assignment), pppd has to change the interface IP addresses
+to the negotiated addresses. This may disrupt existing connections,
+and the use of demand dialling with peers that do dynamic IP address
+assignment is not recommended.
+.SH MULTILINK
+Multilink PPP provides the capability to combine two or more PPP links
+between a pair of machines into a single `bundle', which appears as a
+single virtual PPP link which has the combined bandwidth of the
+individual links. Currently, multilink PPP is only supported under
+Linux.
+.LP
+Pppd detects that the link it is controlling is connected to the same
+peer as another link using the peer's endpoint discriminator and the
+authenticated identity of the peer (if it authenticates itself). The
+endpoint discriminator is a block of data which is hopefully unique
+for each peer. Several types of data can be used, including
+locally-assigned strings of bytes, IP addresses, MAC addresses,
+randomly strings of bytes, or E-164 phone numbers. The endpoint
+discriminator sent to the peer by pppd can be set using the endpoint
+option.
+.LP
+In circumstances the peer may send no endpoint discriminator or a
+non-unique value. The optional bundle option adds an extra string
+which is added to the peer's endpoint discriminator and authenticated
+identity when matching up links to be joined together in a bundle.
+The bundle option can also be used to allow the establishment of
+multiple bundles between the local system and the peer. Pppd uses a
+TDB database in /var/run/pppd.tdb to match up links.
+.LP
+Assuming that multilink is enabled and the peer is willing to
+negotiate multilink, then when pppd is invoked to bring up the first
+link to the peer, it will detect that no other link is connected to
+the peer and create a new bundle, that is, another ppp network
+interface unit. When another pppd is invoked to bring up another link
+to the peer, it will detect the existing bundle and join its link to
+it. Currently, if the first pppd terminates (for example, because of
+a hangup or a received signal) the bundle is destroyed.
+.SH EXAMPLES
+.LP
+The following examples assume that the /etc/ppp/options file contains
+the \fIauth\fR option (as in the default /etc/ppp/options file in the
+ppp distribution).
+.LP
+Probably the most common use of pppd is to dial out to an ISP. This
+can be done with a command such as
+.IP
+pppd call isp
+.LP
+where the /etc/ppp/peers/isp file is set up by the system
+administrator to contain something like this:
+.IP
+ttyS0 19200 crtscts
+.br
+connect '/usr/sbin/chat -v -f /etc/ppp/chat-isp'
+.br
+noauth
+.LP
+In this example, we are using chat to dial the ISP's modem and go
+through any logon sequence required. The /etc/ppp/chat-isp file
+contains the script used by chat; it could for example contain
+something like this:
+.IP
+ABORT "NO CARRIER"
+.br
+ABORT "NO DIALTONE"
+.br
+ABORT "ERROR"
+.br
+ABORT "NO ANSWER"
+.br
+ABORT "BUSY"
+.br
+ABORT "Username/Password Incorrect"
+.br
+"" "at"
+.br
+OK "at&d0&c1"
+.br
+OK "atdt2468135"
+.br
+"name:" "^Umyuserid"
+.br
+"word:" "\\qmypassword"
+.br
+"ispts" "\\q^Uppp"
+.br
+"~-^Uppp-~"
+.LP
+See the chat(8) man page for details of chat scripts.
+.LP
+Pppd can also be used to provide a dial-in ppp service for users. If
+the users already have login accounts, the simplest way to set up the
+ppp service is to let the users log in to their accounts and run pppd
+(installed setuid-root) with a command such as
+.IP
+pppd proxyarp
+.LP
+To allow a user to use the PPP facilities, you need to allocate an IP
+address for that user's machine and create an entry in
+/etc/ppp/pap-secrets or /etc/ppp/chap-secrets (depending on which
+authentication method the PPP implementation on the user's machine
+supports), so that the user's
+machine can authenticate itself. For example, if Joe has a machine
+called "joespc" which is to be allowed to dial in to the machine
+called "server" and use the IP address joespc.my.net, you would add an
+entry like this to /etc/ppp/pap-secrets or /etc/ppp/chap-secrets:
+.IP
+joespc server "joe's secret" joespc.my.net
+.LP
+Alternatively, you can create a username called (for example) "ppp",
+whose login shell is pppd and whose home directory is /etc/ppp.
+Options to be used when pppd is run this way can be put in
+/etc/ppp/.ppprc.
+.LP
+If your serial connection is any more complicated than a piece of
+wire, you may need to arrange for some control characters to be
+escaped. In particular, it is often useful to escape XON (^Q) and
+XOFF (^S), using \fIasyncmap a0000\fR. If the path includes a telnet,
+you probably should escape ^] as well (\fIasyncmap 200a0000\fR). If
+the path includes an rlogin, you will need to use the \fIescape ff\fR
+option on the end which is running the rlogin client, since many
+rlogin implementations are not transparent; they will remove the
+sequence [0xff, 0xff, 0x73, 0x73, followed by any 8 bytes] from the
+stream.
+.SH DIAGNOSTICS
+.LP
+Messages are sent to the syslog daemon using facility LOG_DAEMON.
+(This can be overriden by recompiling pppd with the macro
+LOG_PPP defined as the desired facility.) In order to see the error
+and debug messages, you will need to edit your /etc/syslog.conf file
+to direct the messages to the desired output device or file.
+.LP
+The \fIdebug\fR option causes the contents of all control packets sent
+or received to be logged, that is, all LCP, PAP, CHAP or IPCP packets.
+This can be useful if the PPP negotiation does not succeed or if
+authentication fails.
+If debugging is enabled at compile time, the \fIdebug\fR option also
+causes other debugging messages to be logged.
+.LP
+Debugging can also be enabled or disabled by sending a SIGUSR1 signal
+to the pppd process. This signal acts as a toggle.
+.SH EXIT STATUS
+The exit status of pppd is set to indicate whether any error was
+detected, or the reason for the link being terminated. The values
+used are:
+.TP
+.B 0
+Pppd has detached, or otherwise the connection was successfully
+established and terminated at the peer's request.
+.TP
+.B 1
+An immediately fatal error of some kind occurred, such as an essential
+system call failing, or running out of virtual memory.
+.TP
+.B 2
+An error was detected in processing the options given, such as two
+mutually exclusive options being used.
+.TP
+.B 3
+Pppd is not setuid-root and the invoking user is not root.
+.TP
+.B 4
+The kernel does not support PPP, for example, the PPP kernel driver is
+not included or cannot be loaded.
+.TP
+.B 5
+Pppd terminated because it was sent a SIGINT, SIGTERM or SIGHUP
+signal.
+.TP
+.B 6
+The serial port could not be locked.
+.TP
+.B 7
+The serial port could not be opened.
+.TP
+.B 8
+The connect script failed (returned a non-zero exit status).
+.TP
+.B 9
+The command specified as the argument to the \fIpty\fR option could
+not be run.
+.TP
+.B 10
+The PPP negotiation failed, that is, it didn't reach the point where
+at least one network protocol (e.g. IP) was running.
+.TP
+.B 11
+The peer system failed (or refused) to authenticate itself.
+.TP
+.B 12
+The link was established successfully and terminated because it was
+idle.
+.TP
+.B 13
+The link was established successfully and terminated because the
+connect time limit was reached.
+.TP
+.B 14
+Callback was negotiated and an incoming call should arrive shortly.
+.TP
+.B 15
+The link was terminated because the peer is not responding to echo
+requests.
+.TP
+.B 16
+The link was terminated by the modem hanging up.
+.TP
+.B 17
+The PPP negotiation failed because serial loopback was detected.
+.TP
+.B 18
+The init script failed (returned a non-zero exit status).
+.TP
+.B 19
+We failed to authenticate ourselves to the peer.
+.SH SCRIPTS
+Pppd invokes scripts at various stages in its processing which can be
+used to perform site-specific ancillary processing. These scripts are
+usually shell scripts, but could be executable code files instead.
+Pppd does not wait for the scripts to finish. The scripts are
+executed as root (with the real and effective user-id set to 0), so
+that they can do things such as update routing tables or run
+privileged daemons. Be careful that the contents of these scripts do
+not compromise your system's security. Pppd runs the scripts with
+standard input, output and error redirected to /dev/null, and with an
+environment that is empty except for some environment variables that
+give information about the link. The environment variables that pppd
+sets are:
+.TP
+.B DEVICE
+The name of the serial tty device being used.
+.TP
+.B IFNAME
+The name of the network interface being used.
+.TP
+.B IPLOCAL
+The IP address for the local end of the link. This is only set when
+IPCP has come up.
+.TP
+.B IPREMOTE
+The IP address for the remote end of the link. This is only set when
+IPCP has come up.
+.TP
+.B PEERNAME
+The authenticated name of the peer. This is only set if the peer
+authenticates itself.
+.TP
+.B SPEED
+The baud rate of the tty device.
+.TP
+.B ORIG_UID
+The real user-id of the user who invoked pppd.
+.TP
+.B PPPLOGNAME
+The username of the real user-id that invoked pppd. This is always set.
+.P
+For the ip-down and auth-down scripts, pppd also sets the following
+variables giving statistics for the connection:
+.TP
+.B CONNECT_TIME
+The number of seconds from when the PPP negotiation started until the
+connection was terminated.
+.TP
+.B BYTES_SENT
+The number of bytes sent (at the level of the serial port) during the
+connection.
+.TP
+.B BYTES_RCVD
+The number of bytes received (at the level of the serial port) during
+the connection.
+.TP
+.B LINKNAME
+The logical name of the link, set with the \fIlinkname\fR option.
+.P
+Pppd invokes the following scripts, if they exist. It is not an error
+if they don't exist.
+.TP
+.B /etc/ppp/auth-up
+A program or script which is executed after the remote system
+successfully authenticates itself. It is executed with the parameters
+.IP
+\fIinterface-name peer-name user-name tty-device speed\fR
+.IP
+Note that this script is not executed if the peer doesn't authenticate
+itself, for example when the \fInoauth\fR option is used.
+.TP
+.B /etc/ppp/auth-down
+A program or script which is executed when the link goes down, if
+/etc/ppp/auth-up was previously executed. It is executed in the same
+manner with the same parameters as /etc/ppp/auth-up.
+.TP
+.B /etc/ppp/ip-up
+A program or script which is executed when the link is available for
+sending and receiving IP packets (that is, IPCP has come up). It is
+executed with the parameters
+.IP
+\fIinterface-name tty-device speed local-IP-address
+remote-IP-address ipparam\fR
+.TP
+.B /etc/ppp/ip-down
+A program or script which is executed when the link is no longer
+available for sending and receiving IP packets. This script can be
+used for undoing the effects of the /etc/ppp/ip-up script. It is
+invoked in the same manner and with the same parameters as the ip-up
+script.
+.TP
+.B /etc/ppp/ipv6-up
+Like /etc/ppp/ip-up, except that it is executed when the link is available
+for sending and receiving IPv6 packets. It is executed with the parameters
+.IP
+\fIinterface-name tty-device speed local-link-local-address
+remote-link-local-address ipparam\fR
+.TP
+.B /etc/ppp/ipv6-down
+Similar to /etc/ppp/ip-down, but it is executed when IPv6 packets can no
+longer be transmitted on the link. It is executed with the same parameters
+as the ipv6-up script.
+.TP
+.B /etc/ppp/ipx-up
+A program or script which is executed when the link is available for
+sending and receiving IPX packets (that is, IPXCP has come up). It is
+executed with the parameters
+.IP
+\fIinterface-name tty-device speed network-number local-IPX-node-address
+remote-IPX-node-address local-IPX-routing-protocol remote-IPX-routing-protocol
+local-IPX-router-name remote-IPX-router-name ipparam pppd-pid\fR
+.IP
+The local-IPX-routing-protocol and remote-IPX-routing-protocol field
+may be one of the following:
+.IP
+NONE to indicate that there is no routing protocol
+.br
+RIP to indicate that RIP/SAP should be used
+.br
+NLSP to indicate that Novell NLSP should be used
+.br
+RIP NLSP to indicate that both RIP/SAP and NLSP should be used
+.TP
+.B /etc/ppp/ipx-down
+A program or script which is executed when the link is no longer
+available for sending and receiving IPX packets. This script can be
+used for undoing the effects of the /etc/ppp/ipx-up script. It is
+invoked in the same manner and with the same parameters as the ipx-up
+script.
+.SH FILES
+.TP
+.B /var/run/ppp\fIn\fB.pid \fR(BSD or Linux), \fB/etc/ppp/ppp\fIn\fB.pid \fR(others)
+Process-ID for pppd process on ppp interface unit \fIn\fR.
+.TP
+.B /var/run/ppp-\fIname\fB.pid \fR(BSD or Linux), \fB/etc/ppp/ppp-\fIname\fB.pid \fR(others)
+Process-ID for pppd process for logical link \fIname\fR (see the
+\fIlinkname\fR option).
+.TP
+.B /etc/ppp/pap-secrets
+Usernames, passwords and IP addresses for PAP authentication. This
+file should be owned by root and not readable or writable by any other
+user. Pppd will log a warning if this is not the case.
+.TP
+.B /etc/ppp/chap-secrets
+Names, secrets and IP addresses for CHAP authentication. As for
+/etc/ppp/pap-secrets, this file should be owned by root and not
+readable or writable by any other user. Pppd will log a warning if
+this is not the case.
+.TP
+.B /etc/ppp/options
+System default options for pppd, read before user default options or
+command-line options.
+.TP
+.B ~/.ppprc
+User default options, read before /etc/ppp/options.\fIttyname\fR.
+.TP
+.B /etc/ppp/options.\fIttyname
+System default options for the serial port being used, read after
+~/.ppprc. In forming the \fIttyname\fR part of this
+filename, an initial /dev/ is stripped from the port name (if
+present), and any slashes in the remaining part are converted to
+dots.
+.TP
+.B /etc/ppp/peers
+A directory containing options files which may contain privileged
+options, even if pppd was invoked by a user other than root. The
+system administrator can create options files in this directory to
+permit non-privileged users to dial out without requiring the peer to
+authenticate, but only to certain trusted peers.
+.SH SEE ALSO
+.TP
+.B RFC1144
+Jacobson, V.
+\fICompressing TCP/IP headers for low-speed serial links.\fR
+February 1990.
+.TP
+.B RFC1321
+Rivest, R.
+.I The MD5 Message-Digest Algorithm.
+April 1992.
+.TP
+.B RFC1332
+McGregor, G.
+.I PPP Internet Protocol Control Protocol (IPCP).
+May 1992.
+.TP
+.B RFC1334
+Lloyd, B.; Simpson, W.A.
+.I PPP authentication protocols.
+October 1992.
+.TP
+.B RFC1661
+Simpson, W.A.
+.I The Point\-to\-Point Protocol (PPP).
+July 1994.
+.TP
+.B RFC1662
+Simpson, W.A.
+.I PPP in HDLC-like Framing.
+July 1994.
+.TP
+.B RFC2472
+Haskin, D.
+.I IP Version 6 over PPP
+December 1998.
+.SH NOTES
+The following signals have the specified effect when sent to pppd.
+.TP
+.B SIGINT, SIGTERM
+These signals cause pppd to terminate the link (by closing LCP),
+restore the serial device settings, and exit.
+.TP
+.B SIGHUP
+This signal causes pppd to terminate the link, restore the serial
+device settings, and close the serial device. If the \fIpersist\fR or
+\fIdemand\fR option has been specified, pppd will try to reopen the
+serial device and start another connection (after the holdoff period).
+Otherwise pppd will exit. If this signal is received during the
+holdoff period, it causes pppd to end the holdoff period immediately.
+.TP
+.B SIGUSR1
+This signal toggles the state of the \fIdebug\fR option.
+.TP
+.B SIGUSR2
+This signal causes pppd to renegotiate compression. This can be
+useful to re-enable compression after it has been disabled as a result
+of a fatal decompression error. (Fatal decompression errors generally
+indicate a bug in one or other implementation.)
+
+.SH AUTHORS
+Paul Mackerras (Paul.Mackerras@cs.anu.edu.au), based on earlier work by
+Drew Perkins,
+Brad Clements,
+Karl Fox,
+Greg Christy,
+and
+Brad Parker.
diff --git a/mdk-stage1/ppp/pppd/pppd.h b/mdk-stage1/ppp/pppd/pppd.h
new file mode 100644
index 000000000..158756220
--- /dev/null
+++ b/mdk-stage1/ppp/pppd/pppd.h
@@ -0,0 +1,787 @@
+/*
+ * pppd.h - PPP daemon global declarations.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id: pppd.h 195720 2001-06-11 11:44:34Z gc $
+ */
+
+/*
+ * TODO:
+ */
+
+#ifndef __PPPD_H__
+#define __PPPD_H__
+
+#include <stdio.h> /* for FILE */
+#include <limits.h> /* for NGROUPS_MAX */
+#include <sys/param.h> /* for MAXPATHLEN and BSD4_4, if defined */
+#include <sys/types.h> /* for u_int32_t, if defined */
+#include <sys/time.h> /* for struct timeval */
+#include <net/ppp_defs.h>
+#include "patchlevel.h"
+
+#if defined(__STDC__)
+#include <stdarg.h>
+#define __V(x) x
+#else
+#include <varargs.h>
+#define __V(x) (va_alist) va_dcl
+#define const
+#define volatile
+#endif
+
+#ifdef INET6
+#include "eui64.h"
+#endif
+
+/*
+ * Limits.
+ */
+
+#define NUM_PPP 1 /* One PPP interface supported (per process) */
+#define MAXWORDLEN 1024 /* max length of word in file (incl null) */
+#define MAXARGS 1 /* max # args to a command */
+#define MAXNAMELEN 256 /* max length of hostname or name for auth */
+#define MAXSECRETLEN 256 /* max length of password or secret */
+
+/*
+ * Option descriptor structure.
+ */
+
+typedef unsigned char bool;
+
+enum opt_type {
+ o_special_noarg = 0,
+ o_special = 1,
+ o_bool,
+ o_int,
+ o_uint32,
+ o_string,
+ o_wild,
+};
+
+typedef struct {
+ char *name; /* name of the option */
+ enum opt_type type;
+ void *addr;
+ char *description;
+ int flags;
+ void *addr2;
+ int upper_limit;
+ int lower_limit;
+ const char *source;
+ short int priority;
+ short int winner;
+} option_t;
+
+/* Values for flags */
+#define OPT_VALUE 0xff /* mask for presupplied value */
+#define OPT_HEX 0x100 /* int option is in hex */
+#define OPT_NOARG 0x200 /* option doesn't take argument */
+#define OPT_OR 0x400 /* OR in argument to value */
+#define OPT_INC 0x800 /* increment value */
+#define OPT_PRIV 0x1000 /* privileged option */
+#define OPT_STATIC 0x2000 /* string option goes into static array */
+#define OPT_LLIMIT 0x4000 /* check value against lower limit */
+#define OPT_ULIMIT 0x8000 /* check value against upper limit */
+#define OPT_LIMITS (OPT_LLIMIT|OPT_ULIMIT)
+#define OPT_ZEROOK 0x10000 /* 0 value is OK even if not within limits */
+#define OPT_HIDE 0x10000 /* for o_string, print value as ?????? */
+#define OPT_A2LIST 0x10000 /* for o_special, keep list of values */
+#define OPT_NOINCR 0x20000 /* value mustn't be increased */
+#define OPT_ZEROINF 0x40000 /* with OPT_NOINCR, 0 == infinity */
+#define OPT_PRIO 0x80000 /* process option priorities for this option */
+#define OPT_PRIOSUB 0x100000 /* subsidiary member of priority group */
+#define OPT_ALIAS 0x200000 /* option is alias for previous option */
+#define OPT_A2COPY 0x400000 /* addr2 -> second location to rcv value */
+#define OPT_ENABLE 0x800000 /* use *addr2 as enable for option */
+#define OPT_A2CLR 0x1000000 /* clear *(bool *)addr2 */
+#define OPT_PRIVFIX 0x2000000 /* user can't override if set by root */
+#define OPT_INITONLY 0x4000000 /* option can only be set in init phase */
+#define OPT_DEVEQUIV 0x8000000 /* equiv to device name */
+#define OPT_DEVNAM (OPT_INITONLY | OPT_DEVEQUIV)
+#define OPT_A2PRINTER 0x10000000 /* *addr2 is a fn for printing option */
+#define OPT_A2STRVAL 0x20000000 /* *addr2 points to current string value */
+#define OPT_NOPRINT 0x40000000 /* don't print this option at all */
+
+#define OPT_VAL(x) ((x) & OPT_VALUE)
+
+/* Values for priority */
+#define OPRIO_DEFAULT 0 /* a default value */
+#define OPRIO_CFGFILE 1 /* value from a configuration file */
+#define OPRIO_CMDLINE 2 /* value from the command line */
+#define OPRIO_SECFILE 3 /* value from options in a secrets file */
+#define OPRIO_ROOT 100 /* added to priority if OPT_PRIVFIX && root */
+
+#ifndef GIDSET_TYPE
+#define GIDSET_TYPE gid_t
+#endif
+
+/* Structure representing a list of permitted IP addresses. */
+struct permitted_ip {
+ int permit; /* 1 = permit, 0 = forbid */
+ u_int32_t base; /* match if (addr & mask) == base */
+ u_int32_t mask; /* base and mask are in network byte order */
+};
+
+/*
+ * Unfortunately, the linux kernel driver uses a different structure
+ * for statistics from the rest of the ports.
+ * This structure serves as a common representation for the bits
+ * pppd needs.
+ */
+struct pppd_stats {
+ unsigned int bytes_in;
+ unsigned int bytes_out;
+};
+
+/* Used for storing a sequence of words. Usually malloced. */
+struct wordlist {
+ struct wordlist *next;
+ char *word;
+};
+
+/* An endpoint discriminator, used with multilink. */
+#define MAX_ENDP_LEN 20 /* maximum length of discriminator value */
+struct epdisc {
+ unsigned char class;
+ unsigned char length;
+ unsigned char value[MAX_ENDP_LEN];
+};
+
+/* values for epdisc.class */
+#define EPD_NULL 0 /* null discriminator, no data */
+#define EPD_LOCAL 1
+#define EPD_IP 2
+#define EPD_MAC 3
+#define EPD_MAGIC 4
+#define EPD_PHONENUM 5
+
+typedef void (*notify_func) __P((void *, int));
+
+struct notifier {
+ struct notifier *next;
+ notify_func func;
+ void *arg;
+};
+
+/*
+ * Global variables.
+ */
+
+extern int hungup; /* Physical layer has disconnected */
+extern int ifunit; /* Interface unit number */
+extern char ifname[]; /* Interface name */
+extern char hostname[]; /* Our hostname */
+extern u_char outpacket_buf[]; /* Buffer for outgoing packets */
+extern int phase; /* Current state of link - see values below */
+extern int baud_rate; /* Current link speed in bits/sec */
+extern char *progname; /* Name of this program */
+extern int redirect_stderr;/* Connector's stderr should go to file */
+extern char peer_authname[];/* Authenticated name of peer */
+extern int privileged; /* We were run by real-uid root */
+extern int need_holdoff; /* Need holdoff period after link terminates */
+extern char **script_env; /* Environment variables for scripts */
+extern int detached; /* Have detached from controlling tty */
+extern GIDSET_TYPE groups[NGROUPS_MAX]; /* groups the user is in */
+extern int ngroups; /* How many groups valid in groups */
+extern struct pppd_stats link_stats; /* byte/packet counts etc. for link */
+extern int link_stats_valid; /* set if link_stats is valid */
+extern int link_connect_time; /* time the link was up for */
+extern int using_pty; /* using pty as device (notty or pty opt.) */
+extern int log_to_fd; /* logging to this fd as well as syslog */
+extern bool log_default; /* log_to_fd is default (stdout) */
+extern char *no_ppp_msg; /* message to print if ppp not in kernel */
+extern volatile int status; /* exit status for pppd */
+extern bool devnam_fixed; /* can no longer change devnam */
+extern int unsuccess; /* # unsuccessful connection attempts */
+extern int do_callback; /* set if we want to do callback next */
+extern int doing_callback; /* set if this is a callback */
+extern char ppp_devnam[MAXPATHLEN];
+extern struct notifier *pidchange; /* for notifications of pid changing */
+extern struct notifier *phasechange; /* for notifications of phase changes */
+extern struct notifier *exitnotify; /* for notification that we're exiting */
+extern struct notifier *sigreceived; /* notification of received signal */
+extern int listen_time; /* time to listen first (ms) */
+
+/* Values for do_callback and doing_callback */
+#define CALLBACK_DIALIN 1 /* we are expecting the call back */
+#define CALLBACK_DIALOUT 2 /* we are dialling out to call back */
+
+/*
+ * Variables set by command-line options.
+ */
+
+extern int debug; /* Debug flag */
+extern int kdebugflag; /* Tell kernel to print debug messages */
+extern int default_device; /* Using /dev/tty or equivalent */
+extern char devnam[MAXPATHLEN]; /* Device name */
+extern int crtscts; /* Use hardware flow control */
+extern bool modem; /* Use modem control lines */
+extern int inspeed; /* Input/Output speed requested */
+extern u_int32_t netmask; /* IP netmask to set on interface */
+extern bool lockflag; /* Create lock file to lock the serial dev */
+extern bool nodetach; /* Don't detach from controlling tty */
+extern bool updetach; /* Detach from controlling tty when link up */
+extern char *initializer; /* Script to initialize physical link */
+extern char *connect_script; /* Script to establish physical link */
+extern char *disconnect_script; /* Script to disestablish physical link */
+extern char *welcomer; /* Script to welcome client after connection */
+extern char *ptycommand; /* Command to run on other side of pty */
+extern int maxconnect; /* Maximum connect time (seconds) */
+extern char user[MAXNAMELEN];/* Our name for authenticating ourselves */
+extern char passwd[MAXSECRETLEN]; /* Password for PAP or CHAP */
+extern bool auth_required; /* Peer is required to authenticate */
+extern bool persist; /* Reopen link after it goes down */
+extern bool uselogin; /* Use /etc/passwd for checking PAP */
+extern char our_name[MAXNAMELEN];/* Our name for authentication purposes */
+extern char remote_name[MAXNAMELEN]; /* Peer's name for authentication */
+extern bool explicit_remote;/* remote_name specified with remotename opt */
+extern bool demand; /* Do dial-on-demand */
+extern char *ipparam; /* Extra parameter for ip up/down scripts */
+extern bool cryptpap; /* Others' PAP passwords are encrypted */
+extern int idle_time_limit;/* Shut down link if idle for this long */
+extern int holdoff; /* Dead time before restarting */
+extern bool holdoff_specified; /* true if user gave a holdoff value */
+extern bool notty; /* Stdin/out is not a tty */
+extern char *pty_socket; /* Socket to connect to pty */
+extern char *record_file; /* File to record chars sent/received */
+extern bool sync_serial; /* Device is synchronous serial device */
+extern int maxfail; /* Max # of unsuccessful connection attempts */
+extern char linkname[MAXPATHLEN]; /* logical name for link */
+extern bool tune_kernel; /* May alter kernel settings as necessary */
+extern int connect_delay; /* Time to delay after connect script */
+extern int max_data_rate; /* max bytes/sec through charshunt */
+extern int req_unit; /* interface unit number to use */
+extern bool multilink; /* enable multilink operation */
+extern bool noendpoint; /* don't send or accept endpt. discrim. */
+extern char *bundle_name; /* bundle name for multilink */
+extern bool dump_options; /* print out option values */
+extern bool dryrun; /* check everything, print options, exit */
+
+#ifdef PPP_FILTER
+extern struct bpf_program pass_filter; /* Filter for pkts to pass */
+extern struct bpf_program active_filter; /* Filter for link-active pkts */
+#endif
+
+#ifdef MSLANMAN
+extern bool ms_lanman; /* Use LanMan password instead of NT */
+ /* Has meaning only with MS-CHAP challenges */
+#endif
+
+extern char *current_option; /* the name of the option being parsed */
+extern int privileged_option; /* set iff the current option came from root */
+extern char *option_source; /* string saying where the option came from */
+extern int option_priority; /* priority of current options */
+
+/*
+ * Values for phase.
+ */
+#define PHASE_DEAD 0
+#define PHASE_INITIALIZE 1
+#define PHASE_SERIALCONN 2
+#define PHASE_DORMANT 3
+#define PHASE_ESTABLISH 4
+#define PHASE_AUTHENTICATE 5
+#define PHASE_CALLBACK 6
+#define PHASE_NETWORK 7
+#define PHASE_RUNNING 8
+#define PHASE_TERMINATE 9
+#define PHASE_DISCONNECT 10
+#define PHASE_HOLDOFF 11
+
+/*
+ * The following struct gives the addresses of procedures to call
+ * for a particular protocol.
+ */
+struct protent {
+ u_short protocol; /* PPP protocol number */
+ /* Initialization procedure */
+ void (*init) __P((int unit));
+ /* Process a received packet */
+ void (*input) __P((int unit, u_char *pkt, int len));
+ /* Process a received protocol-reject */
+ void (*protrej) __P((int unit));
+ /* Lower layer has come up */
+ void (*lowerup) __P((int unit));
+ /* Lower layer has gone down */
+ void (*lowerdown) __P((int unit));
+ /* Open the protocol */
+ void (*open) __P((int unit));
+ /* Close the protocol */
+ void (*close) __P((int unit, char *reason));
+ /* Print a packet in readable form */
+ int (*printpkt) __P((u_char *pkt, int len,
+ void (*printer) __P((void *, char *, ...)),
+ void *arg));
+ /* Process a received data packet */
+ void (*datainput) __P((int unit, u_char *pkt, int len));
+ bool enabled_flag; /* 0 iff protocol is disabled */
+ char *name; /* Text name of protocol */
+ char *data_name; /* Text name of corresponding data protocol */
+ option_t *options; /* List of command-line options */
+ /* Check requested options, assign defaults */
+ void (*check_options) __P((void));
+ /* Configure interface for demand-dial */
+ int (*demand_conf) __P((int unit));
+ /* Say whether to bring up link for this pkt */
+ int (*active_pkt) __P((u_char *pkt, int len));
+};
+
+/* Table of pointers to supported protocols */
+extern struct protent *protocols[];
+
+/*
+ * This struct contains pointers to a set of procedures for
+ * doing operations on a "channel". A channel provides a way
+ * to send and receive PPP packets - the canonical example is
+ * a serial port device in PPP line discipline (or equivalently
+ * with PPP STREAMS modules pushed onto it).
+ */
+struct channel {
+ /* set of options for this channel */
+ option_t *options;
+ /* find and process a per-channel options file */
+ void (*process_extra_options) __P((void));
+ /* check all the options that have been given */
+ void (*check_options) __P((void));
+ /* get the channel ready to do PPP, return a file descriptor */
+ int (*connect) __P((void));
+ /* we're finished with the channel */
+ void (*disconnect) __P((void));
+ /* put the channel into PPP `mode' */
+ int (*establish_ppp) __P((int));
+ /* take the channel out of PPP `mode', restore loopback if demand */
+ void (*disestablish_ppp) __P((int));
+ /* set the transmit-side PPP parameters of the channel */
+ void (*send_config) __P((int, u_int32_t, int, int));
+ /* set the receive-side PPP parameters of the channel */
+ void (*recv_config) __P((int, u_int32_t, int, int));
+ /* cleanup on error or normal exit */
+ void (*cleanup) __P((void));
+ /* close the device, called in children after fork */
+ void (*close) __P((void));
+};
+
+extern struct channel *the_channel;
+
+#define ppp_send_config(unit, mtu, accm, pc, acc) \
+do { \
+ if (the_channel->send_config) \
+ (*the_channel->send_config)((mtu), (accm), (pc), (acc)); \
+} while (0)
+
+#define ppp_recv_config(unit, mtu, accm, pc, acc) \
+do { \
+ if (the_channel->send_config) \
+ (*the_channel->recv_config)((mtu), (accm), (pc), (acc)); \
+} while (0)
+
+/*
+ * Prototypes.
+ */
+
+/* Procedures exported from main.c. */
+void set_ifunit __P((int)); /* set stuff that depends on ifunit */
+void detach __P((void)); /* Detach from controlling tty */
+void die __P((int)); /* Cleanup and exit */
+void quit __P((void)); /* like die(1) */
+void novm __P((char *)); /* Say we ran out of memory, and die */
+void timeout __P((void (*func)(void *), void *arg, int s, int us));
+ /* Call func(arg) after s.us seconds */
+void untimeout __P((void (*func)(void *), void *arg));
+ /* Cancel call to func(arg) */
+void record_child __P((int, char *, void (*) (void *), void *));
+int device_script __P((char *cmd, int in, int out, int dont_wait));
+ /* Run `cmd' with given stdin and stdout */
+pid_t run_program __P((char *prog, char **args, int must_exist,
+ void (*done)(void *), void *arg));
+ /* Run program prog with args in child */
+void reopen_log __P((void)); /* (re)open the connection to syslog */
+void update_link_stats __P((int)); /* Get stats at link termination */
+void script_setenv __P((char *, char *, int)); /* set script env var */
+void script_unsetenv __P((char *)); /* unset script env var */
+void new_phase __P((int)); /* signal start of new phase */
+void add_notifier __P((struct notifier **, notify_func, void *));
+void remove_notifier __P((struct notifier **, notify_func, void *));
+void notify __P((struct notifier *, int));
+
+/* Procedures exported from tty.c. */
+void tty_init __P((void));
+
+/* Procedures exported from utils.c. */
+void log_packet __P((u_char *, int, char *, int));
+ /* Format a packet and log it with syslog */
+void print_string __P((char *, int, void (*) (void *, char *, ...),
+ void *)); /* Format a string for output */
+int slprintf __P((char *, int, char *, ...)); /* sprintf++ */
+int vslprintf __P((char *, int, char *, va_list)); /* vsprintf++ */
+size_t strlcpy __P((char *, const char *, size_t)); /* safe strcpy */
+size_t strlcat __P((char *, const char *, size_t)); /* safe strncpy */
+void dbglog __P((char *, ...)); /* log a debug message */
+void info __P((char *, ...)); /* log an informational message */
+void notice __P((char *, ...)); /* log a notice-level message */
+void warn __P((char *, ...)); /* log a warning message */
+void error __P((char *, ...)); /* log an error message */
+void fatal __P((char *, ...)); /* log an error message and die(1) */
+void init_pr_log __P((char *, int)); /* initialize for using pr_log */
+void pr_log __P((void *, char *, ...)); /* printer fn, output to syslog */
+void end_pr_log __P((void)); /* finish up after using pr_log */
+
+/* Procedures exported from auth.c */
+void link_required __P((int)); /* we are starting to use the link */
+void link_terminated __P((int)); /* we are finished with the link */
+void link_down __P((int)); /* the LCP layer has left the Opened state */
+void link_established __P((int)); /* the link is up; authenticate now */
+void start_networks __P((void)); /* start all the network control protos */
+void np_up __P((int, int)); /* a network protocol has come up */
+void np_down __P((int, int)); /* a network protocol has gone down */
+void np_finished __P((int, int)); /* a network protocol no longer needs link */
+void auth_peer_fail __P((int, int));
+ /* peer failed to authenticate itself */
+void auth_peer_success __P((int, int, char *, int));
+ /* peer successfully authenticated itself */
+void auth_withpeer_fail __P((int, int));
+ /* we failed to authenticate ourselves */
+void auth_withpeer_success __P((int, int));
+ /* we successfully authenticated ourselves */
+void auth_check_options __P((void));
+ /* check authentication options supplied */
+void auth_reset __P((int)); /* check what secrets we have */
+int check_passwd __P((int, char *, int, char *, int, char **));
+ /* Check peer-supplied username/password */
+int get_secret __P((int, char *, char *, char *, int *, int));
+ /* get "secret" for chap */
+int auth_ip_addr __P((int, u_int32_t));
+ /* check if IP address is authorized */
+int bad_ip_adrs __P((u_int32_t));
+ /* check if IP address is unreasonable */
+
+/* Procedures exported from demand.c */
+void demand_conf __P((void)); /* config interface(s) for demand-dial */
+void demand_block __P((void)); /* set all NPs to queue up packets */
+void demand_unblock __P((void)); /* set all NPs to pass packets */
+void demand_discard __P((void)); /* set all NPs to discard packets */
+void demand_rexmit __P((int)); /* retransmit saved frames for an NP */
+int loop_chars __P((unsigned char *, int)); /* process chars from loopback */
+int loop_frame __P((unsigned char *, int)); /* should we bring link up? */
+
+/* Procedures exported from multilink.c */
+void mp_check_options __P((void)); /* Check multilink-related options */
+int mp_join_bundle __P((void)); /* join our link to an appropriate bundle */
+char *epdisc_to_str __P((struct epdisc *)); /* string from endpoint discrim. */
+int str_to_epdisc __P((struct epdisc *, char *)); /* endpt disc. from str */
+
+/* Procedures exported from sys-*.c */
+void sys_init __P((void)); /* Do system-dependent initialization */
+void sys_cleanup __P((void)); /* Restore system state before exiting */
+int sys_check_options __P((void)); /* Check options specified */
+void sys_close __P((void)); /* Clean up in a child before execing */
+int ppp_available __P((void)); /* Test whether ppp kernel support exists */
+int get_pty __P((int *, int *, char *, int)); /* Get pty master/slave */
+int open_ppp_loopback __P((void)); /* Open loopback for demand-dialling */
+int tty_establish_ppp __P((int)); /* Turn serial port into a ppp interface */
+void tty_disestablish_ppp __P((int)); /* Restore port to normal operation */
+void make_new_bundle __P((int, int, int, int)); /* Create new bundle */
+int bundle_attach __P((int)); /* Attach link to existing bundle */
+void cfg_bundle __P((int, int, int, int)); /* Configure existing bundle */
+void clean_check __P((void)); /* Check if line was 8-bit clean */
+void set_up_tty __P((int, int)); /* Set up port's speed, parameters, etc. */
+void restore_tty __P((int)); /* Restore port's original parameters */
+void setdtr __P((int, int)); /* Raise or lower port's DTR line */
+void output __P((int, u_char *, int)); /* Output a PPP packet */
+void wait_input __P((struct timeval *));
+ /* Wait for input, with timeout */
+void add_fd __P((int)); /* Add fd to set to wait for */
+void remove_fd __P((int)); /* Remove fd from set to wait for */
+int read_packet __P((u_char *)); /* Read PPP packet */
+int get_loop_output __P((void)); /* Read pkts from loopback */
+void tty_send_config __P((int, u_int32_t, int, int));
+ /* Configure i/f transmit parameters */
+void tty_set_xaccm __P((ext_accm));
+ /* Set extended transmit ACCM */
+void tty_recv_config __P((int, u_int32_t, int, int));
+ /* Configure i/f receive parameters */
+int ccp_test __P((int, u_char *, int, int));
+ /* Test support for compression scheme */
+void ccp_flags_set __P((int, int, int));
+ /* Set kernel CCP state */
+int ccp_fatal_error __P((int)); /* Test for fatal decomp error in kernel */
+int get_idle_time __P((int, struct ppp_idle *));
+ /* Find out how long link has been idle */
+int get_ppp_stats __P((int, struct pppd_stats *));
+ /* Return link statistics */
+void netif_set_mtu __P((int, int)); /* Set PPP interface MTU */
+int sifvjcomp __P((int, int, int, int));
+ /* Configure VJ TCP header compression */
+int sifup __P((int)); /* Configure i/f up for one protocol */
+int sifnpmode __P((int u, int proto, enum NPmode mode));
+ /* Set mode for handling packets for proto */
+int sifdown __P((int)); /* Configure i/f down for one protocol */
+int sifaddr __P((int, u_int32_t, u_int32_t, u_int32_t));
+ /* Configure IPv4 addresses for i/f */
+int cifaddr __P((int, u_int32_t, u_int32_t));
+ /* Reset i/f IP addresses */
+#ifdef INET6
+int sif6addr __P((int, eui64_t, eui64_t));
+ /* Configure IPv6 addresses for i/f */
+int cif6addr __P((int, eui64_t, eui64_t));
+ /* Remove an IPv6 address from i/f */
+#endif
+int sifdefaultroute __P((int, u_int32_t, u_int32_t));
+ /* Create default route through i/f */
+int cifdefaultroute __P((int, u_int32_t, u_int32_t));
+ /* Delete default route through i/f */
+int sifproxyarp __P((int, u_int32_t));
+ /* Add proxy ARP entry for peer */
+int cifproxyarp __P((int, u_int32_t));
+ /* Delete proxy ARP entry for peer */
+u_int32_t GetMask __P((u_int32_t)); /* Get appropriate netmask for address */
+int lock __P((char *)); /* Create lock file for device */
+int relock __P((int)); /* Rewrite lock file with new pid */
+void unlock __P((void)); /* Delete previously-created lock file */
+int get_host_seed __P((void)); /* Get host-dependent random number seed */
+int have_route_to __P((u_int32_t)); /* Check if route to addr exists */
+#ifdef PPP_FILTER
+int set_filters __P((struct bpf_program *pass, struct bpf_program *active));
+ /* Set filter programs in kernel */
+#endif
+#ifdef IPX_CHANGE
+int sipxfaddr __P((int, unsigned long, unsigned char *));
+int cipxfaddr __P((int));
+#endif
+int get_if_hwaddr __P((u_char *addr, char *name));
+char *get_first_ethernet __P((void));
+
+/* Procedures exported from options.c */
+int parse_args __P((int argc, char **argv));
+ /* Parse options from arguments given */
+int options_from_file __P((char *filename, int must_exist, int check_prot,
+ int privileged));
+ /* Parse options from an options file */
+int options_from_user __P((void)); /* Parse options from user's .ppprc */
+int options_for_tty __P((void)); /* Parse options from /etc/ppp/options.tty */
+int options_from_list __P((struct wordlist *, int privileged));
+ /* Parse options from a wordlist */
+int getword __P((FILE *f, char *word, int *newlinep, char *filename));
+ /* Read a word from a file */
+void option_error __P((char *fmt, ...));
+ /* Print an error message about an option */
+int int_option __P((char *, int *));
+ /* Simplified number_option for decimal ints */
+void add_options __P((option_t *)); /* Add extra options */
+void check_options __P((void)); /* check values after all options parsed */
+int override_value __P((const char *, int, const char *));
+ /* override value if permitted by priority */
+void print_options __P((void (*) __P((void *, char *, ...)), void *));
+ /* print out values of all options */
+
+int parse_dotted_ip __P((char *, u_int32_t *));
+
+/*
+ * Hooks to enable plugins to change various things.
+ */
+extern int (*new_phase_hook) __P((int));
+extern int (*idle_time_hook) __P((struct ppp_idle *));
+extern int (*holdoff_hook) __P((void));
+extern int (*pap_check_hook) __P((void));
+extern int (*pap_auth_hook) __P((char *user, char *passwd, char **msgp,
+ struct wordlist **paddrs,
+ struct wordlist **popts));
+extern void (*pap_logout_hook) __P((void));
+extern int (*pap_passwd_hook) __P((char *user, char *passwd));
+extern void (*ip_up_hook) __P((void));
+extern void (*ip_down_hook) __P((void));
+extern void (*ip_choose_hook) __P((u_int32_t *));
+
+/*
+ * Inline versions of get/put char/short/long.
+ * Pointer is advanced; we assume that both arguments
+ * are lvalues and will already be in registers.
+ * cp MUST be u_char *.
+ */
+#define GETCHAR(c, cp) { \
+ (c) = *(cp)++; \
+}
+#define PUTCHAR(c, cp) { \
+ *(cp)++ = (u_char) (c); \
+}
+
+
+#define GETSHORT(s, cp) { \
+ (s) = *(cp)++ << 8; \
+ (s) |= *(cp)++; \
+}
+#define PUTSHORT(s, cp) { \
+ *(cp)++ = (u_char) ((s) >> 8); \
+ *(cp)++ = (u_char) (s); \
+}
+
+#define GETLONG(l, cp) { \
+ (l) = *(cp)++ << 8; \
+ (l) |= *(cp)++; (l) <<= 8; \
+ (l) |= *(cp)++; (l) <<= 8; \
+ (l) |= *(cp)++; \
+}
+#define PUTLONG(l, cp) { \
+ *(cp)++ = (u_char) ((l) >> 24); \
+ *(cp)++ = (u_char) ((l) >> 16); \
+ *(cp)++ = (u_char) ((l) >> 8); \
+ *(cp)++ = (u_char) (l); \
+}
+
+#define INCPTR(n, cp) ((cp) += (n))
+#define DECPTR(n, cp) ((cp) -= (n))
+
+/*
+ * System dependent definitions for user-level 4.3BSD UNIX implementation.
+ */
+
+#define TIMEOUT(r, f, t) timeout((r), (f), (t), 0)
+#define UNTIMEOUT(r, f) untimeout((r), (f))
+
+#define BCOPY(s, d, l) memcpy(d, s, l)
+#define BZERO(s, n) memset(s, 0, n)
+
+#define PRINTMSG(m, l) { info("Remote message: %0.*v", l, m); }
+
+/*
+ * MAKEHEADER - Add Header fields to a packet.
+ */
+#define MAKEHEADER(p, t) { \
+ PUTCHAR(PPP_ALLSTATIONS, p); \
+ PUTCHAR(PPP_UI, p); \
+ PUTSHORT(t, p); }
+
+/*
+ * Exit status values.
+ */
+#define EXIT_OK 0
+#define EXIT_FATAL_ERROR 1
+#define EXIT_OPTION_ERROR 2
+#define EXIT_NOT_ROOT 3
+#define EXIT_NO_KERNEL_SUPPORT 4
+#define EXIT_USER_REQUEST 5
+#define EXIT_LOCK_FAILED 6
+#define EXIT_OPEN_FAILED 7
+#define EXIT_CONNECT_FAILED 8
+#define EXIT_PTYCMD_FAILED 9
+#define EXIT_NEGOTIATION_FAILED 10
+#define EXIT_PEER_AUTH_FAILED 11
+#define EXIT_IDLE_TIMEOUT 12
+#define EXIT_CONNECT_TIME 13
+#define EXIT_CALLBACK 14
+#define EXIT_PEER_DEAD 15
+#define EXIT_HANGUP 16
+#define EXIT_LOOPBACK 17
+#define EXIT_INIT_FAILED 18
+#define EXIT_AUTH_TOPEER_FAILED 19
+
+/*
+ * Debug macros. Slightly useful for finding bugs in pppd, not particularly
+ * useful for finding out why your connection isn't being established.
+ */
+#ifdef DEBUGALL
+#define DEBUGMAIN 1
+#define DEBUGFSM 1
+#define DEBUGLCP 1
+#define DEBUGIPCP 1
+#define DEBUGIPV6CP 1
+#define DEBUGUPAP 1
+#define DEBUGCHAP 1
+#endif
+
+#ifndef LOG_PPP /* we use LOG_LOCAL2 for syslog by default */
+#if defined(DEBUGMAIN) || defined(DEBUGFSM) || defined(DEBUGSYS) \
+ || defined(DEBUGLCP) || defined(DEBUGIPCP) || defined(DEBUGUPAP) \
+ || defined(DEBUGCHAP) || defined(DEBUG) || defined(DEBUGIPV6CP)
+#define LOG_PPP LOG_LOCAL2
+#else
+#define LOG_PPP LOG_DAEMON
+#endif
+#endif /* LOG_PPP */
+
+#ifdef DEBUGMAIN
+#define MAINDEBUG(x) if (debug) dbglog x
+#else
+#define MAINDEBUG(x)
+#endif
+
+#ifdef DEBUGSYS
+#define SYSDEBUG(x) if (debug) dbglog x
+#else
+#define SYSDEBUG(x)
+#endif
+
+#ifdef DEBUGFSM
+#define FSMDEBUG(x) if (debug) dbglog x
+#else
+#define FSMDEBUG(x)
+#endif
+
+#ifdef DEBUGLCP
+#define LCPDEBUG(x) if (debug) dbglog x
+#else
+#define LCPDEBUG(x)
+#endif
+
+#ifdef DEBUGIPCP
+#define IPCPDEBUG(x) if (debug) dbglog x
+#else
+#define IPCPDEBUG(x)
+#endif
+
+#ifdef DEBUGIPV6CP
+#define IPV6CPDEBUG(x) if (debug) dbglog x
+#else
+#define IPV6CPDEBUG(x)
+#endif
+
+#ifdef DEBUGUPAP
+#define UPAPDEBUG(x) if (debug) dbglog x
+#else
+#define UPAPDEBUG(x)
+#endif
+
+#ifdef DEBUGCHAP
+#define CHAPDEBUG(x) if (debug) dbglog x
+#else
+#define CHAPDEBUG(x)
+#endif
+
+#ifdef DEBUGIPXCP
+#define IPXCPDEBUG(x) if (debug) dbglog x
+#else
+#define IPXCPDEBUG(x)
+#endif
+
+#ifndef SIGTYPE
+#if defined(sun) || defined(SYSV) || defined(POSIX_SOURCE)
+#define SIGTYPE void
+#else
+#define SIGTYPE int
+#endif /* defined(sun) || defined(SYSV) || defined(POSIX_SOURCE) */
+#endif /* SIGTYPE */
+
+#ifndef MIN
+#define MIN(a, b) ((a) < (b)? (a): (b))
+#endif
+#ifndef MAX
+#define MAX(a, b) ((a) > (b)? (a): (b))
+#endif
+
+#endif /* __PPP_H__ */
diff --git a/mdk-stage1/ppp/pppd/pppd.h.wtmp b/mdk-stage1/ppp/pppd/pppd.h.wtmp
new file mode 100644
index 000000000..b69585d8c
--- /dev/null
+++ b/mdk-stage1/ppp/pppd/pppd.h.wtmp
@@ -0,0 +1,789 @@
+/*
+ * pppd.h - PPP daemon global declarations.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id: pppd.h.wtmp 195720 2001-06-11 11:44:34Z gc $
+ */
+
+/*
+ * TODO:
+ */
+
+#ifndef __PPPD_H__
+#define __PPPD_H__
+
+#include <stdio.h> /* for FILE */
+#include <limits.h> /* for NGROUPS_MAX */
+#include <sys/param.h> /* for MAXPATHLEN and BSD4_4, if defined */
+#include <sys/types.h> /* for u_int32_t, if defined */
+#include <sys/time.h> /* for struct timeval */
+#include <net/ppp_defs.h>
+#include "patchlevel.h"
+
+#if defined(__STDC__)
+#include <stdarg.h>
+#define __V(x) x
+#else
+#include <varargs.h>
+#define __V(x) (va_alist) va_dcl
+#define const
+#define volatile
+#endif
+
+#ifdef INET6
+#include "eui64.h"
+#endif
+
+/*
+ * Limits.
+ */
+
+#define NUM_PPP 1 /* One PPP interface supported (per process) */
+#define MAXWORDLEN 1024 /* max length of word in file (incl null) */
+#define MAXARGS 1 /* max # args to a command */
+#define MAXNAMELEN 256 /* max length of hostname or name for auth */
+#define MAXSECRETLEN 256 /* max length of password or secret */
+
+/*
+ * Option descriptor structure.
+ */
+
+typedef unsigned char bool;
+
+enum opt_type {
+ o_special_noarg = 0,
+ o_special = 1,
+ o_bool,
+ o_int,
+ o_uint32,
+ o_string,
+ o_wild,
+};
+
+typedef struct {
+ char *name; /* name of the option */
+ enum opt_type type;
+ void *addr;
+ char *description;
+ int flags;
+ void *addr2;
+ int upper_limit;
+ int lower_limit;
+ const char *source;
+ short int priority;
+ short int winner;
+} option_t;
+
+/* Values for flags */
+#define OPT_VALUE 0xff /* mask for presupplied value */
+#define OPT_HEX 0x100 /* int option is in hex */
+#define OPT_NOARG 0x200 /* option doesn't take argument */
+#define OPT_OR 0x400 /* OR in argument to value */
+#define OPT_INC 0x800 /* increment value */
+#define OPT_PRIV 0x1000 /* privileged option */
+#define OPT_STATIC 0x2000 /* string option goes into static array */
+#define OPT_LLIMIT 0x4000 /* check value against lower limit */
+#define OPT_ULIMIT 0x8000 /* check value against upper limit */
+#define OPT_LIMITS (OPT_LLIMIT|OPT_ULIMIT)
+#define OPT_ZEROOK 0x10000 /* 0 value is OK even if not within limits */
+#define OPT_HIDE 0x10000 /* for o_string, print value as ?????? */
+#define OPT_A2LIST 0x10000 /* for o_special, keep list of values */
+#define OPT_NOINCR 0x20000 /* value mustn't be increased */
+#define OPT_ZEROINF 0x40000 /* with OPT_NOINCR, 0 == infinity */
+#define OPT_PRIO 0x80000 /* process option priorities for this option */
+#define OPT_PRIOSUB 0x100000 /* subsidiary member of priority group */
+#define OPT_ALIAS 0x200000 /* option is alias for previous option */
+#define OPT_A2COPY 0x400000 /* addr2 -> second location to rcv value */
+#define OPT_ENABLE 0x800000 /* use *addr2 as enable for option */
+#define OPT_A2CLR 0x1000000 /* clear *(bool *)addr2 */
+#define OPT_PRIVFIX 0x2000000 /* user can't override if set by root */
+#define OPT_INITONLY 0x4000000 /* option can only be set in init phase */
+#define OPT_DEVEQUIV 0x8000000 /* equiv to device name */
+#define OPT_DEVNAM (OPT_INITONLY | OPT_DEVEQUIV)
+#define OPT_A2PRINTER 0x10000000 /* *addr2 is a fn for printing option */
+#define OPT_A2STRVAL 0x20000000 /* *addr2 points to current string value */
+#define OPT_NOPRINT 0x40000000 /* don't print this option at all */
+
+#define OPT_VAL(x) ((x) & OPT_VALUE)
+
+/* Values for priority */
+#define OPRIO_DEFAULT 0 /* a default value */
+#define OPRIO_CFGFILE 1 /* value from a configuration file */
+#define OPRIO_CMDLINE 2 /* value from the command line */
+#define OPRIO_SECFILE 3 /* value from options in a secrets file */
+#define OPRIO_ROOT 100 /* added to priority if OPT_PRIVFIX && root */
+
+#ifndef GIDSET_TYPE
+#define GIDSET_TYPE gid_t
+#endif
+
+/* Structure representing a list of permitted IP addresses. */
+struct permitted_ip {
+ int permit; /* 1 = permit, 0 = forbid */
+ u_int32_t base; /* match if (addr & mask) == base */
+ u_int32_t mask; /* base and mask are in network byte order */
+};
+
+/*
+ * Unfortunately, the linux kernel driver uses a different structure
+ * for statistics from the rest of the ports.
+ * This structure serves as a common representation for the bits
+ * pppd needs.
+ */
+struct pppd_stats {
+ unsigned int bytes_in;
+ unsigned int bytes_out;
+};
+
+/* Used for storing a sequence of words. Usually malloced. */
+struct wordlist {
+ struct wordlist *next;
+ char *word;
+};
+
+/* An endpoint discriminator, used with multilink. */
+#define MAX_ENDP_LEN 20 /* maximum length of discriminator value */
+struct epdisc {
+ unsigned char class;
+ unsigned char length;
+ unsigned char value[MAX_ENDP_LEN];
+};
+
+/* values for epdisc.class */
+#define EPD_NULL 0 /* null discriminator, no data */
+#define EPD_LOCAL 1
+#define EPD_IP 2
+#define EPD_MAC 3
+#define EPD_MAGIC 4
+#define EPD_PHONENUM 5
+
+typedef void (*notify_func) __P((void *, int));
+
+struct notifier {
+ struct notifier *next;
+ notify_func func;
+ void *arg;
+};
+
+/*
+ * Global variables.
+ */
+
+extern int hungup; /* Physical layer has disconnected */
+extern int ifunit; /* Interface unit number */
+extern char ifname[]; /* Interface name */
+extern char hostname[]; /* Our hostname */
+extern u_char outpacket_buf[]; /* Buffer for outgoing packets */
+extern int phase; /* Current state of link - see values below */
+extern int baud_rate; /* Current link speed in bits/sec */
+extern char *progname; /* Name of this program */
+extern int redirect_stderr;/* Connector's stderr should go to file */
+extern char peer_authname[];/* Authenticated name of peer */
+extern int privileged; /* We were run by real-uid root */
+extern int need_holdoff; /* Need holdoff period after link terminates */
+extern char **script_env; /* Environment variables for scripts */
+extern int detached; /* Have detached from controlling tty */
+extern GIDSET_TYPE groups[NGROUPS_MAX]; /* groups the user is in */
+extern int ngroups; /* How many groups valid in groups */
+extern struct pppd_stats link_stats; /* byte/packet counts etc. for link */
+extern int link_stats_valid; /* set if link_stats is valid */
+extern int link_connect_time; /* time the link was up for */
+extern int using_pty; /* using pty as device (notty or pty opt.) */
+extern int log_to_fd; /* logging to this fd as well as syslog */
+extern bool log_default; /* log_to_fd is default (stdout) */
+extern char *no_ppp_msg; /* message to print if ppp not in kernel */
+extern volatile int status; /* exit status for pppd */
+extern bool devnam_fixed; /* can no longer change devnam */
+extern int unsuccess; /* # unsuccessful connection attempts */
+extern int do_callback; /* set if we want to do callback next */
+extern int doing_callback; /* set if this is a callback */
+extern char ppp_devnam[MAXPATHLEN];
+extern struct notifier *pidchange; /* for notifications of pid changing */
+extern struct notifier *phasechange; /* for notifications of phase changes */
+extern struct notifier *exitnotify; /* for notification that we're exiting */
+extern struct notifier *sigreceived; /* notification of received signal */
+extern int listen_time; /* time to listen first (ms) */
+
+/* Values for do_callback and doing_callback */
+#define CALLBACK_DIALIN 1 /* we are expecting the call back */
+#define CALLBACK_DIALOUT 2 /* we are dialling out to call back */
+
+/*
+ * Variables set by command-line options.
+ */
+
+extern int debug; /* Debug flag */
+extern int kdebugflag; /* Tell kernel to print debug messages */
+extern int default_device; /* Using /dev/tty or equivalent */
+extern char devnam[MAXPATHLEN]; /* Device name */
+extern int crtscts; /* Use hardware flow control */
+extern bool modem; /* Use modem control lines */
+extern int inspeed; /* Input/Output speed requested */
+extern u_int32_t netmask; /* IP netmask to set on interface */
+extern bool lockflag; /* Create lock file to lock the serial dev */
+extern bool nodetach; /* Don't detach from controlling tty */
+extern bool updetach; /* Detach from controlling tty when link up */
+extern char *initializer; /* Script to initialize physical link */
+extern char *connect_script; /* Script to establish physical link */
+extern char *disconnect_script; /* Script to disestablish physical link */
+extern char *welcomer; /* Script to welcome client after connection */
+extern char *ptycommand; /* Command to run on other side of pty */
+extern int maxconnect; /* Maximum connect time (seconds) */
+extern char user[MAXNAMELEN];/* Our name for authenticating ourselves */
+extern char passwd[MAXSECRETLEN]; /* Password for PAP or CHAP */
+extern bool auth_required; /* Peer is required to authenticate */
+extern bool persist; /* Reopen link after it goes down */
+extern bool uselogin; /* Use /etc/passwd for checking PAP */
+extern char our_name[MAXNAMELEN];/* Our name for authentication purposes */
+extern char remote_name[MAXNAMELEN]; /* Peer's name for authentication */
+extern bool explicit_remote;/* remote_name specified with remotename opt */
+extern bool demand; /* Do dial-on-demand */
+extern char *ipparam; /* Extra parameter for ip up/down scripts */
+extern bool cryptpap; /* Others' PAP passwords are encrypted */
+extern int idle_time_limit;/* Shut down link if idle for this long */
+extern int holdoff; /* Dead time before restarting */
+extern bool holdoff_specified; /* true if user gave a holdoff value */
+extern bool notty; /* Stdin/out is not a tty */
+extern char *pty_socket; /* Socket to connect to pty */
+extern char *record_file; /* File to record chars sent/received */
+extern bool sync_serial; /* Device is synchronous serial device */
+extern int maxfail; /* Max # of unsuccessful connection attempts */
+extern char linkname[MAXPATHLEN]; /* logical name for link */
+extern bool tune_kernel; /* May alter kernel settings as necessary */
+extern int connect_delay; /* Time to delay after connect script */
+extern int max_data_rate; /* max bytes/sec through charshunt */
+extern int req_unit; /* interface unit number to use */
+extern bool multilink; /* enable multilink operation */
+extern bool noendpoint; /* don't send or accept endpt. discrim. */
+extern char *bundle_name; /* bundle name for multilink */
+extern bool dump_options; /* print out option values */
+extern bool dryrun; /* check everything, print options, exit */
+
+#ifdef PPP_FILTER
+extern struct bpf_program pass_filter; /* Filter for pkts to pass */
+extern struct bpf_program active_filter; /* Filter for link-active pkts */
+#endif
+
+#ifdef MSLANMAN
+extern bool ms_lanman; /* Use LanMan password instead of NT */
+ /* Has meaning only with MS-CHAP challenges */
+#endif
+
+extern char *current_option; /* the name of the option being parsed */
+extern int privileged_option; /* set iff the current option came from root */
+extern char *option_source; /* string saying where the option came from */
+extern int option_priority; /* priority of current options */
+
+/*
+ * Values for phase.
+ */
+#define PHASE_DEAD 0
+#define PHASE_INITIALIZE 1
+#define PHASE_SERIALCONN 2
+#define PHASE_DORMANT 3
+#define PHASE_ESTABLISH 4
+#define PHASE_AUTHENTICATE 5
+#define PHASE_CALLBACK 6
+#define PHASE_NETWORK 7
+#define PHASE_RUNNING 8
+#define PHASE_TERMINATE 9
+#define PHASE_DISCONNECT 10
+#define PHASE_HOLDOFF 11
+
+/*
+ * The following struct gives the addresses of procedures to call
+ * for a particular protocol.
+ */
+struct protent {
+ u_short protocol; /* PPP protocol number */
+ /* Initialization procedure */
+ void (*init) __P((int unit));
+ /* Process a received packet */
+ void (*input) __P((int unit, u_char *pkt, int len));
+ /* Process a received protocol-reject */
+ void (*protrej) __P((int unit));
+ /* Lower layer has come up */
+ void (*lowerup) __P((int unit));
+ /* Lower layer has gone down */
+ void (*lowerdown) __P((int unit));
+ /* Open the protocol */
+ void (*open) __P((int unit));
+ /* Close the protocol */
+ void (*close) __P((int unit, char *reason));
+ /* Print a packet in readable form */
+ int (*printpkt) __P((u_char *pkt, int len,
+ void (*printer) __P((void *, char *, ...)),
+ void *arg));
+ /* Process a received data packet */
+ void (*datainput) __P((int unit, u_char *pkt, int len));
+ bool enabled_flag; /* 0 iff protocol is disabled */
+ char *name; /* Text name of protocol */
+ char *data_name; /* Text name of corresponding data protocol */
+ option_t *options; /* List of command-line options */
+ /* Check requested options, assign defaults */
+ void (*check_options) __P((void));
+ /* Configure interface for demand-dial */
+ int (*demand_conf) __P((int unit));
+ /* Say whether to bring up link for this pkt */
+ int (*active_pkt) __P((u_char *pkt, int len));
+};
+
+/* Table of pointers to supported protocols */
+extern struct protent *protocols[];
+
+/*
+ * This struct contains pointers to a set of procedures for
+ * doing operations on a "channel". A channel provides a way
+ * to send and receive PPP packets - the canonical example is
+ * a serial port device in PPP line discipline (or equivalently
+ * with PPP STREAMS modules pushed onto it).
+ */
+struct channel {
+ /* set of options for this channel */
+ option_t *options;
+ /* find and process a per-channel options file */
+ void (*process_extra_options) __P((void));
+ /* check all the options that have been given */
+ void (*check_options) __P((void));
+ /* get the channel ready to do PPP, return a file descriptor */
+ int (*connect) __P((void));
+ /* we're finished with the channel */
+ void (*disconnect) __P((void));
+ /* put the channel into PPP `mode' */
+ int (*establish_ppp) __P((int));
+ /* take the channel out of PPP `mode', restore loopback if demand */
+ void (*disestablish_ppp) __P((int));
+ /* set the transmit-side PPP parameters of the channel */
+ void (*send_config) __P((int, u_int32_t, int, int));
+ /* set the receive-side PPP parameters of the channel */
+ void (*recv_config) __P((int, u_int32_t, int, int));
+ /* cleanup on error or normal exit */
+ void (*cleanup) __P((void));
+ /* close the device, called in children after fork */
+ void (*close) __P((void));
+};
+
+extern struct channel *the_channel;
+
+#define ppp_send_config(unit, mtu, accm, pc, acc) \
+do { \
+ if (the_channel->send_config) \
+ (*the_channel->send_config)((mtu), (accm), (pc), (acc)); \
+} while (0)
+
+#define ppp_recv_config(unit, mtu, accm, pc, acc) \
+do { \
+ if (the_channel->send_config) \
+ (*the_channel->recv_config)((mtu), (accm), (pc), (acc)); \
+} while (0)
+
+/*
+ * Prototypes.
+ */
+
+/* Procedures exported from main.c. */
+void set_ifunit __P((int)); /* set stuff that depends on ifunit */
+void detach __P((void)); /* Detach from controlling tty */
+void die __P((int)); /* Cleanup and exit */
+void quit __P((void)); /* like die(1) */
+void novm __P((char *)); /* Say we ran out of memory, and die */
+void timeout __P((void (*func)(void *), void *arg, int s, int us));
+ /* Call func(arg) after s.us seconds */
+void untimeout __P((void (*func)(void *), void *arg));
+ /* Cancel call to func(arg) */
+void record_child __P((int, char *, void (*) (void *), void *));
+int device_script __P((char *cmd, int in, int out, int dont_wait));
+ /* Run `cmd' with given stdin and stdout */
+pid_t run_program __P((char *prog, char **args, int must_exist,
+ void (*done)(void *), void *arg));
+ /* Run program prog with args in child */
+void reopen_log __P((void)); /* (re)open the connection to syslog */
+void update_link_stats __P((int)); /* Get stats at link termination */
+void script_setenv __P((char *, char *, int)); /* set script env var */
+void script_unsetenv __P((char *)); /* unset script env var */
+void new_phase __P((int)); /* signal start of new phase */
+void add_notifier __P((struct notifier **, notify_func, void *));
+void remove_notifier __P((struct notifier **, notify_func, void *));
+void notify __P((struct notifier *, int));
+
+/* Procedures exported from tty.c. */
+void tty_init __P((void));
+
+/* Procedures exported from utils.c. */
+void log_packet __P((u_char *, int, char *, int));
+ /* Format a packet and log it with syslog */
+void print_string __P((char *, int, void (*) (void *, char *, ...),
+ void *)); /* Format a string for output */
+int slprintf __P((char *, int, char *, ...)); /* sprintf++ */
+int vslprintf __P((char *, int, char *, va_list)); /* vsprintf++ */
+size_t strlcpy __P((char *, const char *, size_t)); /* safe strcpy */
+size_t strlcat __P((char *, const char *, size_t)); /* safe strncpy */
+void dbglog __P((char *, ...)); /* log a debug message */
+void info __P((char *, ...)); /* log an informational message */
+void notice __P((char *, ...)); /* log a notice-level message */
+void warn __P((char *, ...)); /* log a warning message */
+void error __P((char *, ...)); /* log an error message */
+void fatal __P((char *, ...)); /* log an error message and die(1) */
+void init_pr_log __P((char *, int)); /* initialize for using pr_log */
+void pr_log __P((void *, char *, ...)); /* printer fn, output to syslog */
+void end_pr_log __P((void)); /* finish up after using pr_log */
+
+/* Procedures exported from auth.c */
+void link_required __P((int)); /* we are starting to use the link */
+void link_terminated __P((int)); /* we are finished with the link */
+void link_down __P((int)); /* the LCP layer has left the Opened state */
+void link_established __P((int)); /* the link is up; authenticate now */
+void start_networks __P((void)); /* start all the network control protos */
+void np_up __P((int, int)); /* a network protocol has come up */
+void np_down __P((int, int)); /* a network protocol has gone down */
+void np_finished __P((int, int)); /* a network protocol no longer needs link */
+void auth_peer_fail __P((int, int));
+ /* peer failed to authenticate itself */
+void auth_peer_success __P((int, int, char *, int));
+ /* peer successfully authenticated itself */
+void auth_withpeer_fail __P((int, int));
+ /* we failed to authenticate ourselves */
+void auth_withpeer_success __P((int, int));
+ /* we successfully authenticated ourselves */
+void auth_check_options __P((void));
+ /* check authentication options supplied */
+void auth_reset __P((int)); /* check what secrets we have */
+int check_passwd __P((int, char *, int, char *, int, char **));
+ /* Check peer-supplied username/password */
+int get_secret __P((int, char *, char *, char *, int *, int));
+ /* get "secret" for chap */
+int auth_ip_addr __P((int, u_int32_t));
+ /* check if IP address is authorized */
+int bad_ip_adrs __P((u_int32_t));
+ /* check if IP address is unreasonable */
+
+/* Procedures exported from demand.c */
+void demand_conf __P((void)); /* config interface(s) for demand-dial */
+void demand_block __P((void)); /* set all NPs to queue up packets */
+void demand_unblock __P((void)); /* set all NPs to pass packets */
+void demand_discard __P((void)); /* set all NPs to discard packets */
+void demand_rexmit __P((int)); /* retransmit saved frames for an NP */
+int loop_chars __P((unsigned char *, int)); /* process chars from loopback */
+int loop_frame __P((unsigned char *, int)); /* should we bring link up? */
+
+/* Procedures exported from multilink.c */
+void mp_check_options __P((void)); /* Check multilink-related options */
+int mp_join_bundle __P((void)); /* join our link to an appropriate bundle */
+char *epdisc_to_str __P((struct epdisc *)); /* string from endpoint discrim. */
+int str_to_epdisc __P((struct epdisc *, char *)); /* endpt disc. from str */
+
+/* Procedures exported from sys-*.c */
+void sys_init __P((void)); /* Do system-dependent initialization */
+void sys_cleanup __P((void)); /* Restore system state before exiting */
+int sys_check_options __P((void)); /* Check options specified */
+void sys_close __P((void)); /* Clean up in a child before execing */
+int ppp_available __P((void)); /* Test whether ppp kernel support exists */
+int get_pty __P((int *, int *, char *, int)); /* Get pty master/slave */
+int open_ppp_loopback __P((void)); /* Open loopback for demand-dialling */
+int tty_establish_ppp __P((int)); /* Turn serial port into a ppp interface */
+void tty_disestablish_ppp __P((int)); /* Restore port to normal operation */
+void make_new_bundle __P((int, int, int, int)); /* Create new bundle */
+int bundle_attach __P((int)); /* Attach link to existing bundle */
+void cfg_bundle __P((int, int, int, int)); /* Configure existing bundle */
+void clean_check __P((void)); /* Check if line was 8-bit clean */
+void set_up_tty __P((int, int)); /* Set up port's speed, parameters, etc. */
+void restore_tty __P((int)); /* Restore port's original parameters */
+void setdtr __P((int, int)); /* Raise or lower port's DTR line */
+void output __P((int, u_char *, int)); /* Output a PPP packet */
+void wait_input __P((struct timeval *));
+ /* Wait for input, with timeout */
+void add_fd __P((int)); /* Add fd to set to wait for */
+void remove_fd __P((int)); /* Remove fd from set to wait for */
+int read_packet __P((u_char *)); /* Read PPP packet */
+int get_loop_output __P((void)); /* Read pkts from loopback */
+void tty_send_config __P((int, u_int32_t, int, int));
+ /* Configure i/f transmit parameters */
+void tty_set_xaccm __P((ext_accm));
+ /* Set extended transmit ACCM */
+void tty_recv_config __P((int, u_int32_t, int, int));
+ /* Configure i/f receive parameters */
+int ccp_test __P((int, u_char *, int, int));
+ /* Test support for compression scheme */
+void ccp_flags_set __P((int, int, int));
+ /* Set kernel CCP state */
+int ccp_fatal_error __P((int)); /* Test for fatal decomp error in kernel */
+int get_idle_time __P((int, struct ppp_idle *));
+ /* Find out how long link has been idle */
+int get_ppp_stats __P((int, struct pppd_stats *));
+ /* Return link statistics */
+void netif_set_mtu __P((int, int)); /* Set PPP interface MTU */
+int sifvjcomp __P((int, int, int, int));
+ /* Configure VJ TCP header compression */
+int sifup __P((int)); /* Configure i/f up for one protocol */
+int sifnpmode __P((int u, int proto, enum NPmode mode));
+ /* Set mode for handling packets for proto */
+int sifdown __P((int)); /* Configure i/f down for one protocol */
+int sifaddr __P((int, u_int32_t, u_int32_t, u_int32_t));
+ /* Configure IPv4 addresses for i/f */
+int cifaddr __P((int, u_int32_t, u_int32_t));
+ /* Reset i/f IP addresses */
+#ifdef INET6
+int sif6addr __P((int, eui64_t, eui64_t));
+ /* Configure IPv6 addresses for i/f */
+int cif6addr __P((int, eui64_t, eui64_t));
+ /* Remove an IPv6 address from i/f */
+#endif
+int sifdefaultroute __P((int, u_int32_t, u_int32_t));
+ /* Create default route through i/f */
+int cifdefaultroute __P((int, u_int32_t, u_int32_t));
+ /* Delete default route through i/f */
+int sifproxyarp __P((int, u_int32_t));
+ /* Add proxy ARP entry for peer */
+int cifproxyarp __P((int, u_int32_t));
+ /* Delete proxy ARP entry for peer */
+u_int32_t GetMask __P((u_int32_t)); /* Get appropriate netmask for address */
+int lock __P((char *)); /* Create lock file for device */
+int relock __P((int)); /* Rewrite lock file with new pid */
+void unlock __P((void)); /* Delete previously-created lock file */
+void logwtmp __P((const char *, const char *, const char *));
+ /* Write entry to wtmp file */
+int get_host_seed __P((void)); /* Get host-dependent random number seed */
+int have_route_to __P((u_int32_t)); /* Check if route to addr exists */
+#ifdef PPP_FILTER
+int set_filters __P((struct bpf_program *pass, struct bpf_program *active));
+ /* Set filter programs in kernel */
+#endif
+#ifdef IPX_CHANGE
+int sipxfaddr __P((int, unsigned long, unsigned char *));
+int cipxfaddr __P((int));
+#endif
+int get_if_hwaddr __P((u_char *addr, char *name));
+char *get_first_ethernet __P((void));
+
+/* Procedures exported from options.c */
+int parse_args __P((int argc, char **argv));
+ /* Parse options from arguments given */
+int options_from_file __P((char *filename, int must_exist, int check_prot,
+ int privileged));
+ /* Parse options from an options file */
+int options_from_user __P((void)); /* Parse options from user's .ppprc */
+int options_for_tty __P((void)); /* Parse options from /etc/ppp/options.tty */
+int options_from_list __P((struct wordlist *, int privileged));
+ /* Parse options from a wordlist */
+int getword __P((FILE *f, char *word, int *newlinep, char *filename));
+ /* Read a word from a file */
+void option_error __P((char *fmt, ...));
+ /* Print an error message about an option */
+int int_option __P((char *, int *));
+ /* Simplified number_option for decimal ints */
+void add_options __P((option_t *)); /* Add extra options */
+void check_options __P((void)); /* check values after all options parsed */
+int override_value __P((const char *, int, const char *));
+ /* override value if permitted by priority */
+void print_options __P((void (*) __P((void *, char *, ...)), void *));
+ /* print out values of all options */
+
+int parse_dotted_ip __P((char *, u_int32_t *));
+
+/*
+ * Hooks to enable plugins to change various things.
+ */
+extern int (*new_phase_hook) __P((int));
+extern int (*idle_time_hook) __P((struct ppp_idle *));
+extern int (*holdoff_hook) __P((void));
+extern int (*pap_check_hook) __P((void));
+extern int (*pap_auth_hook) __P((char *user, char *passwd, char **msgp,
+ struct wordlist **paddrs,
+ struct wordlist **popts));
+extern void (*pap_logout_hook) __P((void));
+extern int (*pap_passwd_hook) __P((char *user, char *passwd));
+extern void (*ip_up_hook) __P((void));
+extern void (*ip_down_hook) __P((void));
+extern void (*ip_choose_hook) __P((u_int32_t *));
+
+/*
+ * Inline versions of get/put char/short/long.
+ * Pointer is advanced; we assume that both arguments
+ * are lvalues and will already be in registers.
+ * cp MUST be u_char *.
+ */
+#define GETCHAR(c, cp) { \
+ (c) = *(cp)++; \
+}
+#define PUTCHAR(c, cp) { \
+ *(cp)++ = (u_char) (c); \
+}
+
+
+#define GETSHORT(s, cp) { \
+ (s) = *(cp)++ << 8; \
+ (s) |= *(cp)++; \
+}
+#define PUTSHORT(s, cp) { \
+ *(cp)++ = (u_char) ((s) >> 8); \
+ *(cp)++ = (u_char) (s); \
+}
+
+#define GETLONG(l, cp) { \
+ (l) = *(cp)++ << 8; \
+ (l) |= *(cp)++; (l) <<= 8; \
+ (l) |= *(cp)++; (l) <<= 8; \
+ (l) |= *(cp)++; \
+}
+#define PUTLONG(l, cp) { \
+ *(cp)++ = (u_char) ((l) >> 24); \
+ *(cp)++ = (u_char) ((l) >> 16); \
+ *(cp)++ = (u_char) ((l) >> 8); \
+ *(cp)++ = (u_char) (l); \
+}
+
+#define INCPTR(n, cp) ((cp) += (n))
+#define DECPTR(n, cp) ((cp) -= (n))
+
+/*
+ * System dependent definitions for user-level 4.3BSD UNIX implementation.
+ */
+
+#define TIMEOUT(r, f, t) timeout((r), (f), (t), 0)
+#define UNTIMEOUT(r, f) untimeout((r), (f))
+
+#define BCOPY(s, d, l) memcpy(d, s, l)
+#define BZERO(s, n) memset(s, 0, n)
+
+#define PRINTMSG(m, l) { info("Remote message: %0.*v", l, m); }
+
+/*
+ * MAKEHEADER - Add Header fields to a packet.
+ */
+#define MAKEHEADER(p, t) { \
+ PUTCHAR(PPP_ALLSTATIONS, p); \
+ PUTCHAR(PPP_UI, p); \
+ PUTSHORT(t, p); }
+
+/*
+ * Exit status values.
+ */
+#define EXIT_OK 0
+#define EXIT_FATAL_ERROR 1
+#define EXIT_OPTION_ERROR 2
+#define EXIT_NOT_ROOT 3
+#define EXIT_NO_KERNEL_SUPPORT 4
+#define EXIT_USER_REQUEST 5
+#define EXIT_LOCK_FAILED 6
+#define EXIT_OPEN_FAILED 7
+#define EXIT_CONNECT_FAILED 8
+#define EXIT_PTYCMD_FAILED 9
+#define EXIT_NEGOTIATION_FAILED 10
+#define EXIT_PEER_AUTH_FAILED 11
+#define EXIT_IDLE_TIMEOUT 12
+#define EXIT_CONNECT_TIME 13
+#define EXIT_CALLBACK 14
+#define EXIT_PEER_DEAD 15
+#define EXIT_HANGUP 16
+#define EXIT_LOOPBACK 17
+#define EXIT_INIT_FAILED 18
+#define EXIT_AUTH_TOPEER_FAILED 19
+
+/*
+ * Debug macros. Slightly useful for finding bugs in pppd, not particularly
+ * useful for finding out why your connection isn't being established.
+ */
+#ifdef DEBUGALL
+#define DEBUGMAIN 1
+#define DEBUGFSM 1
+#define DEBUGLCP 1
+#define DEBUGIPCP 1
+#define DEBUGIPV6CP 1
+#define DEBUGUPAP 1
+#define DEBUGCHAP 1
+#endif
+
+#ifndef LOG_PPP /* we use LOG_LOCAL2 for syslog by default */
+#if defined(DEBUGMAIN) || defined(DEBUGFSM) || defined(DEBUGSYS) \
+ || defined(DEBUGLCP) || defined(DEBUGIPCP) || defined(DEBUGUPAP) \
+ || defined(DEBUGCHAP) || defined(DEBUG) || defined(DEBUGIPV6CP)
+#define LOG_PPP LOG_LOCAL2
+#else
+#define LOG_PPP LOG_DAEMON
+#endif
+#endif /* LOG_PPP */
+
+#ifdef DEBUGMAIN
+#define MAINDEBUG(x) if (debug) dbglog x
+#else
+#define MAINDEBUG(x)
+#endif
+
+#ifdef DEBUGSYS
+#define SYSDEBUG(x) if (debug) dbglog x
+#else
+#define SYSDEBUG(x)
+#endif
+
+#ifdef DEBUGFSM
+#define FSMDEBUG(x) if (debug) dbglog x
+#else
+#define FSMDEBUG(x)
+#endif
+
+#ifdef DEBUGLCP
+#define LCPDEBUG(x) if (debug) dbglog x
+#else
+#define LCPDEBUG(x)
+#endif
+
+#ifdef DEBUGIPCP
+#define IPCPDEBUG(x) if (debug) dbglog x
+#else
+#define IPCPDEBUG(x)
+#endif
+
+#ifdef DEBUGIPV6CP
+#define IPV6CPDEBUG(x) if (debug) dbglog x
+#else
+#define IPV6CPDEBUG(x)
+#endif
+
+#ifdef DEBUGUPAP
+#define UPAPDEBUG(x) if (debug) dbglog x
+#else
+#define UPAPDEBUG(x)
+#endif
+
+#ifdef DEBUGCHAP
+#define CHAPDEBUG(x) if (debug) dbglog x
+#else
+#define CHAPDEBUG(x)
+#endif
+
+#ifdef DEBUGIPXCP
+#define IPXCPDEBUG(x) if (debug) dbglog x
+#else
+#define IPXCPDEBUG(x)
+#endif
+
+#ifndef SIGTYPE
+#if defined(sun) || defined(SYSV) || defined(POSIX_SOURCE)
+#define SIGTYPE void
+#else
+#define SIGTYPE int
+#endif /* defined(sun) || defined(SYSV) || defined(POSIX_SOURCE) */
+#endif /* SIGTYPE */
+
+#ifndef MIN
+#define MIN(a, b) ((a) < (b)? (a): (b))
+#endif
+#ifndef MAX
+#define MAX(a, b) ((a) > (b)? (a): (b))
+#endif
+
+#endif /* __PPP_H__ */
diff --git a/mdk-stage1/ppp/pppd/sys-linux.c b/mdk-stage1/ppp/pppd/sys-linux.c
new file mode 100644
index 000000000..3ab92dfba
--- /dev/null
+++ b/mdk-stage1/ppp/pppd/sys-linux.c
@@ -0,0 +1,2672 @@
+/*
+ * sys-linux.c - System-dependent procedures for setting up
+ * PPP interfaces on Linux systems
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/errno.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <sys/utsname.h>
+#include <sys/sysmacros.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <syslog.h>
+#include <string.h>
+#include <time.h>
+#include <memory.h>
+#include <utmp.h>
+#include <mntent.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <termios.h>
+#include <unistd.h>
+
+/* This is in netdevice.h. However, this compile will fail miserably if
+ you attempt to include netdevice.h because it has so many references
+ to __memcpy functions which it should not attempt to do. So, since I
+ really don't use it, but it must be defined, define it now. */
+
+#ifndef MAX_ADDR_LEN
+#define MAX_ADDR_LEN 7
+#endif
+
+#if (defined(__GLIBC__) && __GLIBC__ >= 2) || defined(__dietlibc__)
+#include <asm/types.h> /* glibc 2 conflicts with linux/types.h */
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <net/route.h>
+#include <netinet/if_ether.h>
+#else
+#include <linux/types.h>
+#include <linux/if.h>
+#include <linux/if_arp.h>
+#include <linux/route.h>
+#include <linux/if_ether.h>
+#endif
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <linux/ppp_defs.h>
+#include <linux/if_ppp.h>
+
+#include "pppd.h"
+#include "fsm.h"
+#include "ipcp.h"
+
+#ifdef IPX_CHANGE
+#include "ipxcp.h"
+#if __GLIBC__ >= 2 && \
+ !(defined(__powerpc__) && __GLIBC__ == 2 && __GLIBC_MINOR__ == 0)
+#include <netipx/ipx.h>
+#else
+#include <linux/ipx.h>
+#endif
+#endif /* IPX_CHANGE */
+
+#ifdef PPP_FILTER
+#include <net/bpf.h>
+#include <linux/filter.h>
+#endif /* PPP_FILTER */
+
+#ifdef LOCKLIB
+#include <sys/locks.h>
+#endif
+
+#ifdef INET6
+#ifndef _LINUX_IN6_H
+/*
+ * This is in linux/include/net/ipv6.h.
+ */
+
+struct in6_ifreq {
+ struct in6_addr ifr6_addr;
+ __u32 ifr6_prefixlen;
+ unsigned int ifr6_ifindex;
+};
+#endif
+
+#define IN6_LLADDR_FROM_EUI64(sin6, eui64) do { \
+ memset(&sin6.s6_addr, 0, sizeof(struct in6_addr)); \
+ sin6.s6_addr16[0] = htons(0xfe80); \
+ eui64_copy(eui64, sin6.s6_addr32[2]); \
+ } while (0)
+
+#endif /* INET6 */
+
+/* We can get an EIO error on an ioctl if the modem has hung up */
+#define ok_error(num) ((num)==EIO)
+
+static int tty_disc = N_TTY; /* The TTY discipline */
+static int ppp_disc = N_PPP; /* The PPP discpline */
+static int initfdflags = -1; /* Initial file descriptor flags for fd */
+static int ppp_fd = -1; /* fd which is set to PPP discipline */
+static int sock_fd = -1; /* socket for doing interface ioctls */
+static int slave_fd = -1;
+static int master_fd = -1;
+#ifdef INET6
+static int sock6_fd = -1;
+#endif /* INET6 */
+static int ppp_dev_fd = -1; /* fd for /dev/ppp (new style driver) */
+static int chindex; /* channel index (new style driver) */
+
+static fd_set in_fds; /* set of fds that wait_input waits for */
+static int max_in_fd; /* highest fd set in in_fds */
+
+static int has_proxy_arp = 0;
+static int driver_version = 0;
+static int driver_modification = 0;
+static int driver_patch = 0;
+static int driver_is_old = 0;
+static int restore_term = 0; /* 1 => we've munged the terminal */
+static struct termios inittermios; /* Initial TTY termios */
+
+static int new_style_driver = 0;
+
+static char loop_name[20];
+static unsigned char inbuf[512]; /* buffer for chars read from loopback */
+
+static int if_is_up; /* Interface has been marked up */
+static u_int32_t default_route_gateway; /* Gateway for default route added */
+static u_int32_t proxy_arp_addr; /* Addr for proxy arp entry added */
+static char proxy_arp_dev[16]; /* Device for proxy arp entry */
+static u_int32_t our_old_addr; /* for detecting address changes */
+static int dynaddr_set; /* 1 if ip_dynaddr set */
+static int looped; /* 1 if using loop */
+static int link_mtu; /* mtu for the link (not bundle) */
+
+static struct utsname utsname; /* for the kernel version */
+static int kernel_version;
+#define KVERSION(j,n,p) ((j)*1000000 + (n)*1000 + (p))
+
+#define MAX_IFS 100
+
+#define FLAGS_GOOD (IFF_UP | IFF_BROADCAST)
+#define FLAGS_MASK (IFF_UP | IFF_BROADCAST | \
+ IFF_POINTOPOINT | IFF_LOOPBACK | IFF_NOARP)
+
+#define SIN_ADDR(x) (((struct sockaddr_in *) (&(x)))->sin_addr.s_addr)
+
+/* Prototypes for procedures local to this file. */
+static int get_flags (int fd);
+static void set_flags (int fd, int flags);
+static int translate_speed (int bps);
+static int baud_rate_of (int speed);
+static void close_route_table (void);
+static int open_route_table (void);
+static int read_route_table (struct rtentry *rt);
+static int defaultroute_exists (struct rtentry *rt);
+static int get_ether_addr (u_int32_t ipaddr, struct sockaddr *hwaddr,
+ char *name, int namelen);
+static void decode_version (char *buf, int *version, int *mod, int *patch);
+static int set_kdebugflag(int level);
+static int ppp_registered(void);
+static int make_ppp_unit(void);
+static void restore_loop(void); /* Transfer ppp unit back to loopback */
+
+extern u_char inpacket_buf[]; /* borrowed from main.c */
+
+/*
+ * SET_SA_FAMILY - set the sa_family field of a struct sockaddr,
+ * if it exists.
+ */
+
+#define SET_SA_FAMILY(addr, family) \
+ memset ((char *) &(addr), '\0', sizeof(addr)); \
+ addr.sa_family = (family);
+
+/*
+ * Determine if the PPP connection should still be present.
+ */
+
+extern int hungup;
+
+/* new_fd is the fd of a tty */
+static void set_ppp_fd (int new_fd)
+{
+ SYSDEBUG ((LOG_DEBUG, "setting ppp_fd to %d\n", new_fd));
+ ppp_fd = new_fd;
+ if (!new_style_driver)
+ ppp_dev_fd = new_fd;
+}
+
+static int still_ppp(void)
+{
+ if (new_style_driver)
+ return !hungup && ppp_fd >= 0;
+ if (!hungup || ppp_fd == slave_fd)
+ return 1;
+ if (slave_fd >= 0) {
+ set_ppp_fd(slave_fd);
+ return 1;
+ }
+ return 0;
+}
+
+/********************************************************************
+ *
+ * Functions to read and set the flags value in the device driver
+ */
+
+static int get_flags (int fd)
+{
+ int flags;
+
+ if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &flags) < 0) {
+ if ( ok_error (errno) )
+ flags = 0;
+ else
+ fatal("ioctl(PPPIOCGFLAGS): %m");
+ }
+
+ SYSDEBUG ((LOG_DEBUG, "get flags = %x\n", flags));
+ return flags;
+}
+
+/********************************************************************/
+
+static void set_flags (int fd, int flags)
+{
+ SYSDEBUG ((LOG_DEBUG, "set flags = %x\n", flags));
+
+ if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &flags) < 0) {
+ if (! ok_error (errno) )
+ fatal("ioctl(PPPIOCSFLAGS, %x): %m", flags, errno);
+ }
+}
+
+/********************************************************************
+ *
+ * sys_init - System-dependent initialization.
+ */
+
+void sys_init(void)
+{
+ int flags;
+
+ if (new_style_driver) {
+ ppp_dev_fd = open("/dev/ppp", O_RDWR);
+ if (ppp_dev_fd < 0)
+ fatal("Couldn't open /dev/ppp: %m");
+ flags = fcntl(ppp_dev_fd, F_GETFL);
+ if (flags == -1
+ || fcntl(ppp_dev_fd, F_SETFL, flags | O_NONBLOCK) == -1)
+ warn("Couldn't set /dev/ppp to nonblock: %m");
+ }
+
+ /* Get an internet socket for doing socket ioctls. */
+ sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (sock_fd < 0)
+ fatal("Couldn't create IP socket: %m(%d)", errno);
+
+#ifdef INET6
+ sock6_fd = socket(AF_INET6, SOCK_DGRAM, 0);
+ if (sock6_fd < 0)
+ sock6_fd = -errno; /* save errno for later */
+#endif
+
+ FD_ZERO(&in_fds);
+ max_in_fd = 0;
+}
+
+/********************************************************************
+ *
+ * sys_cleanup - restore any system state we modified before exiting:
+ * mark the interface down, delete default route and/or proxy arp entry.
+ * This shouldn't call die() because it's called from die().
+ */
+
+void sys_cleanup(void)
+{
+/*
+ * Take down the device
+ */
+ if (if_is_up) {
+ if_is_up = 0;
+ sifdown(0);
+ }
+/*
+ * Delete any routes through the device.
+ */
+ if (default_route_gateway != 0)
+ cifdefaultroute(0, 0, default_route_gateway);
+
+ if (has_proxy_arp)
+ cifproxyarp(0, proxy_arp_addr);
+}
+
+/********************************************************************
+ *
+ * sys_close - Clean up in a child process before execing.
+ */
+void
+sys_close(void)
+{
+ if (new_style_driver)
+ close(ppp_dev_fd);
+ if (sock_fd >= 0)
+ close(sock_fd);
+ if (slave_fd >= 0)
+ close(slave_fd);
+ if (master_fd >= 0)
+ close(master_fd);
+ closelog();
+}
+
+/********************************************************************
+ *
+ * set_kdebugflag - Define the debugging level for the kernel
+ */
+
+static int set_kdebugflag (int requested_level)
+{
+ if (new_style_driver && ifunit < 0)
+ return 1;
+ if (ioctl(ppp_dev_fd, PPPIOCSDEBUG, &requested_level) < 0) {
+ if ( ! ok_error (errno) )
+ error("ioctl(PPPIOCSDEBUG): %m");
+ return (0);
+ }
+ SYSDEBUG ((LOG_INFO, "set kernel debugging level to %d",
+ requested_level));
+ return (1);
+}
+
+/********************************************************************
+ *
+ * tty_establish_ppp - Turn the serial port into a ppp interface.
+ */
+
+int tty_establish_ppp (int tty_fd)
+{
+ int x;
+ int fd = -1;
+
+/*
+ * Ensure that the tty device is in exclusive mode.
+ */
+ if (ioctl(tty_fd, TIOCEXCL, 0) < 0) {
+ if ( ! ok_error ( errno ))
+ warn("Couldn't make tty exclusive: %m");
+ }
+/*
+ * Demand mode - prime the old ppp device to relinquish the unit.
+ */
+ if (!new_style_driver && looped
+ && ioctl(slave_fd, PPPIOCXFERUNIT, 0) < 0) {
+ error("ioctl(transfer ppp unit): %m");
+ return -1;
+ }
+/*
+ * Set the current tty to the PPP discpline
+ */
+
+#ifndef N_SYNC_PPP
+#define N_SYNC_PPP 14
+#endif
+ ppp_disc = (new_style_driver && sync_serial)? N_SYNC_PPP: N_PPP;
+ if (ioctl(tty_fd, TIOCSETD, &ppp_disc) < 0) {
+ if ( ! ok_error (errno) ) {
+ error("Couldn't set tty to PPP discipline: %m");
+ return -1;
+ }
+ }
+
+ if (new_style_driver) {
+ /* Open another instance of /dev/ppp and connect the channel to it */
+ int flags;
+
+ if (ioctl(tty_fd, PPPIOCGCHAN, &chindex) == -1) {
+ error("Couldn't get channel number: %m");
+ goto err;
+ }
+ dbglog("using channel %d", chindex);
+ fd = open("/dev/ppp", O_RDWR);
+ if (fd < 0) {
+ error("Couldn't reopen /dev/ppp: %m");
+ goto err;
+ }
+ if (ioctl(fd, PPPIOCATTCHAN, &chindex) < 0) {
+ error("Couldn't attach to channel %d: %m", chindex);
+ goto err_close;
+ }
+ flags = fcntl(fd, F_GETFL);
+ if (flags == -1 || fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1)
+ warn("Couldn't set /dev/ppp (channel) to nonblock: %m");
+ set_ppp_fd(fd);
+
+ if (!looped)
+ ifunit = -1;
+ if (!looped && !multilink) {
+ /*
+ * Create a new PPP unit.
+ */
+ if (make_ppp_unit() < 0)
+ goto err_close;
+ }
+
+ if (looped)
+ set_flags(ppp_dev_fd, get_flags(ppp_dev_fd) & ~SC_LOOP_TRAFFIC);
+
+ if (!multilink) {
+ add_fd(ppp_dev_fd);
+ if (ioctl(fd, PPPIOCCONNECT, &ifunit) < 0) {
+ error("Couldn't attach to PPP unit %d: %m", ifunit);
+ goto err_close;
+ }
+ }
+
+ } else {
+ /*
+ * Old-style driver: find out which interface we were given.
+ */
+ set_ppp_fd (tty_fd);
+ if (ioctl(tty_fd, PPPIOCGUNIT, &x) < 0) {
+ if (ok_error (errno))
+ goto err;
+ fatal("ioctl(PPPIOCGUNIT): %m(%d)", errno);
+ }
+ /* Check that we got the same unit again. */
+ if (looped && x != ifunit)
+ fatal("transfer_ppp failed: wanted unit %d, got %d", ifunit, x);
+ ifunit = x;
+
+ /*
+ * Fetch the initial file flags and reset blocking mode on the file.
+ */
+ initfdflags = fcntl(tty_fd, F_GETFL);
+ if (initfdflags == -1 ||
+ fcntl(tty_fd, F_SETFL, initfdflags | O_NONBLOCK) == -1) {
+ if ( ! ok_error (errno))
+ warn("Couldn't set device to non-blocking mode: %m");
+ }
+ }
+
+ looped = 0;
+
+ /*
+ * Enable debug in the driver if requested.
+ */
+ if (!looped)
+ set_kdebugflag (kdebugflag);
+
+#define SC_RCVB (SC_RCV_B7_0 | SC_RCV_B7_1 | SC_RCV_EVNP | SC_RCV_ODDP)
+#define SC_LOGB (SC_DEBUG | SC_LOG_INPKT | SC_LOG_OUTPKT | SC_LOG_RAWIN \
+ | SC_LOG_FLUSH)
+
+ set_flags(ppp_fd, ((get_flags(ppp_fd) & ~(SC_RCVB | SC_LOGB))
+ | ((kdebugflag * SC_DEBUG) & SC_LOGB)));
+
+ SYSDEBUG ((LOG_NOTICE, "Using version %d.%d.%d of PPP driver",
+ driver_version, driver_modification, driver_patch));
+
+ return ppp_fd;
+
+ err_close:
+ close(fd);
+ err:
+ if (ioctl(tty_fd, TIOCSETD, &tty_disc) < 0 && !ok_error(errno))
+ warn("Couldn't reset tty to normal line discipline: %m");
+ return -1;
+}
+
+/********************************************************************
+ *
+ * tty_disestablish_ppp - Restore the serial port to normal operation,
+ * and reconnect the ppp unit to the loopback if in demand mode.
+ * This shouldn't call die() because it's called from die().
+ */
+
+void tty_disestablish_ppp(int tty_fd)
+{
+ if (demand)
+ restore_loop();
+ if (!hungup) {
+/*
+ * Flush the tty output buffer so that the TIOCSETD doesn't hang.
+ */
+ if (tcflush(tty_fd, TCIOFLUSH) < 0)
+ warn("tcflush failed: %m");
+/*
+ * Restore the previous line discipline
+ */
+ if (ioctl(tty_fd, TIOCSETD, &tty_disc) < 0) {
+ if ( ! ok_error (errno))
+ error("ioctl(TIOCSETD, N_TTY): %m");
+ }
+
+ if (ioctl(tty_fd, TIOCNXCL, 0) < 0) {
+ if ( ! ok_error (errno))
+ warn("ioctl(TIOCNXCL): %m(%d)", errno);
+ }
+
+ /* Reset non-blocking mode on fd. */
+ if (initfdflags != -1 && fcntl(tty_fd, F_SETFL, initfdflags) < 0) {
+ if ( ! ok_error (errno))
+ warn("Couldn't restore device fd flags: %m");
+ }
+ }
+ initfdflags = -1;
+
+ if (new_style_driver) {
+ close(ppp_fd);
+ ppp_fd = -1;
+ if (!looped && ifunit >= 0 && ioctl(ppp_dev_fd, PPPIOCDETACH) < 0)
+ error("Couldn't release PPP unit: %m");
+ if (!multilink)
+ remove_fd(ppp_dev_fd);
+ }
+}
+
+/*
+ * make_ppp_unit - make a new ppp unit for ppp_dev_fd.
+ * Assumes new_style_driver.
+ */
+static int make_ppp_unit()
+{
+ int x;
+
+ ifunit = req_unit;
+ x = ioctl(ppp_dev_fd, PPPIOCNEWUNIT, &ifunit);
+ if (x < 0 && req_unit >= 0 && errno == EEXIST) {
+ warn("Couldn't allocate PPP unit %d as it is already in use");
+ ifunit = -1;
+ x = ioctl(ppp_dev_fd, PPPIOCNEWUNIT, &ifunit);
+ }
+ if (x < 0)
+ error("Couldn't create new ppp unit: %m");
+ return x;
+}
+
+/*
+ * cfg_bundle - configure the existing bundle.
+ * Used in demand mode.
+ */
+void cfg_bundle(int mrru, int mtru, int rssn, int tssn)
+{
+ int flags;
+
+ if (!new_style_driver)
+ return;
+
+ /* set the mrru, mtu and flags */
+ if (ioctl(ppp_dev_fd, PPPIOCSMRRU, &mrru) < 0)
+ error("Couldn't set MRRU: %m");
+ flags = get_flags(ppp_dev_fd);
+ flags &= ~(SC_MP_SHORTSEQ | SC_MP_XSHORTSEQ);
+ flags |= (rssn? SC_MP_SHORTSEQ: 0) | (tssn? SC_MP_XSHORTSEQ: 0)
+ | (mrru? SC_MULTILINK: 0);
+
+ set_flags(ppp_dev_fd, flags);
+
+ /* connect up the channel */
+ if (ioctl(ppp_fd, PPPIOCCONNECT, &ifunit) < 0)
+ fatal("Couldn't attach to PPP unit %d: %m", ifunit);
+ add_fd(ppp_dev_fd);
+}
+
+/*
+ * make_new_bundle - create a new PPP unit (i.e. a bundle)
+ * and connect our channel to it. This should only get called
+ * if `multilink' was set at the time establish_ppp was called.
+ * In demand mode this uses our existing bundle instead of making
+ * a new one.
+ */
+void make_new_bundle(int mrru, int mtru, int rssn, int tssn)
+{
+ if (!new_style_driver)
+ return;
+
+ /* make us a ppp unit */
+ if (make_ppp_unit() < 0)
+ die(1);
+
+ /* set the mrru and flags */
+ cfg_bundle(mrru, mtru, rssn, tssn);
+}
+
+/*
+ * bundle_attach - attach our link to a given PPP unit.
+ * We assume the unit is controlled by another pppd.
+ */
+int bundle_attach(int ifnum)
+{
+ if (!new_style_driver)
+ return -1;
+
+ if (ioctl(ppp_dev_fd, PPPIOCATTACH, &ifnum) < 0) {
+ if (errno == ENXIO)
+ return 0; /* doesn't still exist */
+ fatal("Couldn't attach to interface unit %d: %m\n", ifnum);
+ }
+ if (ioctl(ppp_fd, PPPIOCCONNECT, &ifnum) < 0)
+ fatal("Couldn't connect to interface unit %d: %m", ifnum);
+ set_flags(ppp_dev_fd, get_flags(ppp_dev_fd) | SC_MULTILINK);
+
+ ifunit = ifnum;
+ return 1;
+}
+
+/********************************************************************
+ *
+ * clean_check - Fetch the flags for the device and generate
+ * appropriate error messages.
+ */
+void clean_check(void)
+{
+ int x;
+ char *s;
+
+ if (still_ppp()) {
+ if (ioctl(ppp_fd, PPPIOCGFLAGS, (caddr_t) &x) == 0) {
+ s = NULL;
+ switch (~x & (SC_RCV_B7_0|SC_RCV_B7_1|SC_RCV_EVNP|SC_RCV_ODDP)) {
+ case SC_RCV_B7_0:
+ s = "all had bit 7 set to 1";
+ break;
+
+ case SC_RCV_B7_1:
+ s = "all had bit 7 set to 0";
+ break;
+
+ case SC_RCV_EVNP:
+ s = "all had odd parity";
+ break;
+
+ case SC_RCV_ODDP:
+ s = "all had even parity";
+ break;
+ }
+
+ if (s != NULL) {
+ warn("Receive serial link is not 8-bit clean:");
+ warn("Problem: %s", s);
+ }
+ }
+ }
+}
+
+
+/*
+ * List of valid speeds.
+ */
+
+struct speed {
+ int speed_int, speed_val;
+} speeds[] = {
+#ifdef B50
+ { 50, B50 },
+#endif
+#ifdef B75
+ { 75, B75 },
+#endif
+#ifdef B110
+ { 110, B110 },
+#endif
+#ifdef B134
+ { 134, B134 },
+#endif
+#ifdef B150
+ { 150, B150 },
+#endif
+#ifdef B200
+ { 200, B200 },
+#endif
+#ifdef B300
+ { 300, B300 },
+#endif
+#ifdef B600
+ { 600, B600 },
+#endif
+#ifdef B1200
+ { 1200, B1200 },
+#endif
+#ifdef B1800
+ { 1800, B1800 },
+#endif
+#ifdef B2000
+ { 2000, B2000 },
+#endif
+#ifdef B2400
+ { 2400, B2400 },
+#endif
+#ifdef B3600
+ { 3600, B3600 },
+#endif
+#ifdef B4800
+ { 4800, B4800 },
+#endif
+#ifdef B7200
+ { 7200, B7200 },
+#endif
+#ifdef B9600
+ { 9600, B9600 },
+#endif
+#ifdef B19200
+ { 19200, B19200 },
+#endif
+#ifdef B38400
+ { 38400, B38400 },
+#endif
+#ifdef B57600
+ { 57600, B57600 },
+#endif
+#ifdef B76800
+ { 76800, B76800 },
+#endif
+#ifdef B115200
+ { 115200, B115200 },
+#endif
+#ifdef EXTA
+ { 19200, EXTA },
+#endif
+#ifdef EXTB
+ { 38400, EXTB },
+#endif
+#ifdef B230400
+ { 230400, B230400 },
+#endif
+#ifdef B460800
+ { 460800, B460800 },
+#endif
+#ifdef B921600
+ { 921600, B921600 },
+#endif
+ { 0, 0 }
+};
+
+/********************************************************************
+ *
+ * Translate from bits/second to a speed_t.
+ */
+
+static int translate_speed (int bps)
+{
+ struct speed *speedp;
+
+ if (bps != 0) {
+ for (speedp = speeds; speedp->speed_int; speedp++) {
+ if (bps == speedp->speed_int)
+ return speedp->speed_val;
+ }
+ warn("speed %d not supported", bps);
+ }
+ return 0;
+}
+
+/********************************************************************
+ *
+ * Translate from a speed_t to bits/second.
+ */
+
+static int baud_rate_of (int speed)
+{
+ struct speed *speedp;
+
+ if (speed != 0) {
+ for (speedp = speeds; speedp->speed_int; speedp++) {
+ if (speed == speedp->speed_val)
+ return speedp->speed_int;
+ }
+ }
+ return 0;
+}
+
+/********************************************************************
+ *
+ * set_up_tty: Set up the serial port on `fd' for 8 bits, no parity,
+ * at the requested speed, etc. If `local' is true, set CLOCAL
+ * regardless of whether the modem option was specified.
+ */
+
+void set_up_tty(int tty_fd, int local)
+{
+ int speed;
+ struct termios tios;
+
+ setdtr(tty_fd, 1);
+ if (tcgetattr(tty_fd, &tios) < 0) {
+ if (!ok_error(errno))
+ fatal("tcgetattr: %m(%d)", errno);
+ return;
+ }
+
+ if (!restore_term)
+ inittermios = tios;
+
+ tios.c_cflag &= ~(CSIZE | CSTOPB | PARENB | CLOCAL);
+ tios.c_cflag |= CS8 | CREAD | HUPCL;
+
+ tios.c_iflag = IGNBRK | IGNPAR;
+ tios.c_oflag = 0;
+ tios.c_lflag = 0;
+ tios.c_cc[VMIN] = 1;
+ tios.c_cc[VTIME] = 0;
+
+ if (local || !modem)
+ tios.c_cflag ^= (CLOCAL | HUPCL);
+
+ switch (crtscts) {
+ case 1:
+ tios.c_cflag |= CRTSCTS;
+ break;
+
+ case -2:
+ tios.c_iflag |= IXON | IXOFF;
+ tios.c_cc[VSTOP] = 0x13; /* DC3 = XOFF = ^S */
+ tios.c_cc[VSTART] = 0x11; /* DC1 = XON = ^Q */
+ break;
+
+ case -1:
+ tios.c_cflag &= ~CRTSCTS;
+ break;
+
+ default:
+ break;
+ }
+
+ speed = translate_speed(inspeed);
+ if (speed) {
+ cfsetospeed (&tios, speed);
+ cfsetispeed (&tios, speed);
+ }
+/*
+ * We can't proceed if the serial port speed is B0,
+ * since that implies that the serial port is disabled.
+ */
+ else {
+ speed = cfgetospeed(&tios);
+ if (speed == B0)
+ fatal("Baud rate for %s is 0; need explicit baud rate", devnam);
+ }
+
+ if (tcsetattr(tty_fd, TCSAFLUSH, &tios) < 0)
+ if (!ok_error(errno))
+ fatal("tcsetattr: %m");
+
+ baud_rate = baud_rate_of(speed);
+ restore_term = 1;
+}
+
+/********************************************************************
+ *
+ * setdtr - control the DTR line on the serial port.
+ * This is called from die(), so it shouldn't call die().
+ */
+
+void setdtr (int tty_fd, int on)
+{
+ int modembits = TIOCM_DTR;
+
+ ioctl(tty_fd, (on ? TIOCMBIS : TIOCMBIC), &modembits);
+}
+
+/********************************************************************
+ *
+ * restore_tty - restore the terminal to the saved settings.
+ */
+
+void restore_tty (int tty_fd)
+{
+ if (restore_term) {
+ restore_term = 0;
+/*
+ * Turn off echoing, because otherwise we can get into
+ * a loop with the tty and the modem echoing to each other.
+ * We presume we are the sole user of this tty device, so
+ * when we close it, it will revert to its defaults anyway.
+ */
+ if (!default_device)
+ inittermios.c_lflag &= ~(ECHO | ECHONL);
+
+ if (tcsetattr(tty_fd, TCSAFLUSH, &inittermios) < 0) {
+ if (! ok_error (errno))
+ warn("tcsetattr: %m");
+ }
+ }
+}
+
+/********************************************************************
+ *
+ * output - Output PPP packet.
+ */
+
+void output (int unit, unsigned char *p, int len)
+{
+ int fd = ppp_fd;
+ int proto;
+
+ if (debug)
+ dbglog("sent %P", p, len);
+
+ if (len < PPP_HDRLEN)
+ return;
+ if (new_style_driver) {
+ p += 2;
+ len -= 2;
+ proto = (p[0] << 8) + p[1];
+ if (ifunit >= 0 && !(proto >= 0xc000 || proto == PPP_CCPFRAG))
+ fd = ppp_dev_fd;
+ }
+ if (write(fd, p, len) < 0) {
+ if (errno == EWOULDBLOCK || errno == ENOBUFS
+ || errno == ENXIO || errno == EIO || errno == EINTR)
+ warn("write: warning: %m (%d)", errno);
+ else
+ error("write: %m (%d)", errno);
+ }
+}
+
+/********************************************************************
+ *
+ * wait_input - wait until there is data available,
+ * for the length of time specified by *timo (indefinite
+ * if timo is NULL).
+ */
+
+void wait_input(struct timeval *timo)
+{
+ fd_set ready, exc;
+ int n;
+
+ ready = in_fds;
+ exc = in_fds;
+ n = select(max_in_fd + 1, &ready, NULL, &exc, timo);
+ if (n < 0 && errno != EINTR)
+ fatal("select: %m(%d)", errno);
+}
+
+/*
+ * add_fd - add an fd to the set that wait_input waits for.
+ */
+void add_fd(int fd)
+{
+ FD_SET(fd, &in_fds);
+ if (fd > max_in_fd)
+ max_in_fd = fd;
+}
+
+/*
+ * remove_fd - remove an fd from the set that wait_input waits for.
+ */
+void remove_fd(int fd)
+{
+ FD_CLR(fd, &in_fds);
+}
+
+
+/********************************************************************
+ *
+ * read_packet - get a PPP packet from the serial device.
+ */
+
+int read_packet (unsigned char *buf)
+{
+ int len, nr;
+
+ len = PPP_MRU + PPP_HDRLEN;
+ if (new_style_driver) {
+ *buf++ = PPP_ALLSTATIONS;
+ *buf++ = PPP_UI;
+ len -= 2;
+ }
+ nr = -1;
+ if (ppp_fd >= 0) {
+ nr = read(ppp_fd, buf, len);
+ if (nr < 0 && errno != EWOULDBLOCK && errno != EIO && errno != EINTR)
+ error("read: %m");
+ if (nr < 0 && errno == ENXIO)
+ return 0;
+ }
+ if (nr < 0 && new_style_driver && ifunit >= 0) {
+ /* N.B. we read ppp_fd first since LCP packets come in there. */
+ nr = read(ppp_dev_fd, buf, len);
+ if (nr < 0 && errno != EWOULDBLOCK && errno != EIO && errno != EINTR)
+ error("read /dev/ppp: %m");
+ if (nr < 0 && errno == ENXIO)
+ return 0;
+ }
+ return (new_style_driver && nr > 0)? nr+2: nr;
+}
+
+/********************************************************************
+ *
+ * get_loop_output - get outgoing packets from the ppp device,
+ * and detect when we want to bring the real link up.
+ * Return value is 1 if we need to bring up the link, 0 otherwise.
+ */
+int
+get_loop_output(void)
+{
+ int rv = 0;
+ int n;
+
+ if (new_style_driver) {
+ while ((n = read_packet(inpacket_buf)) > 0)
+ if (loop_frame(inpacket_buf, n))
+ rv = 1;
+ return rv;
+ }
+
+ while ((n = read(master_fd, inbuf, sizeof(inbuf))) > 0)
+ if (loop_chars(inbuf, n))
+ rv = 1;
+
+ if (n == 0)
+ fatal("eof on loopback");
+
+ if (errno != EWOULDBLOCK)
+ fatal("read from loopback: %m(%d)", errno);
+
+ return rv;
+}
+
+/*
+ * netif_set_mtu - set the MTU on the PPP network interface.
+ */
+void
+netif_set_mtu(int unit, int mtu)
+{
+ struct ifreq ifr;
+
+ SYSDEBUG ((LOG_DEBUG, "netif_set_mtu: mtu = %d\n", mtu));
+
+ memset (&ifr, '\0', sizeof (ifr));
+ strlcpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
+ ifr.ifr_mtu = mtu;
+
+ if (ifunit >= 0 && ioctl(sock_fd, SIOCSIFMTU, (caddr_t) &ifr) < 0)
+ fatal("ioctl(SIOCSIFMTU): %m");
+}
+
+/********************************************************************
+ *
+ * tty_send_config - configure the transmit characteristics of
+ * the ppp interface.
+ */
+
+void tty_send_config (int mtu,u_int32_t asyncmap,int pcomp,int accomp)
+{
+ u_int x;
+
+/*
+ * Set the asyncmap and other parameters for the ppp device
+ */
+ if (!still_ppp())
+ return;
+ link_mtu = mtu;
+ SYSDEBUG ((LOG_DEBUG, "send_config: asyncmap = %lx\n", asyncmap));
+ if (ioctl(ppp_fd, PPPIOCSASYNCMAP, (caddr_t) &asyncmap) < 0) {
+ if (!ok_error(errno))
+ fatal("ioctl(PPPIOCSASYNCMAP): %m(%d)", errno);
+ return;
+ }
+
+ x = get_flags(ppp_fd);
+ x = pcomp ? x | SC_COMP_PROT : x & ~SC_COMP_PROT;
+ x = accomp ? x | SC_COMP_AC : x & ~SC_COMP_AC;
+ x = sync_serial ? x | SC_SYNC : x & ~SC_SYNC;
+ set_flags(ppp_fd, x);
+}
+
+/********************************************************************
+ *
+ * tty_set_xaccm - set the extended transmit ACCM for the interface.
+ */
+
+void tty_set_xaccm (ext_accm accm)
+{
+ SYSDEBUG ((LOG_DEBUG, "set_xaccm: %08lx %08lx %08lx %08lx\n",
+ accm[0], accm[1], accm[2], accm[3]));
+
+ if (!still_ppp())
+ return;
+ if (ioctl(ppp_fd, PPPIOCSXASYNCMAP, accm) < 0 && errno != ENOTTY) {
+ if ( ! ok_error (errno))
+ warn("ioctl(set extended ACCM): %m(%d)", errno);
+ }
+}
+
+/********************************************************************
+ *
+ * tty_recv_config - configure the receive-side characteristics of
+ * the ppp interface.
+ */
+
+void tty_recv_config (int mru,u_int32_t asyncmap,int pcomp,int accomp)
+{
+ SYSDEBUG ((LOG_DEBUG, "recv_config: mru = %d\n", mru));
+/*
+ * If we were called because the link has gone down then there is nothing
+ * which may be done. Just return without incident.
+ */
+ if (!still_ppp())
+ return;
+/*
+ * Set the receiver parameters
+ */
+ if (ioctl(ppp_fd, PPPIOCSMRU, (caddr_t) &mru) < 0) {
+ if ( ! ok_error (errno))
+ error("ioctl(PPPIOCSMRU): %m(%d)", errno);
+ }
+ if (new_style_driver && ifunit >= 0
+ && ioctl(ppp_dev_fd, PPPIOCSMRU, (caddr_t) &mru) < 0)
+ error("Couldn't set MRU in generic PPP layer: %m");
+
+ SYSDEBUG ((LOG_DEBUG, "recv_config: asyncmap = %lx\n", asyncmap));
+ if (ioctl(ppp_fd, PPPIOCSRASYNCMAP, (caddr_t) &asyncmap) < 0) {
+ if (!ok_error(errno))
+ error("ioctl(PPPIOCSRASYNCMAP): %m(%d)", errno);
+ }
+}
+
+/********************************************************************
+ *
+ * ccp_test - ask kernel whether a given compression method
+ * is acceptable for use.
+ */
+
+int ccp_test (int unit, u_char *opt_ptr, int opt_len, int for_transmit)
+{
+ struct ppp_option_data data;
+
+ memset (&data, '\0', sizeof (data));
+ data.ptr = opt_ptr;
+ data.length = opt_len;
+ data.transmit = for_transmit;
+
+ if (ioctl(ppp_dev_fd, PPPIOCSCOMPRESS, (caddr_t) &data) >= 0)
+ return 1;
+
+ return (errno == ENOBUFS)? 0: -1;
+}
+
+/********************************************************************
+ *
+ * ccp_flags_set - inform kernel about the current state of CCP.
+ */
+
+void ccp_flags_set (int unit, int isopen, int isup)
+{
+ if (still_ppp()) {
+ int x = get_flags(ppp_dev_fd);
+ x = isopen? x | SC_CCP_OPEN : x &~ SC_CCP_OPEN;
+ x = isup? x | SC_CCP_UP : x &~ SC_CCP_UP;
+ set_flags (ppp_dev_fd, x);
+ }
+}
+
+#ifdef PPP_FILTER
+/*
+ * set_filters - set the active and pass filters in the kernel driver.
+ */
+int set_filters(struct bpf_program *pass, struct bpf_program *active)
+{
+ struct sock_fprog fp;
+
+ fp.len = pass->bf_len;
+ fp.filter = (struct sock_filter *) pass->bf_insns;
+ if (ioctl(ppp_dev_fd, PPPIOCSPASS, &fp) < 0) {
+ if (errno == ENOTTY)
+ warn("kernel does not support PPP filtering");
+ else
+ error("Couldn't set pass-filter in kernel: %m");
+ return 0;
+ }
+ fp.len = active->bf_len;
+ fp.filter = (struct sock_filter *) active->bf_insns;
+ if (ioctl(ppp_dev_fd, PPPIOCSACTIVE, &fp) < 0) {
+ error("Couldn't set active-filter in kernel: %m");
+ return 0;
+ }
+ return 1;
+}
+#endif /* PPP_FILTER */
+
+/********************************************************************
+ *
+ * get_idle_time - return how long the link has been idle.
+ */
+int
+get_idle_time(u, ip)
+ int u;
+ struct ppp_idle *ip;
+{
+ return ioctl(ppp_dev_fd, PPPIOCGIDLE, ip) >= 0;
+}
+
+/********************************************************************
+ *
+ * get_ppp_stats - return statistics for the link.
+ */
+int
+get_ppp_stats(u, stats)
+ int u;
+ struct pppd_stats *stats;
+{
+ struct ifpppstatsreq req;
+
+ memset (&req, 0, sizeof (req));
+
+ req.stats_ptr = (caddr_t) &req.stats;
+ strlcpy(req.ifr__name, ifname, sizeof(req.ifr__name));
+ if (ioctl(sock_fd, SIOCGPPPSTATS, &req) < 0) {
+ error("Couldn't get PPP statistics: %m");
+ return 0;
+ }
+ stats->bytes_in = req.stats.p.ppp_ibytes;
+ stats->bytes_out = req.stats.p.ppp_obytes;
+ return 1;
+}
+
+/********************************************************************
+ *
+ * ccp_fatal_error - returns 1 if decompression was disabled as a
+ * result of an error detected after decompression of a packet,
+ * 0 otherwise. This is necessary because of patent nonsense.
+ */
+
+int ccp_fatal_error (int unit)
+{
+ int x = get_flags(ppp_dev_fd);
+
+ return x & SC_DC_FERROR;
+}
+
+/********************************************************************
+ *
+ * path_to_procfs - find the path to the proc file system mount point
+ */
+static char proc_path[MAXPATHLEN];
+static int proc_path_len;
+
+static char *path_to_procfs(const char *tail)
+{
+ struct mntent *mntent;
+ FILE *fp;
+
+ if (proc_path_len == 0) {
+ /* Default the mount location of /proc */
+ strlcpy (proc_path, "/proc", sizeof(proc_path));
+ proc_path_len = 5;
+ fp = fopen(MOUNTED, "r");
+ if (fp != NULL) {
+ while ((mntent = getmntent(fp)) != NULL) {
+ if (strcmp(mntent->mnt_type, MNTTYPE_IGNORE) == 0)
+ continue;
+ if (strcmp(mntent->mnt_type, "proc") == 0) {
+ strlcpy(proc_path, mntent->mnt_dir, sizeof(proc_path));
+ proc_path_len = strlen(proc_path);
+ break;
+ }
+ }
+ fclose (fp);
+ }
+ }
+
+ strlcpy(proc_path + proc_path_len, tail,
+ sizeof(proc_path) - proc_path_len);
+ return proc_path;
+}
+
+/*
+ * /proc/net/route parsing stuff.
+ */
+#define ROUTE_MAX_COLS 12
+FILE *route_fd = (FILE *) 0;
+static char route_buffer[512];
+static int route_dev_col, route_dest_col, route_gw_col;
+static int route_flags_col, route_mask_col;
+static int route_num_cols;
+
+static int open_route_table (void);
+static void close_route_table (void);
+static int read_route_table (struct rtentry *rt);
+
+/********************************************************************
+ *
+ * close_route_table - close the interface to the route table
+ */
+
+static void close_route_table (void)
+{
+ if (route_fd != (FILE *) 0) {
+ fclose (route_fd);
+ route_fd = (FILE *) 0;
+ }
+}
+
+/********************************************************************
+ *
+ * open_route_table - open the interface to the route table
+ */
+static char route_delims[] = " \t\n";
+
+static int open_route_table (void)
+{
+ char *path;
+
+ close_route_table();
+
+ path = path_to_procfs("/net/route");
+ route_fd = fopen (path, "r");
+ if (route_fd == NULL) {
+ error("can't open routing table %s: %m", path);
+ return 0;
+ }
+
+ route_dev_col = 0; /* default to usual columns */
+ route_dest_col = 1;
+ route_gw_col = 2;
+ route_flags_col = 3;
+ route_mask_col = 7;
+ route_num_cols = 8;
+
+ /* parse header line */
+ if (fgets(route_buffer, sizeof(route_buffer), route_fd) != 0) {
+ char *p = route_buffer, *q;
+ int col;
+ for (col = 0; col < ROUTE_MAX_COLS; ++col) {
+ int used = 1;
+ if ((q = strtok(p, route_delims)) == 0)
+ break;
+ if (strcasecmp(q, "iface") == 0)
+ route_dev_col = col;
+ else if (strcasecmp(q, "destination") == 0)
+ route_dest_col = col;
+ else if (strcasecmp(q, "gateway") == 0)
+ route_gw_col = col;
+ else if (strcasecmp(q, "flags") == 0)
+ route_flags_col = col;
+ else if (strcasecmp(q, "mask") == 0)
+ route_mask_col = col;
+ else
+ used = 0;
+ if (used && col >= route_num_cols)
+ route_num_cols = col + 1;
+ p = NULL;
+ }
+ }
+
+ return 1;
+}
+
+/********************************************************************
+ *
+ * read_route_table - read the next entry from the route table
+ */
+
+static int read_route_table(struct rtentry *rt)
+{
+ char *cols[ROUTE_MAX_COLS], *p;
+ int col;
+
+ memset (rt, '\0', sizeof (struct rtentry));
+
+ if (fgets (route_buffer, sizeof (route_buffer), route_fd) == (char *) 0)
+ return 0;
+
+ p = route_buffer;
+ for (col = 0; col < route_num_cols; ++col) {
+ cols[col] = strtok(p, route_delims);
+ if (cols[col] == NULL)
+ return 0; /* didn't get enough columns */
+ p = NULL;
+ }
+
+ SIN_ADDR(rt->rt_dst) = strtoul(cols[route_dest_col], NULL, 16);
+ SIN_ADDR(rt->rt_gateway) = strtoul(cols[route_gw_col], NULL, 16);
+ SIN_ADDR(rt->rt_genmask) = strtoul(cols[route_mask_col], NULL, 16);
+
+ rt->rt_flags = (short) strtoul(cols[route_flags_col], NULL, 16);
+ rt->rt_dev = cols[route_dev_col];
+
+ return 1;
+}
+
+/********************************************************************
+ *
+ * defaultroute_exists - determine if there is a default route
+ */
+
+static int defaultroute_exists (struct rtentry *rt)
+{
+ int result = 0;
+
+ if (!open_route_table())
+ return 0;
+
+ while (read_route_table(rt) != 0) {
+ if ((rt->rt_flags & RTF_UP) == 0)
+ continue;
+
+ if (kernel_version > KVERSION(2,1,0) && SIN_ADDR(rt->rt_genmask) != 0)
+ continue;
+ if (SIN_ADDR(rt->rt_dst) == 0L) {
+ result = 1;
+ break;
+ }
+ }
+
+ close_route_table();
+ return result;
+}
+
+/*
+ * have_route_to - determine if the system has any route to
+ * a given IP address. `addr' is in network byte order.
+ * Return value is 1 if yes, 0 if no, -1 if don't know.
+ * For demand mode to work properly, we have to ignore routes
+ * through our own interface.
+ */
+int have_route_to(u_int32_t addr)
+{
+ struct rtentry rt;
+ int result = 0;
+
+ if (!open_route_table())
+ return -1; /* don't know */
+
+ while (read_route_table(&rt)) {
+ if ((rt.rt_flags & RTF_UP) == 0 || strcmp(rt.rt_dev, ifname) == 0)
+ continue;
+ if ((addr & SIN_ADDR(rt.rt_genmask)) == SIN_ADDR(rt.rt_dst)) {
+ result = 1;
+ break;
+ }
+ }
+
+ close_route_table();
+ return result;
+}
+
+/********************************************************************
+ *
+ * sifdefaultroute - assign a default route through the address given.
+ */
+
+int sifdefaultroute (int unit, u_int32_t ouraddr, u_int32_t gateway)
+{
+ struct rtentry rt;
+
+ if (defaultroute_exists(&rt) && strcmp(rt.rt_dev, ifname) != 0) {
+ u_int32_t old_gateway = SIN_ADDR(rt.rt_gateway);
+
+ if (old_gateway != gateway)
+ error("not replacing existing default route to %s [%I]",
+ rt.rt_dev, old_gateway);
+ return 0;
+ }
+
+ memset (&rt, '\0', sizeof (rt));
+ SET_SA_FAMILY (rt.rt_dst, AF_INET);
+ SET_SA_FAMILY (rt.rt_gateway, AF_INET);
+
+ if (kernel_version > KVERSION(2,1,0)) {
+ SET_SA_FAMILY (rt.rt_genmask, AF_INET);
+ SIN_ADDR(rt.rt_genmask) = 0L;
+ }
+
+ SIN_ADDR(rt.rt_gateway) = gateway;
+
+ rt.rt_flags = RTF_UP | RTF_GATEWAY;
+ if (ioctl(sock_fd, SIOCADDRT, &rt) < 0) {
+ if ( ! ok_error ( errno ))
+ error("default route ioctl(SIOCADDRT): %m(%d)", errno);
+ return 0;
+ }
+
+ default_route_gateway = gateway;
+ return 1;
+}
+
+/********************************************************************
+ *
+ * cifdefaultroute - delete a default route through the address given.
+ */
+
+int cifdefaultroute (int unit, u_int32_t ouraddr, u_int32_t gateway)
+{
+ struct rtentry rt;
+
+ default_route_gateway = 0;
+
+ memset (&rt, '\0', sizeof (rt));
+ SET_SA_FAMILY (rt.rt_dst, AF_INET);
+ SET_SA_FAMILY (rt.rt_gateway, AF_INET);
+
+ if (kernel_version > KVERSION(2,1,0)) {
+ SET_SA_FAMILY (rt.rt_genmask, AF_INET);
+ SIN_ADDR(rt.rt_genmask) = 0L;
+ }
+
+ SIN_ADDR(rt.rt_gateway) = gateway;
+
+ rt.rt_flags = RTF_UP | RTF_GATEWAY;
+ if (ioctl(sock_fd, SIOCDELRT, &rt) < 0 && errno != ESRCH) {
+ if (still_ppp()) {
+ if ( ! ok_error ( errno ))
+ error("default route ioctl(SIOCDELRT): %m (%d)", errno);
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+/********************************************************************
+ *
+ * sifproxyarp - Make a proxy ARP entry for the peer.
+ */
+
+int sifproxyarp (int unit, u_int32_t his_adr)
+{
+ struct arpreq arpreq;
+ char *forw_path;
+
+ if (has_proxy_arp == 0) {
+ memset (&arpreq, '\0', sizeof(arpreq));
+
+ SET_SA_FAMILY(arpreq.arp_pa, AF_INET);
+ SIN_ADDR(arpreq.arp_pa) = his_adr;
+ arpreq.arp_flags = ATF_PERM | ATF_PUBL;
+/*
+ * Get the hardware address of an interface on the same subnet
+ * as our local address.
+ */
+ if (!get_ether_addr(his_adr, &arpreq.arp_ha, proxy_arp_dev,
+ sizeof(proxy_arp_dev))) {
+ error("Cannot determine ethernet address for proxy ARP");
+ return 0;
+ }
+ strlcpy(arpreq.arp_dev, proxy_arp_dev, sizeof(arpreq.arp_dev));
+
+ if (ioctl(sock_fd, SIOCSARP, (caddr_t)&arpreq) < 0) {
+ if ( ! ok_error ( errno ))
+ error("ioctl(SIOCSARP): %m(%d)", errno);
+ return 0;
+ }
+ proxy_arp_addr = his_adr;
+ has_proxy_arp = 1;
+
+ if (tune_kernel) {
+ forw_path = path_to_procfs("/sys/net/ipv4/ip_forward");
+ if (forw_path != 0) {
+ int fd = open(forw_path, O_WRONLY);
+ if (fd >= 0) {
+ if (write(fd, "1", 1) != 1)
+ error("Couldn't enable IP forwarding: %m");
+ close(fd);
+ }
+ }
+ }
+ }
+
+ return 1;
+}
+
+/********************************************************************
+ *
+ * cifproxyarp - Delete the proxy ARP entry for the peer.
+ */
+
+int cifproxyarp (int unit, u_int32_t his_adr)
+{
+ struct arpreq arpreq;
+
+ if (has_proxy_arp) {
+ has_proxy_arp = 0;
+ memset (&arpreq, '\0', sizeof(arpreq));
+ SET_SA_FAMILY(arpreq.arp_pa, AF_INET);
+ SIN_ADDR(arpreq.arp_pa) = his_adr;
+ arpreq.arp_flags = ATF_PERM | ATF_PUBL;
+ strlcpy(arpreq.arp_dev, proxy_arp_dev, sizeof(arpreq.arp_dev));
+
+ if (ioctl(sock_fd, SIOCDARP, (caddr_t)&arpreq) < 0) {
+ if ( ! ok_error ( errno ))
+ warn("ioctl(SIOCDARP): %m(%d)", errno);
+ return 0;
+ }
+ }
+ return 1;
+}
+
+/********************************************************************
+ *
+ * get_ether_addr - get the hardware address of an interface on the
+ * the same subnet as ipaddr.
+ */
+
+static int get_ether_addr (u_int32_t ipaddr,
+ struct sockaddr *hwaddr,
+ char *name, int namelen)
+{
+ struct ifreq *ifr, *ifend;
+ u_int32_t ina, mask;
+ char *aliasp;
+ struct ifreq ifreq;
+ struct ifconf ifc;
+ struct ifreq ifs[MAX_IFS];
+
+ ifc.ifc_len = sizeof(ifs);
+ ifc.ifc_req = ifs;
+ if (ioctl(sock_fd, SIOCGIFCONF, &ifc) < 0) {
+ if ( ! ok_error ( errno ))
+ error("ioctl(SIOCGIFCONF): %m(%d)", errno);
+ return 0;
+ }
+
+ SYSDEBUG ((LOG_DEBUG, "proxy arp: scanning %d interfaces for IP %s",
+ ifc.ifc_len / sizeof(struct ifreq), ip_ntoa(ipaddr)));
+/*
+ * Scan through looking for an interface with an Internet
+ * address on the same subnet as `ipaddr'.
+ */
+ ifend = ifs + (ifc.ifc_len / sizeof(struct ifreq));
+ for (ifr = ifc.ifc_req; ifr < ifend; ifr++) {
+ if (ifr->ifr_addr.sa_family == AF_INET) {
+ ina = SIN_ADDR(ifr->ifr_addr);
+ strlcpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name));
+ SYSDEBUG ((LOG_DEBUG, "proxy arp: examining interface %s",
+ ifreq.ifr_name));
+/*
+ * Check that the interface is up, and not point-to-point
+ * nor loopback.
+ */
+ if (ioctl(sock_fd, SIOCGIFFLAGS, &ifreq) < 0)
+ continue;
+
+ if (((ifreq.ifr_flags ^ FLAGS_GOOD) & FLAGS_MASK) != 0)
+ continue;
+/*
+ * Get its netmask and check that it's on the right subnet.
+ */
+ if (ioctl(sock_fd, SIOCGIFNETMASK, &ifreq) < 0)
+ continue;
+
+ mask = SIN_ADDR(ifreq.ifr_addr);
+ SYSDEBUG ((LOG_DEBUG, "proxy arp: interface addr %s mask %lx",
+ ip_ntoa(ina), ntohl(mask)));
+
+ if (((ipaddr ^ ina) & mask) != 0)
+ continue;
+ break;
+ }
+ }
+
+ if (ifr >= ifend)
+ return 0;
+
+ strlcpy(name, ifreq.ifr_name, namelen);
+
+ /* trim off the :1 in eth0:1 */
+ aliasp = strchr(name, ':');
+ if (aliasp != 0)
+ *aliasp = 0;
+
+ info("found interface %s for proxy arp", name);
+/*
+ * Now get the hardware address.
+ */
+ memset (&ifreq.ifr_hwaddr, 0, sizeof (struct sockaddr));
+ if (ioctl (sock_fd, SIOCGIFHWADDR, &ifreq) < 0) {
+ error("SIOCGIFHWADDR(%s): %m(%d)", ifreq.ifr_name, errno);
+ return 0;
+ }
+
+ memcpy (hwaddr,
+ &ifreq.ifr_hwaddr,
+ sizeof (struct sockaddr));
+
+ SYSDEBUG ((LOG_DEBUG,
+ "proxy arp: found hwaddr %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
+ (int) ((unsigned char *) &hwaddr->sa_data)[0],
+ (int) ((unsigned char *) &hwaddr->sa_data)[1],
+ (int) ((unsigned char *) &hwaddr->sa_data)[2],
+ (int) ((unsigned char *) &hwaddr->sa_data)[3],
+ (int) ((unsigned char *) &hwaddr->sa_data)[4],
+ (int) ((unsigned char *) &hwaddr->sa_data)[5],
+ (int) ((unsigned char *) &hwaddr->sa_data)[6],
+ (int) ((unsigned char *) &hwaddr->sa_data)[7]));
+ return 1;
+}
+
+/*
+ * get_if_hwaddr - get the hardware address for the specified
+ * network interface device.
+ */
+int
+get_if_hwaddr(u_char *addr, char *name)
+{
+ struct ifreq ifreq;
+ int ret, sock_fd;
+
+ sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (sock_fd < 0)
+ return 0;
+ memset(&ifreq.ifr_hwaddr, 0, sizeof(struct sockaddr));
+ strlcpy(ifreq.ifr_name, name, sizeof(ifreq.ifr_name));
+ ret = ioctl(sock_fd, SIOCGIFHWADDR, &ifreq);
+ close(sock_fd);
+ if (ret >= 0)
+ memcpy(addr, ifreq.ifr_hwaddr.sa_data, 6);
+ return ret;
+}
+
+/*
+ * get_first_ethernet - return the name of the first ethernet-style
+ * interface on this system.
+ */
+char *
+get_first_ethernet()
+{
+ return "eth0";
+}
+
+/********************************************************************
+ *
+ * Return user specified netmask, modified by any mask we might determine
+ * for address `addr' (in network byte order).
+ * Here we scan through the system's list of interfaces, looking for
+ * any non-point-to-point interfaces which might appear to be on the same
+ * network as `addr'. If we find any, we OR in their netmask to the
+ * user-specified netmask.
+ */
+
+u_int32_t GetMask (u_int32_t addr)
+{
+ u_int32_t mask, nmask, ina;
+ struct ifreq *ifr, *ifend, ifreq;
+ struct ifconf ifc;
+ struct ifreq ifs[MAX_IFS];
+
+ addr = ntohl(addr);
+
+ if (IN_CLASSA(addr)) /* determine network mask for address class */
+ nmask = IN_CLASSA_NET;
+ else if (IN_CLASSB(addr))
+ nmask = IN_CLASSB_NET;
+ else
+ nmask = IN_CLASSC_NET;
+
+ /* class D nets are disallowed by bad_ip_adrs */
+ mask = netmask | htonl(nmask);
+/*
+ * Scan through the system's network interfaces.
+ */
+ ifc.ifc_len = sizeof(ifs);
+ ifc.ifc_req = ifs;
+ if (ioctl(sock_fd, SIOCGIFCONF, &ifc) < 0) {
+ if ( ! ok_error ( errno ))
+ warn("ioctl(SIOCGIFCONF): %m(%d)", errno);
+ return mask;
+ }
+
+ ifend = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len);
+ for (ifr = ifc.ifc_req; ifr < ifend; ifr++) {
+/*
+ * Check the interface's internet address.
+ */
+ if (ifr->ifr_addr.sa_family != AF_INET)
+ continue;
+ ina = SIN_ADDR(ifr->ifr_addr);
+ if (((ntohl(ina) ^ addr) & nmask) != 0)
+ continue;
+/*
+ * Check that the interface is up, and not point-to-point nor loopback.
+ */
+ strlcpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name));
+ if (ioctl(sock_fd, SIOCGIFFLAGS, &ifreq) < 0)
+ continue;
+
+ if (((ifreq.ifr_flags ^ FLAGS_GOOD) & FLAGS_MASK) != 0)
+ continue;
+/*
+ * Get its netmask and OR it into our mask.
+ */
+ if (ioctl(sock_fd, SIOCGIFNETMASK, &ifreq) < 0)
+ continue;
+ mask |= SIN_ADDR(ifreq.ifr_addr);
+ break;
+ }
+ return mask;
+}
+
+/********************************************************************
+ *
+ * Internal routine to decode the version.modification.patch level
+ */
+
+static void decode_version (char *buf, int *version,
+ int *modification, int *patch)
+{
+ char *endp;
+
+ *version = (int) strtoul (buf, &endp, 10);
+ *modification = 0;
+ *patch = 0;
+
+ if (endp != buf && *endp == '.') {
+ buf = endp + 1;
+ *modification = (int) strtoul (buf, &endp, 10);
+ if (endp != buf && *endp == '.') {
+ buf = endp + 1;
+ *patch = (int) strtoul (buf, &buf, 10);
+ }
+ }
+}
+
+/********************************************************************
+ *
+ * Procedure to determine if the PPP line discipline is registered.
+ */
+
+static int
+ppp_registered(void)
+{
+ int local_fd;
+ int mfd = -1;
+ int ret = 0;
+ char slave[16];
+
+ /*
+ * We used to open the serial device and set it to the ppp line
+ * discipline here, in order to create a ppp unit. But that is
+ * not a good idea - the user might have specified a device that
+ * they can't open (permission, or maybe it doesn't really exist).
+ * So we grab a pty master/slave pair and use that.
+ */
+ if (!get_pty(&mfd, &local_fd, slave, 0)) {
+ no_ppp_msg = "Couldn't determine if PPP is supported (no free ptys)";
+ return 0;
+ }
+
+ /*
+ * Try to put the device into the PPP discipline.
+ */
+ if (ioctl(local_fd, TIOCSETD, &ppp_disc) < 0) {
+ error("ioctl(TIOCSETD(PPP)): %m(%d)", errno);
+ } else
+ ret = 1;
+
+ close(local_fd);
+ close(mfd);
+ return ret;
+}
+
+/********************************************************************
+ *
+ * ppp_available - check whether the system has any ppp interfaces
+ * (in fact we check whether we can do an ioctl on ppp0).
+ */
+
+int ppp_available(void)
+{
+ int s, ok, fd;
+ struct ifreq ifr;
+ int size;
+ int my_version, my_modification, my_patch;
+ int osmaj, osmin, ospatch;
+
+ no_ppp_msg =
+ "This system lacks kernel support for PPP. This could be because\n"
+ "the PPP kernel module could not be loaded, or because PPP was not\n"
+ "included in the kernel configuration. If PPP was included as a\n"
+ "module, try `/sbin/modprobe -v ppp'. If that fails, check that\n"
+ "ppp.o exists in /lib/modules/`uname -r`/net.\n"
+ "See README.linux file in the ppp distribution for more details.\n";
+
+ /* get the kernel version now, since we are called before sys_init */
+ uname(&utsname);
+ osmaj = osmin = ospatch = 0;
+ sscanf(utsname.release, "%d.%d.%d", &osmaj, &osmin, &ospatch);
+ kernel_version = KVERSION(osmaj, osmin, ospatch);
+
+ fd = open("/dev/ppp", O_RDWR);
+#if 0
+ if (fd < 0 && errno == ENOENT) {
+ /* try making it and see if that helps. */
+ if (mknod("/dev/ppp", S_IFCHR | S_IRUSR | S_IWUSR,
+ makedev(108, 0)) >= 0) {
+ fd = open("/dev/ppp", O_RDWR);
+ if (fd >= 0)
+ info("Created /dev/ppp device node");
+ else
+ unlink("/dev/ppp"); /* didn't work, undo the mknod */
+ } else if (errno == EEXIST) {
+ fd = open("/dev/ppp", O_RDWR);
+ }
+ }
+#endif /* 0 */
+ if (fd >= 0) {
+ new_style_driver = 1;
+
+ /* XXX should get from driver */
+ driver_version = 2;
+ driver_modification = 4;
+ driver_patch = 0;
+ close(fd);
+ return 1;
+ }
+ if (kernel_version >= KVERSION(2,3,13)) {
+ if (errno == ENOENT)
+ no_ppp_msg =
+ "pppd is unable to open the /dev/ppp device.\n"
+ "You need to create the /dev/ppp device node by\n"
+ "executing the following command as root:\n"
+ " mknod /dev/ppp c 108 0\n";
+ return 0;
+ }
+
+/*
+ * Open a socket for doing the ioctl operations.
+ */
+ s = socket(AF_INET, SOCK_DGRAM, 0);
+ if (s < 0)
+ return 0;
+
+ strlcpy (ifr.ifr_name, "ppp0", sizeof (ifr.ifr_name));
+ ok = ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) >= 0;
+/*
+ * If the device did not exist then attempt to create one by putting the
+ * current tty into the PPP discipline. If this works then obtain the
+ * flags for the device again.
+ */
+ if (!ok) {
+ if (ppp_registered()) {
+ strlcpy (ifr.ifr_name, "ppp0", sizeof (ifr.ifr_name));
+ ok = ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) >= 0;
+ }
+ }
+/*
+ * Ensure that the hardware address is for PPP and not something else
+ */
+ if (ok)
+ ok = ioctl (s, SIOCGIFHWADDR, (caddr_t) &ifr) >= 0;
+
+ if (ok && ((ifr.ifr_hwaddr.sa_family & ~0xFF) != ARPHRD_PPP))
+ ok = 0;
+
+/*
+ * This is the PPP device. Validate the version of the driver at this
+ * point to ensure that this program will work with the driver.
+ */
+ if (ok) {
+ char abBuffer [1024];
+
+ ifr.ifr_data = abBuffer;
+ size = ioctl (s, SIOCGPPPVER, (caddr_t) &ifr);
+ if (size < 0) {
+ error("Couldn't read driver version: %m");
+ ok = 0;
+ no_ppp_msg = "Sorry, couldn't verify kernel driver version\n";
+
+ } else {
+ decode_version(abBuffer,
+ &driver_version,
+ &driver_modification,
+ &driver_patch);
+/*
+ * Validate the version of the driver against the version that we used.
+ */
+ decode_version(VERSION,
+ &my_version,
+ &my_modification,
+ &my_patch);
+
+ /* The version numbers must match */
+ if (driver_version != my_version)
+ ok = 0;
+
+ /* The modification levels must be legal */
+ if (driver_modification < 3) {
+ if (driver_modification >= 2) {
+ /* we can cope with 2.2.0 and above */
+ driver_is_old = 1;
+ } else {
+ ok = 0;
+ }
+ }
+
+ close (s);
+ if (!ok) {
+ slprintf(route_buffer, sizeof(route_buffer),
+ "Sorry - PPP driver version %d.%d.%d is out of date\n",
+ driver_version, driver_modification, driver_patch);
+
+ no_ppp_msg = route_buffer;
+ }
+ }
+ }
+ return ok;
+}
+
+/********************************************************************
+ *
+ * sifvjcomp - config tcp header compression
+ */
+
+int sifvjcomp (int u, int vjcomp, int cidcomp, int maxcid)
+{
+ u_int x = get_flags(ppp_dev_fd);
+
+ if (vjcomp) {
+ if (ioctl (ppp_dev_fd, PPPIOCSMAXCID, (caddr_t) &maxcid) < 0) {
+ if (! ok_error (errno))
+ error("ioctl(PPPIOCSMAXCID): %m(%d)", errno);
+ vjcomp = 0;
+ }
+ }
+
+ x = vjcomp ? x | SC_COMP_TCP : x &~ SC_COMP_TCP;
+ x = cidcomp ? x & ~SC_NO_TCP_CCID : x | SC_NO_TCP_CCID;
+ set_flags (ppp_dev_fd, x);
+
+ return 1;
+}
+
+/********************************************************************
+ *
+ * sifup - Config the interface up and enable IP packets to pass.
+ */
+
+int sifup(int u)
+{
+ struct ifreq ifr;
+
+ memset (&ifr, '\0', sizeof (ifr));
+ strlcpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
+ if (ioctl(sock_fd, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
+ if (! ok_error (errno))
+ error("ioctl (SIOCGIFFLAGS): %m(%d)", errno);
+ return 0;
+ }
+
+ ifr.ifr_flags |= (IFF_UP | IFF_POINTOPOINT);
+ if (ioctl(sock_fd, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
+ if (! ok_error (errno))
+ error("ioctl(SIOCSIFFLAGS): %m(%d)", errno);
+ return 0;
+ }
+ if_is_up++;
+
+ return 1;
+}
+
+/********************************************************************
+ *
+ * sifdown - Disable the indicated protocol and config the interface
+ * down if there are no remaining protocols.
+ */
+
+int sifdown (int u)
+{
+ struct ifreq ifr;
+
+ if (if_is_up && --if_is_up > 0)
+ return 1;
+
+ memset (&ifr, '\0', sizeof (ifr));
+ strlcpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
+ if (ioctl(sock_fd, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
+ if (! ok_error (errno))
+ error("ioctl (SIOCGIFFLAGS): %m(%d)", errno);
+ return 0;
+ }
+
+ ifr.ifr_flags &= ~IFF_UP;
+ ifr.ifr_flags |= IFF_POINTOPOINT;
+ if (ioctl(sock_fd, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
+ if (! ok_error (errno))
+ error("ioctl(SIOCSIFFLAGS): %m(%d)", errno);
+ return 0;
+ }
+ return 1;
+}
+
+/********************************************************************
+ *
+ * sifaddr - Config the interface IP addresses and netmask.
+ */
+
+int sifaddr (int unit, u_int32_t our_adr, u_int32_t his_adr,
+ u_int32_t net_mask)
+{
+ struct ifreq ifr;
+ struct rtentry rt;
+
+ memset (&ifr, '\0', sizeof (ifr));
+ memset (&rt, '\0', sizeof (rt));
+
+ SET_SA_FAMILY (ifr.ifr_addr, AF_INET);
+ SET_SA_FAMILY (ifr.ifr_dstaddr, AF_INET);
+ SET_SA_FAMILY (ifr.ifr_netmask, AF_INET);
+
+ strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
+/*
+ * Set our IP address
+ */
+ SIN_ADDR(ifr.ifr_addr) = our_adr;
+ if (ioctl(sock_fd, SIOCSIFADDR, (caddr_t) &ifr) < 0) {
+ if (errno != EEXIST) {
+ if (! ok_error (errno))
+ error("ioctl(SIOCSIFADDR): %m(%d)", errno);
+ }
+ else {
+ warn("ioctl(SIOCSIFADDR): Address already exists");
+ }
+ return (0);
+ }
+/*
+ * Set the gateway address
+ */
+ SIN_ADDR(ifr.ifr_dstaddr) = his_adr;
+ if (ioctl(sock_fd, SIOCSIFDSTADDR, (caddr_t) &ifr) < 0) {
+ if (! ok_error (errno))
+ error("ioctl(SIOCSIFDSTADDR): %m(%d)", errno);
+ return (0);
+ }
+/*
+ * Set the netmask.
+ * For recent kernels, force the netmask to 255.255.255.255.
+ */
+ if (kernel_version >= KVERSION(2,1,16))
+ net_mask = ~0L;
+ if (net_mask != 0) {
+ SIN_ADDR(ifr.ifr_netmask) = net_mask;
+ if (ioctl(sock_fd, SIOCSIFNETMASK, (caddr_t) &ifr) < 0) {
+ if (! ok_error (errno))
+ error("ioctl(SIOCSIFNETMASK): %m(%d)", errno);
+ return (0);
+ }
+ }
+/*
+ * Add the device route
+ */
+ if (kernel_version < KVERSION(2,1,16)) {
+ SET_SA_FAMILY (rt.rt_dst, AF_INET);
+ SET_SA_FAMILY (rt.rt_gateway, AF_INET);
+ rt.rt_dev = ifname;
+
+ SIN_ADDR(rt.rt_gateway) = 0L;
+ SIN_ADDR(rt.rt_dst) = his_adr;
+ rt.rt_flags = RTF_UP | RTF_HOST;
+
+ if (kernel_version > KVERSION(2,1,0)) {
+ SET_SA_FAMILY (rt.rt_genmask, AF_INET);
+ SIN_ADDR(rt.rt_genmask) = -1L;
+ }
+
+ if (ioctl(sock_fd, SIOCADDRT, &rt) < 0) {
+ if (! ok_error (errno))
+ error("ioctl(SIOCADDRT) device route: %m(%d)", errno);
+ return (0);
+ }
+ }
+
+ /* set ip_dynaddr in demand mode if address changes */
+ if (demand && tune_kernel && !dynaddr_set
+ && our_old_addr && our_old_addr != our_adr) {
+ /* set ip_dynaddr if possible */
+ char *path;
+ int fd;
+
+ path = path_to_procfs("/sys/net/ipv4/ip_dynaddr");
+ if (path != 0 && (fd = open(path, O_WRONLY)) >= 0) {
+ if (write(fd, "1", 1) != 1)
+ error("Couldn't enable dynamic IP addressing: %m");
+ close(fd);
+ }
+ dynaddr_set = 1; /* only 1 attempt */
+ }
+ our_old_addr = 0;
+
+ return 1;
+}
+
+/********************************************************************
+ *
+ * cifaddr - Clear the interface IP addresses, and delete routes
+ * through the interface if possible.
+ */
+
+int cifaddr (int unit, u_int32_t our_adr, u_int32_t his_adr)
+{
+ struct ifreq ifr;
+
+ if (kernel_version < KVERSION(2,1,16)) {
+/*
+ * Delete the route through the device
+ */
+ struct rtentry rt;
+ memset (&rt, '\0', sizeof (rt));
+
+ SET_SA_FAMILY (rt.rt_dst, AF_INET);
+ SET_SA_FAMILY (rt.rt_gateway, AF_INET);
+ rt.rt_dev = ifname;
+
+ SIN_ADDR(rt.rt_gateway) = 0;
+ SIN_ADDR(rt.rt_dst) = his_adr;
+ rt.rt_flags = RTF_UP | RTF_HOST;
+
+ if (kernel_version > KVERSION(2,1,0)) {
+ SET_SA_FAMILY (rt.rt_genmask, AF_INET);
+ SIN_ADDR(rt.rt_genmask) = -1L;
+ }
+
+ if (ioctl(sock_fd, SIOCDELRT, &rt) < 0 && errno != ESRCH) {
+ if (still_ppp() && ! ok_error (errno))
+ error("ioctl(SIOCDELRT) device route: %m(%d)", errno);
+ return (0);
+ }
+ }
+
+ /* This way it is possible to have an IPX-only or IPv6-only interface */
+ memset(&ifr, 0, sizeof(ifr));
+ SET_SA_FAMILY(ifr.ifr_addr, AF_INET);
+ strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+
+ if (ioctl(sock_fd, SIOCSIFADDR, (caddr_t) &ifr) < 0) {
+ if (! ok_error (errno)) {
+ error("ioctl(SIOCSIFADDR): %m(%d)", errno);
+ return 0;
+ }
+ }
+
+ our_old_addr = our_adr;
+
+ return 1;
+}
+
+#ifdef INET6
+/********************************************************************
+ *
+ * sif6addr - Config the interface with an IPv6 link-local address
+ */
+int sif6addr (int unit, eui64_t our_eui64, eui64_t his_eui64)
+{
+ struct in6_ifreq ifr6;
+ struct ifreq ifr;
+ struct in6_rtmsg rt6;
+
+ if (sock6_fd < 0) {
+ errno = -sock6_fd;
+ error("IPv6 socket creation failed: %m");
+ return 0;
+ }
+ memset(&ifr, 0, sizeof (ifr));
+ strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+ if (ioctl(sock6_fd, SIOCGIFINDEX, (caddr_t) &ifr) < 0) {
+ error("sif6addr: ioctl(SIOCGIFINDEX): %m (%d)", errno);
+ return 0;
+ }
+
+ /* Local interface */
+ memset(&ifr6, 0, sizeof(ifr6));
+ IN6_LLADDR_FROM_EUI64(ifr6.ifr6_addr, our_eui64);
+ ifr6.ifr6_ifindex = ifr.ifr_ifindex;
+ ifr6.ifr6_prefixlen = 10;
+
+ if (ioctl(sock6_fd, SIOCSIFADDR, &ifr6) < 0) {
+ error("sif6addr: ioctl(SIOCSIFADDR): %m (%d)", errno);
+ return 0;
+ }
+
+ /* Route to remote host */
+ memset(&rt6, 0, sizeof(rt6));
+ IN6_LLADDR_FROM_EUI64(rt6.rtmsg_dst, his_eui64);
+ rt6.rtmsg_flags = RTF_UP;
+ rt6.rtmsg_dst_len = 10;
+ rt6.rtmsg_ifindex = ifr.ifr_ifindex;
+ rt6.rtmsg_metric = 1;
+
+ if (ioctl(sock6_fd, SIOCADDRT, &rt6) < 0) {
+ error("sif6addr: ioctl(SIOCADDRT): %m (%d)", errno);
+ return 0;
+ }
+
+ return 1;
+}
+
+
+/********************************************************************
+ *
+ * cif6addr - Remove IPv6 address from interface
+ */
+int cif6addr (int unit, eui64_t our_eui64, eui64_t his_eui64)
+{
+ struct ifreq ifr;
+ struct in6_ifreq ifr6;
+
+ if (sock6_fd < 0) {
+ errno = -sock6_fd;
+ error("IPv6 socket creation failed: %m");
+ return 0;
+ }
+ memset(&ifr, 0, sizeof(ifr));
+ strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+ if (ioctl(sock6_fd, SIOCGIFINDEX, (caddr_t) &ifr) < 0) {
+ error("cif6addr: ioctl(SIOCGIFINDEX): %m (%d)", errno);
+ return 0;
+ }
+
+ memset(&ifr6, 0, sizeof(ifr6));
+ IN6_LLADDR_FROM_EUI64(ifr6.ifr6_addr, our_eui64);
+ ifr6.ifr6_ifindex = ifr.ifr_ifindex;
+ ifr6.ifr6_prefixlen = 10;
+
+ if (ioctl(sock6_fd, SIOCDIFADDR, &ifr6) < 0) {
+ if (errno != EADDRNOTAVAIL) {
+ if (! ok_error (errno))
+ error("cif6addr: ioctl(SIOCDIFADDR): %m (%d)", errno);
+ }
+ else {
+ warn("cif6addr: ioctl(SIOCDIFADDR): No such address");
+ }
+ return (0);
+ }
+ return 1;
+}
+#endif /* INET6 */
+
+/*
+ * get_pty - get a pty master/slave pair and chown the slave side
+ * to the uid given. Assumes slave_name points to >= 16 bytes of space.
+ */
+int
+get_pty(master_fdp, slave_fdp, slave_name, uid)
+ int *master_fdp;
+ int *slave_fdp;
+ char *slave_name;
+ int uid;
+{
+ int i, mfd, sfd = -1;
+ char pty_name[16];
+ struct termios tios;
+
+#ifdef TIOCGPTN
+ /*
+ * Try the unix98 way first.
+ */
+ mfd = open("/dev/ptmx", O_RDWR);
+ if (mfd >= 0) {
+ int ptn;
+ if (ioctl(mfd, TIOCGPTN, &ptn) >= 0) {
+ slprintf(pty_name, sizeof(pty_name), "/dev/pts/%d", ptn);
+ chmod(pty_name, S_IRUSR | S_IWUSR);
+#ifdef TIOCSPTLCK
+ ptn = 0;
+ if (ioctl(mfd, TIOCSPTLCK, &ptn) < 0)
+ warn("Couldn't unlock pty slave %s: %m", pty_name);
+#endif
+ if ((sfd = open(pty_name, O_RDWR | O_NOCTTY)) < 0)
+ warn("Couldn't open pty slave %s: %m", pty_name);
+ }
+ }
+#endif /* TIOCGPTN */
+
+ if (sfd < 0) {
+ /* the old way - scan through the pty name space */
+ for (i = 0; i < 64; ++i) {
+ slprintf(pty_name, sizeof(pty_name), "/dev/pty%c%x",
+ 'p' + i / 16, i % 16);
+ mfd = open(pty_name, O_RDWR, 0);
+ if (mfd >= 0) {
+ pty_name[5] = 't';
+ sfd = open(pty_name, O_RDWR | O_NOCTTY, 0);
+ if (sfd >= 0) {
+ fchown(sfd, uid, -1);
+ fchmod(sfd, S_IRUSR | S_IWUSR);
+ break;
+ }
+ close(mfd);
+ }
+ }
+ }
+
+ if (sfd < 0)
+ return 0;
+
+ strlcpy(slave_name, pty_name, 16);
+ *master_fdp = mfd;
+ *slave_fdp = sfd;
+ if (tcgetattr(sfd, &tios) == 0) {
+ tios.c_cflag &= ~(CSIZE | CSTOPB | PARENB);
+ tios.c_cflag |= CS8 | CREAD | CLOCAL;
+ tios.c_iflag = IGNPAR;
+ tios.c_oflag = 0;
+ tios.c_lflag = 0;
+ if (tcsetattr(sfd, TCSAFLUSH, &tios) < 0)
+ warn("couldn't set attributes on pty: %m");
+ } else
+ warn("couldn't get attributes on pty: %m");
+
+ return 1;
+}
+
+/********************************************************************
+ *
+ * open_loopback - open the device we use for getting packets
+ * in demand mode. Under Linux, we use a pty master/slave pair.
+ */
+int
+open_ppp_loopback(void)
+{
+ int flags;
+
+ looped = 1;
+ if (new_style_driver) {
+ /* allocate ourselves a ppp unit */
+ if (make_ppp_unit() < 0)
+ die(1);
+ set_flags(ppp_dev_fd, SC_LOOP_TRAFFIC);
+ set_kdebugflag(kdebugflag);
+ ppp_fd = -1;
+ return ppp_dev_fd;
+ }
+
+ if (!get_pty(&master_fd, &slave_fd, loop_name, 0))
+ fatal("No free pty for loopback");
+ SYSDEBUG(("using %s for loopback", loop_name));
+
+ set_ppp_fd(slave_fd);
+
+ flags = fcntl(master_fd, F_GETFL);
+ if (flags == -1 ||
+ fcntl(master_fd, F_SETFL, flags | O_NONBLOCK) == -1)
+ warn("couldn't set master loopback to nonblock: %m(%d)", errno);
+
+ flags = fcntl(ppp_fd, F_GETFL);
+ if (flags == -1 ||
+ fcntl(ppp_fd, F_SETFL, flags | O_NONBLOCK) == -1)
+ warn("couldn't set slave loopback to nonblock: %m(%d)", errno);
+
+ if (ioctl(ppp_fd, TIOCSETD, &ppp_disc) < 0)
+ fatal("ioctl(TIOCSETD): %m(%d)", errno);
+/*
+ * Find out which interface we were given.
+ */
+ if (ioctl(ppp_fd, PPPIOCGUNIT, &ifunit) < 0)
+ fatal("ioctl(PPPIOCGUNIT): %m(%d)", errno);
+/*
+ * Enable debug in the driver if requested.
+ */
+ set_kdebugflag (kdebugflag);
+
+ return master_fd;
+}
+
+/********************************************************************
+ *
+ * restore_loop - reattach the ppp unit to the loopback.
+ *
+ * The kernel ppp driver automatically reattaches the ppp unit to
+ * the loopback if the serial port is set to a line discipline other
+ * than ppp, or if it detects a modem hangup. The former will happen
+ * in disestablish_ppp if the latter hasn't already happened, so we
+ * shouldn't need to do anything.
+ *
+ * Just to be sure, set the real serial port to the normal discipline.
+ */
+
+static void
+restore_loop(void)
+{
+ looped = 1;
+ if (new_style_driver) {
+ set_flags(ppp_dev_fd, get_flags(ppp_dev_fd) | SC_LOOP_TRAFFIC);
+ return;
+ }
+ if (ppp_fd != slave_fd) {
+ (void) ioctl(ppp_fd, TIOCSETD, &tty_disc);
+ set_ppp_fd(slave_fd);
+ }
+}
+
+/********************************************************************
+ *
+ * sifnpmode - Set the mode for handling packets for a given NP.
+ */
+
+int
+sifnpmode(u, proto, mode)
+ int u;
+ int proto;
+ enum NPmode mode;
+{
+ struct npioctl npi;
+
+ npi.protocol = proto;
+ npi.mode = mode;
+ if (ioctl(ppp_dev_fd, PPPIOCSNPMODE, (caddr_t) &npi) < 0) {
+ if (! ok_error (errno))
+ error("ioctl(PPPIOCSNPMODE, %d, %d): %m (%d)",
+ proto, mode, errno);
+ return 0;
+ }
+ return 1;
+}
+
+
+/********************************************************************
+ *
+ * sipxfaddr - Config the interface IPX networknumber
+ */
+
+int sipxfaddr (int unit, unsigned long int network, unsigned char * node )
+{
+ int result = 1;
+
+#ifdef IPX_CHANGE
+ int skfd;
+ struct ifreq ifr;
+ struct sockaddr_ipx *sipx = (struct sockaddr_ipx *) &ifr.ifr_addr;
+
+ skfd = socket (AF_IPX, SOCK_DGRAM, 0);
+ if (skfd < 0) {
+ if (! ok_error (errno))
+ dbglog("socket(AF_IPX): %m (%d)", errno);
+ result = 0;
+ }
+ else {
+ memset (&ifr, '\0', sizeof (ifr));
+ strlcpy (ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+
+ memcpy (sipx->sipx_node, node, IPX_NODE_LEN);
+ sipx->sipx_family = AF_IPX;
+ sipx->sipx_port = 0;
+ sipx->sipx_network = htonl (network);
+ sipx->sipx_type = IPX_FRAME_ETHERII;
+ sipx->sipx_action = IPX_CRTITF;
+/*
+ * Set the IPX device
+ */
+ if (ioctl(skfd, SIOCSIFADDR, (caddr_t) &ifr) < 0) {
+ result = 0;
+ if (errno != EEXIST) {
+ if (! ok_error (errno))
+ dbglog("ioctl(SIOCSIFADDR, CRTITF): %m (%d)", errno);
+ }
+ else {
+ warn("ioctl(SIOCSIFADDR, CRTITF): Address already exists");
+ }
+ }
+ close (skfd);
+ }
+#endif
+ return result;
+}
+
+/********************************************************************
+ *
+ * cipxfaddr - Clear the information for the IPX network. The IPX routes
+ * are removed and the device is no longer able to pass IPX
+ * frames.
+ */
+
+int cipxfaddr (int unit)
+{
+ int result = 1;
+
+#ifdef IPX_CHANGE
+ int skfd;
+ struct ifreq ifr;
+ struct sockaddr_ipx *sipx = (struct sockaddr_ipx *) &ifr.ifr_addr;
+
+ skfd = socket (AF_IPX, SOCK_DGRAM, 0);
+ if (skfd < 0) {
+ if (! ok_error (errno))
+ dbglog("socket(AF_IPX): %m (%d)", errno);
+ result = 0;
+ }
+ else {
+ memset (&ifr, '\0', sizeof (ifr));
+ strlcpy (ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+
+ sipx->sipx_type = IPX_FRAME_ETHERII;
+ sipx->sipx_action = IPX_DLTITF;
+ sipx->sipx_family = AF_IPX;
+/*
+ * Set the IPX device
+ */
+ if (ioctl(skfd, SIOCSIFADDR, (caddr_t) &ifr) < 0) {
+ if (! ok_error (errno))
+ info("ioctl(SIOCSIFADDR, IPX_DLTITF): %m (%d)", errno);
+ result = 0;
+ }
+ close (skfd);
+ }
+#endif
+ return result;
+}
+
+/*
+ * Use the hostname as part of the random number seed.
+ */
+int
+get_host_seed()
+{
+ int h;
+ char *p = hostname;
+
+ h = 407;
+ for (p = hostname; *p != 0; ++p)
+ h = h * 37 + *p;
+ return h;
+}
+
+/********************************************************************
+ *
+ * sys_check_options - check the options that the user specified
+ */
+
+int
+sys_check_options(void)
+{
+#ifdef IPX_CHANGE
+/*
+ * Disable the IPX protocol if the support is not present in the kernel.
+ */
+ char *path;
+
+ if (ipxcp_protent.enabled_flag) {
+ struct stat stat_buf;
+ if ((path = path_to_procfs("/net/ipx_interface")) == 0
+ || lstat(path, &stat_buf) < 0) {
+ error("IPX support is not present in the kernel\n");
+ ipxcp_protent.enabled_flag = 0;
+ }
+ }
+#endif
+ if (demand && driver_is_old) {
+ option_error("demand dialling is not supported by kernel driver "
+ "version %d.%d.%d", driver_version, driver_modification,
+ driver_patch);
+ return 0;
+ }
+ if (multilink && !new_style_driver) {
+ warn("Warning: multilink is not supported by the kernel driver");
+ multilink = 0;
+ }
+ return 1;
+}
diff --git a/mdk-stage1/ppp/pppd/sys-linux.c.wtmp b/mdk-stage1/ppp/pppd/sys-linux.c.wtmp
new file mode 100644
index 000000000..f1b48423e
--- /dev/null
+++ b/mdk-stage1/ppp/pppd/sys-linux.c.wtmp
@@ -0,0 +1,2750 @@
+/*
+ * sys-linux.c - System-dependent procedures for setting up
+ * PPP interfaces on Linux systems
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/errno.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <sys/utsname.h>
+#include <sys/sysmacros.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <syslog.h>
+#include <string.h>
+#include <time.h>
+#include <memory.h>
+#include <utmp.h>
+#include <mntent.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <termios.h>
+#include <unistd.h>
+
+/* This is in netdevice.h. However, this compile will fail miserably if
+ you attempt to include netdevice.h because it has so many references
+ to __memcpy functions which it should not attempt to do. So, since I
+ really don't use it, but it must be defined, define it now. */
+
+#ifndef MAX_ADDR_LEN
+#define MAX_ADDR_LEN 7
+#endif
+
+#if __GLIBC__ >= 2
+#include <asm/types.h> /* glibc 2 conflicts with linux/types.h */
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <net/route.h>
+#include <netinet/if_ether.h>
+#else
+#include <linux/types.h>
+#include <linux/if.h>
+#include <linux/if_arp.h>
+#include <linux/route.h>
+#include <linux/if_ether.h>
+#endif
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <linux/ppp_defs.h>
+#include <linux/if_ppp.h>
+
+#include "pppd.h"
+#include "fsm.h"
+#include "ipcp.h"
+
+#ifdef IPX_CHANGE
+#include "ipxcp.h"
+#if __GLIBC__ >= 2 && \
+ !(defined(__powerpc__) && __GLIBC__ == 2 && __GLIBC_MINOR__ == 0)
+#include <netipx/ipx.h>
+#else
+#include <linux/ipx.h>
+#endif
+#endif /* IPX_CHANGE */
+
+#ifdef PPP_FILTER
+#include <net/bpf.h>
+#include <linux/filter.h>
+#endif /* PPP_FILTER */
+
+#ifdef LOCKLIB
+#include <sys/locks.h>
+#endif
+
+#ifdef INET6
+#ifndef _LINUX_IN6_H
+/*
+ * This is in linux/include/net/ipv6.h.
+ */
+
+struct in6_ifreq {
+ struct in6_addr ifr6_addr;
+ __u32 ifr6_prefixlen;
+ unsigned int ifr6_ifindex;
+};
+#endif
+
+#define IN6_LLADDR_FROM_EUI64(sin6, eui64) do { \
+ memset(&sin6.s6_addr, 0, sizeof(struct in6_addr)); \
+ sin6.s6_addr16[0] = htons(0xfe80); \
+ eui64_copy(eui64, sin6.s6_addr32[2]); \
+ } while (0)
+
+#endif /* INET6 */
+
+/* We can get an EIO error on an ioctl if the modem has hung up */
+#define ok_error(num) ((num)==EIO)
+
+static int tty_disc = N_TTY; /* The TTY discipline */
+static int ppp_disc = N_PPP; /* The PPP discpline */
+static int initfdflags = -1; /* Initial file descriptor flags for fd */
+static int ppp_fd = -1; /* fd which is set to PPP discipline */
+static int sock_fd = -1; /* socket for doing interface ioctls */
+static int slave_fd = -1;
+static int master_fd = -1;
+#ifdef INET6
+static int sock6_fd = -1;
+#endif /* INET6 */
+static int ppp_dev_fd = -1; /* fd for /dev/ppp (new style driver) */
+static int chindex; /* channel index (new style driver) */
+
+static fd_set in_fds; /* set of fds that wait_input waits for */
+static int max_in_fd; /* highest fd set in in_fds */
+
+static int has_proxy_arp = 0;
+static int driver_version = 0;
+static int driver_modification = 0;
+static int driver_patch = 0;
+static int driver_is_old = 0;
+static int restore_term = 0; /* 1 => we've munged the terminal */
+static struct termios inittermios; /* Initial TTY termios */
+
+static int new_style_driver = 0;
+
+static char loop_name[20];
+static unsigned char inbuf[512]; /* buffer for chars read from loopback */
+
+static int if_is_up; /* Interface has been marked up */
+static u_int32_t default_route_gateway; /* Gateway for default route added */
+static u_int32_t proxy_arp_addr; /* Addr for proxy arp entry added */
+static char proxy_arp_dev[16]; /* Device for proxy arp entry */
+static u_int32_t our_old_addr; /* for detecting address changes */
+static int dynaddr_set; /* 1 if ip_dynaddr set */
+static int looped; /* 1 if using loop */
+static int link_mtu; /* mtu for the link (not bundle) */
+
+static struct utsname utsname; /* for the kernel version */
+static int kernel_version;
+#define KVERSION(j,n,p) ((j)*1000000 + (n)*1000 + (p))
+
+#define MAX_IFS 100
+
+#define FLAGS_GOOD (IFF_UP | IFF_BROADCAST)
+#define FLAGS_MASK (IFF_UP | IFF_BROADCAST | \
+ IFF_POINTOPOINT | IFF_LOOPBACK | IFF_NOARP)
+
+#define SIN_ADDR(x) (((struct sockaddr_in *) (&(x)))->sin_addr.s_addr)
+
+/* Prototypes for procedures local to this file. */
+static int get_flags (int fd);
+static void set_flags (int fd, int flags);
+static int translate_speed (int bps);
+static int baud_rate_of (int speed);
+static void close_route_table (void);
+static int open_route_table (void);
+static int read_route_table (struct rtentry *rt);
+static int defaultroute_exists (struct rtentry *rt);
+static int get_ether_addr (u_int32_t ipaddr, struct sockaddr *hwaddr,
+ char *name, int namelen);
+static void decode_version (char *buf, int *version, int *mod, int *patch);
+static int set_kdebugflag(int level);
+static int ppp_registered(void);
+static int make_ppp_unit(void);
+static void restore_loop(void); /* Transfer ppp unit back to loopback */
+
+extern u_char inpacket_buf[]; /* borrowed from main.c */
+
+/*
+ * SET_SA_FAMILY - set the sa_family field of a struct sockaddr,
+ * if it exists.
+ */
+
+#define SET_SA_FAMILY(addr, family) \
+ memset ((char *) &(addr), '\0', sizeof(addr)); \
+ addr.sa_family = (family);
+
+/*
+ * Determine if the PPP connection should still be present.
+ */
+
+extern int hungup;
+
+/* new_fd is the fd of a tty */
+static void set_ppp_fd (int new_fd)
+{
+ SYSDEBUG ((LOG_DEBUG, "setting ppp_fd to %d\n", new_fd));
+ ppp_fd = new_fd;
+ if (!new_style_driver)
+ ppp_dev_fd = new_fd;
+}
+
+static int still_ppp(void)
+{
+ if (new_style_driver)
+ return !hungup && ppp_fd >= 0;
+ if (!hungup || ppp_fd == slave_fd)
+ return 1;
+ if (slave_fd >= 0) {
+ set_ppp_fd(slave_fd);
+ return 1;
+ }
+ return 0;
+}
+
+/********************************************************************
+ *
+ * Functions to read and set the flags value in the device driver
+ */
+
+static int get_flags (int fd)
+{
+ int flags;
+
+ if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &flags) < 0) {
+ if ( ok_error (errno) )
+ flags = 0;
+ else
+ fatal("ioctl(PPPIOCGFLAGS): %m");
+ }
+
+ SYSDEBUG ((LOG_DEBUG, "get flags = %x\n", flags));
+ return flags;
+}
+
+/********************************************************************/
+
+static void set_flags (int fd, int flags)
+{
+ SYSDEBUG ((LOG_DEBUG, "set flags = %x\n", flags));
+
+ if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &flags) < 0) {
+ if (! ok_error (errno) )
+ fatal("ioctl(PPPIOCSFLAGS, %x): %m", flags, errno);
+ }
+}
+
+/********************************************************************
+ *
+ * sys_init - System-dependent initialization.
+ */
+
+void sys_init(void)
+{
+ int flags;
+
+ if (new_style_driver) {
+ ppp_dev_fd = open("/dev/ppp", O_RDWR);
+ if (ppp_dev_fd < 0)
+ fatal("Couldn't open /dev/ppp: %m");
+ flags = fcntl(ppp_dev_fd, F_GETFL);
+ if (flags == -1
+ || fcntl(ppp_dev_fd, F_SETFL, flags | O_NONBLOCK) == -1)
+ warn("Couldn't set /dev/ppp to nonblock: %m");
+ }
+
+ /* Get an internet socket for doing socket ioctls. */
+ sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (sock_fd < 0)
+ fatal("Couldn't create IP socket: %m(%d)", errno);
+
+#ifdef INET6
+ sock6_fd = socket(AF_INET6, SOCK_DGRAM, 0);
+ if (sock6_fd < 0)
+ sock6_fd = -errno; /* save errno for later */
+#endif
+
+ FD_ZERO(&in_fds);
+ max_in_fd = 0;
+}
+
+/********************************************************************
+ *
+ * sys_cleanup - restore any system state we modified before exiting:
+ * mark the interface down, delete default route and/or proxy arp entry.
+ * This shouldn't call die() because it's called from die().
+ */
+
+void sys_cleanup(void)
+{
+/*
+ * Take down the device
+ */
+ if (if_is_up) {
+ if_is_up = 0;
+ sifdown(0);
+ }
+/*
+ * Delete any routes through the device.
+ */
+ if (default_route_gateway != 0)
+ cifdefaultroute(0, 0, default_route_gateway);
+
+ if (has_proxy_arp)
+ cifproxyarp(0, proxy_arp_addr);
+}
+
+/********************************************************************
+ *
+ * sys_close - Clean up in a child process before execing.
+ */
+void
+sys_close(void)
+{
+ if (new_style_driver)
+ close(ppp_dev_fd);
+ if (sock_fd >= 0)
+ close(sock_fd);
+ if (slave_fd >= 0)
+ close(slave_fd);
+ if (master_fd >= 0)
+ close(master_fd);
+ closelog();
+}
+
+/********************************************************************
+ *
+ * set_kdebugflag - Define the debugging level for the kernel
+ */
+
+static int set_kdebugflag (int requested_level)
+{
+ if (new_style_driver && ifunit < 0)
+ return 1;
+ if (ioctl(ppp_dev_fd, PPPIOCSDEBUG, &requested_level) < 0) {
+ if ( ! ok_error (errno) )
+ error("ioctl(PPPIOCSDEBUG): %m");
+ return (0);
+ }
+ SYSDEBUG ((LOG_INFO, "set kernel debugging level to %d",
+ requested_level));
+ return (1);
+}
+
+/********************************************************************
+ *
+ * tty_establish_ppp - Turn the serial port into a ppp interface.
+ */
+
+int tty_establish_ppp (int tty_fd)
+{
+ int x;
+ int fd = -1;
+
+/*
+ * Ensure that the tty device is in exclusive mode.
+ */
+ if (ioctl(tty_fd, TIOCEXCL, 0) < 0) {
+ if ( ! ok_error ( errno ))
+ warn("Couldn't make tty exclusive: %m");
+ }
+/*
+ * Demand mode - prime the old ppp device to relinquish the unit.
+ */
+ if (!new_style_driver && looped
+ && ioctl(slave_fd, PPPIOCXFERUNIT, 0) < 0) {
+ error("ioctl(transfer ppp unit): %m");
+ return -1;
+ }
+/*
+ * Set the current tty to the PPP discpline
+ */
+
+#ifndef N_SYNC_PPP
+#define N_SYNC_PPP 14
+#endif
+ ppp_disc = (new_style_driver && sync_serial)? N_SYNC_PPP: N_PPP;
+ if (ioctl(tty_fd, TIOCSETD, &ppp_disc) < 0) {
+ if ( ! ok_error (errno) ) {
+ error("Couldn't set tty to PPP discipline: %m");
+ return -1;
+ }
+ }
+
+ if (new_style_driver) {
+ /* Open another instance of /dev/ppp and connect the channel to it */
+ int flags;
+
+ if (ioctl(tty_fd, PPPIOCGCHAN, &chindex) == -1) {
+ error("Couldn't get channel number: %m");
+ goto err;
+ }
+ dbglog("using channel %d", chindex);
+ fd = open("/dev/ppp", O_RDWR);
+ if (fd < 0) {
+ error("Couldn't reopen /dev/ppp: %m");
+ goto err;
+ }
+ if (ioctl(fd, PPPIOCATTCHAN, &chindex) < 0) {
+ error("Couldn't attach to channel %d: %m", chindex);
+ goto err_close;
+ }
+ flags = fcntl(fd, F_GETFL);
+ if (flags == -1 || fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1)
+ warn("Couldn't set /dev/ppp (channel) to nonblock: %m");
+ set_ppp_fd(fd);
+
+ if (!looped)
+ ifunit = -1;
+ if (!looped && !multilink) {
+ /*
+ * Create a new PPP unit.
+ */
+ if (make_ppp_unit() < 0)
+ goto err_close;
+ }
+
+ if (looped)
+ set_flags(ppp_dev_fd, get_flags(ppp_dev_fd) & ~SC_LOOP_TRAFFIC);
+
+ if (!multilink) {
+ add_fd(ppp_dev_fd);
+ if (ioctl(fd, PPPIOCCONNECT, &ifunit) < 0) {
+ error("Couldn't attach to PPP unit %d: %m", ifunit);
+ goto err_close;
+ }
+ }
+
+ } else {
+ /*
+ * Old-style driver: find out which interface we were given.
+ */
+ set_ppp_fd (tty_fd);
+ if (ioctl(tty_fd, PPPIOCGUNIT, &x) < 0) {
+ if (ok_error (errno))
+ goto err;
+ fatal("ioctl(PPPIOCGUNIT): %m(%d)", errno);
+ }
+ /* Check that we got the same unit again. */
+ if (looped && x != ifunit)
+ fatal("transfer_ppp failed: wanted unit %d, got %d", ifunit, x);
+ ifunit = x;
+
+ /*
+ * Fetch the initial file flags and reset blocking mode on the file.
+ */
+ initfdflags = fcntl(tty_fd, F_GETFL);
+ if (initfdflags == -1 ||
+ fcntl(tty_fd, F_SETFL, initfdflags | O_NONBLOCK) == -1) {
+ if ( ! ok_error (errno))
+ warn("Couldn't set device to non-blocking mode: %m");
+ }
+ }
+
+ looped = 0;
+
+ /*
+ * Enable debug in the driver if requested.
+ */
+ if (!looped)
+ set_kdebugflag (kdebugflag);
+
+#define SC_RCVB (SC_RCV_B7_0 | SC_RCV_B7_1 | SC_RCV_EVNP | SC_RCV_ODDP)
+#define SC_LOGB (SC_DEBUG | SC_LOG_INPKT | SC_LOG_OUTPKT | SC_LOG_RAWIN \
+ | SC_LOG_FLUSH)
+
+ set_flags(ppp_fd, ((get_flags(ppp_fd) & ~(SC_RCVB | SC_LOGB))
+ | ((kdebugflag * SC_DEBUG) & SC_LOGB)));
+
+ SYSDEBUG ((LOG_NOTICE, "Using version %d.%d.%d of PPP driver",
+ driver_version, driver_modification, driver_patch));
+
+ return ppp_fd;
+
+ err_close:
+ close(fd);
+ err:
+ if (ioctl(tty_fd, TIOCSETD, &tty_disc) < 0 && !ok_error(errno))
+ warn("Couldn't reset tty to normal line discipline: %m");
+ return -1;
+}
+
+/********************************************************************
+ *
+ * tty_disestablish_ppp - Restore the serial port to normal operation,
+ * and reconnect the ppp unit to the loopback if in demand mode.
+ * This shouldn't call die() because it's called from die().
+ */
+
+void tty_disestablish_ppp(int tty_fd)
+{
+ if (demand)
+ restore_loop();
+ if (!hungup) {
+/*
+ * Flush the tty output buffer so that the TIOCSETD doesn't hang.
+ */
+ if (tcflush(tty_fd, TCIOFLUSH) < 0)
+ warn("tcflush failed: %m");
+/*
+ * Restore the previous line discipline
+ */
+ if (ioctl(tty_fd, TIOCSETD, &tty_disc) < 0) {
+ if ( ! ok_error (errno))
+ error("ioctl(TIOCSETD, N_TTY): %m");
+ }
+
+ if (ioctl(tty_fd, TIOCNXCL, 0) < 0) {
+ if ( ! ok_error (errno))
+ warn("ioctl(TIOCNXCL): %m(%d)", errno);
+ }
+
+ /* Reset non-blocking mode on fd. */
+ if (initfdflags != -1 && fcntl(tty_fd, F_SETFL, initfdflags) < 0) {
+ if ( ! ok_error (errno))
+ warn("Couldn't restore device fd flags: %m");
+ }
+ }
+ initfdflags = -1;
+
+ if (new_style_driver) {
+ close(ppp_fd);
+ ppp_fd = -1;
+ if (!looped && ifunit >= 0 && ioctl(ppp_dev_fd, PPPIOCDETACH) < 0)
+ error("Couldn't release PPP unit: %m");
+ if (!multilink)
+ remove_fd(ppp_dev_fd);
+ }
+}
+
+/*
+ * make_ppp_unit - make a new ppp unit for ppp_dev_fd.
+ * Assumes new_style_driver.
+ */
+static int make_ppp_unit()
+{
+ int x;
+
+ ifunit = req_unit;
+ x = ioctl(ppp_dev_fd, PPPIOCNEWUNIT, &ifunit);
+ if (x < 0 && req_unit >= 0 && errno == EEXIST) {
+ warn("Couldn't allocate PPP unit %d as it is already in use");
+ ifunit = -1;
+ x = ioctl(ppp_dev_fd, PPPIOCNEWUNIT, &ifunit);
+ }
+ if (x < 0)
+ error("Couldn't create new ppp unit: %m");
+ return x;
+}
+
+/*
+ * cfg_bundle - configure the existing bundle.
+ * Used in demand mode.
+ */
+void cfg_bundle(int mrru, int mtru, int rssn, int tssn)
+{
+ int flags;
+
+ if (!new_style_driver)
+ return;
+
+ /* set the mrru, mtu and flags */
+ if (ioctl(ppp_dev_fd, PPPIOCSMRRU, &mrru) < 0)
+ error("Couldn't set MRRU: %m");
+ flags = get_flags(ppp_dev_fd);
+ flags &= ~(SC_MP_SHORTSEQ | SC_MP_XSHORTSEQ);
+ flags |= (rssn? SC_MP_SHORTSEQ: 0) | (tssn? SC_MP_XSHORTSEQ: 0)
+ | (mrru? SC_MULTILINK: 0);
+
+ set_flags(ppp_dev_fd, flags);
+
+ /* connect up the channel */
+ if (ioctl(ppp_fd, PPPIOCCONNECT, &ifunit) < 0)
+ fatal("Couldn't attach to PPP unit %d: %m", ifunit);
+ add_fd(ppp_dev_fd);
+}
+
+/*
+ * make_new_bundle - create a new PPP unit (i.e. a bundle)
+ * and connect our channel to it. This should only get called
+ * if `multilink' was set at the time establish_ppp was called.
+ * In demand mode this uses our existing bundle instead of making
+ * a new one.
+ */
+void make_new_bundle(int mrru, int mtru, int rssn, int tssn)
+{
+ if (!new_style_driver)
+ return;
+
+ /* make us a ppp unit */
+ if (make_ppp_unit() < 0)
+ die(1);
+
+ /* set the mrru and flags */
+ cfg_bundle(mrru, mtru, rssn, tssn);
+}
+
+/*
+ * bundle_attach - attach our link to a given PPP unit.
+ * We assume the unit is controlled by another pppd.
+ */
+int bundle_attach(int ifnum)
+{
+ if (!new_style_driver)
+ return -1;
+
+ if (ioctl(ppp_dev_fd, PPPIOCATTACH, &ifnum) < 0) {
+ if (errno == ENXIO)
+ return 0; /* doesn't still exist */
+ fatal("Couldn't attach to interface unit %d: %m\n", ifnum);
+ }
+ if (ioctl(ppp_fd, PPPIOCCONNECT, &ifnum) < 0)
+ fatal("Couldn't connect to interface unit %d: %m", ifnum);
+ set_flags(ppp_dev_fd, get_flags(ppp_dev_fd) | SC_MULTILINK);
+
+ ifunit = ifnum;
+ return 1;
+}
+
+/********************************************************************
+ *
+ * clean_check - Fetch the flags for the device and generate
+ * appropriate error messages.
+ */
+void clean_check(void)
+{
+ int x;
+ char *s;
+
+ if (still_ppp()) {
+ if (ioctl(ppp_fd, PPPIOCGFLAGS, (caddr_t) &x) == 0) {
+ s = NULL;
+ switch (~x & (SC_RCV_B7_0|SC_RCV_B7_1|SC_RCV_EVNP|SC_RCV_ODDP)) {
+ case SC_RCV_B7_0:
+ s = "all had bit 7 set to 1";
+ break;
+
+ case SC_RCV_B7_1:
+ s = "all had bit 7 set to 0";
+ break;
+
+ case SC_RCV_EVNP:
+ s = "all had odd parity";
+ break;
+
+ case SC_RCV_ODDP:
+ s = "all had even parity";
+ break;
+ }
+
+ if (s != NULL) {
+ warn("Receive serial link is not 8-bit clean:");
+ warn("Problem: %s", s);
+ }
+ }
+ }
+}
+
+
+/*
+ * List of valid speeds.
+ */
+
+struct speed {
+ int speed_int, speed_val;
+} speeds[] = {
+#ifdef B50
+ { 50, B50 },
+#endif
+#ifdef B75
+ { 75, B75 },
+#endif
+#ifdef B110
+ { 110, B110 },
+#endif
+#ifdef B134
+ { 134, B134 },
+#endif
+#ifdef B150
+ { 150, B150 },
+#endif
+#ifdef B200
+ { 200, B200 },
+#endif
+#ifdef B300
+ { 300, B300 },
+#endif
+#ifdef B600
+ { 600, B600 },
+#endif
+#ifdef B1200
+ { 1200, B1200 },
+#endif
+#ifdef B1800
+ { 1800, B1800 },
+#endif
+#ifdef B2000
+ { 2000, B2000 },
+#endif
+#ifdef B2400
+ { 2400, B2400 },
+#endif
+#ifdef B3600
+ { 3600, B3600 },
+#endif
+#ifdef B4800
+ { 4800, B4800 },
+#endif
+#ifdef B7200
+ { 7200, B7200 },
+#endif
+#ifdef B9600
+ { 9600, B9600 },
+#endif
+#ifdef B19200
+ { 19200, B19200 },
+#endif
+#ifdef B38400
+ { 38400, B38400 },
+#endif
+#ifdef B57600
+ { 57600, B57600 },
+#endif
+#ifdef B76800
+ { 76800, B76800 },
+#endif
+#ifdef B115200
+ { 115200, B115200 },
+#endif
+#ifdef EXTA
+ { 19200, EXTA },
+#endif
+#ifdef EXTB
+ { 38400, EXTB },
+#endif
+#ifdef B230400
+ { 230400, B230400 },
+#endif
+#ifdef B460800
+ { 460800, B460800 },
+#endif
+#ifdef B921600
+ { 921600, B921600 },
+#endif
+ { 0, 0 }
+};
+
+/********************************************************************
+ *
+ * Translate from bits/second to a speed_t.
+ */
+
+static int translate_speed (int bps)
+{
+ struct speed *speedp;
+
+ if (bps != 0) {
+ for (speedp = speeds; speedp->speed_int; speedp++) {
+ if (bps == speedp->speed_int)
+ return speedp->speed_val;
+ }
+ warn("speed %d not supported", bps);
+ }
+ return 0;
+}
+
+/********************************************************************
+ *
+ * Translate from a speed_t to bits/second.
+ */
+
+static int baud_rate_of (int speed)
+{
+ struct speed *speedp;
+
+ if (speed != 0) {
+ for (speedp = speeds; speedp->speed_int; speedp++) {
+ if (speed == speedp->speed_val)
+ return speedp->speed_int;
+ }
+ }
+ return 0;
+}
+
+/********************************************************************
+ *
+ * set_up_tty: Set up the serial port on `fd' for 8 bits, no parity,
+ * at the requested speed, etc. If `local' is true, set CLOCAL
+ * regardless of whether the modem option was specified.
+ */
+
+void set_up_tty(int tty_fd, int local)
+{
+ int speed;
+ struct termios tios;
+
+ setdtr(tty_fd, 1);
+ if (tcgetattr(tty_fd, &tios) < 0) {
+ if (!ok_error(errno))
+ fatal("tcgetattr: %m(%d)", errno);
+ return;
+ }
+
+ if (!restore_term)
+ inittermios = tios;
+
+ tios.c_cflag &= ~(CSIZE | CSTOPB | PARENB | CLOCAL);
+ tios.c_cflag |= CS8 | CREAD | HUPCL;
+
+ tios.c_iflag = IGNBRK | IGNPAR;
+ tios.c_oflag = 0;
+ tios.c_lflag = 0;
+ tios.c_cc[VMIN] = 1;
+ tios.c_cc[VTIME] = 0;
+
+ if (local || !modem)
+ tios.c_cflag ^= (CLOCAL | HUPCL);
+
+ switch (crtscts) {
+ case 1:
+ tios.c_cflag |= CRTSCTS;
+ break;
+
+ case -2:
+ tios.c_iflag |= IXON | IXOFF;
+ tios.c_cc[VSTOP] = 0x13; /* DC3 = XOFF = ^S */
+ tios.c_cc[VSTART] = 0x11; /* DC1 = XON = ^Q */
+ break;
+
+ case -1:
+ tios.c_cflag &= ~CRTSCTS;
+ break;
+
+ default:
+ break;
+ }
+
+ speed = translate_speed(inspeed);
+ if (speed) {
+ cfsetospeed (&tios, speed);
+ cfsetispeed (&tios, speed);
+ }
+/*
+ * We can't proceed if the serial port speed is B0,
+ * since that implies that the serial port is disabled.
+ */
+ else {
+ speed = cfgetospeed(&tios);
+ if (speed == B0)
+ fatal("Baud rate for %s is 0; need explicit baud rate", devnam);
+ }
+
+ if (tcsetattr(tty_fd, TCSAFLUSH, &tios) < 0)
+ if (!ok_error(errno))
+ fatal("tcsetattr: %m");
+
+ baud_rate = baud_rate_of(speed);
+ restore_term = 1;
+}
+
+/********************************************************************
+ *
+ * setdtr - control the DTR line on the serial port.
+ * This is called from die(), so it shouldn't call die().
+ */
+
+void setdtr (int tty_fd, int on)
+{
+ int modembits = TIOCM_DTR;
+
+ ioctl(tty_fd, (on ? TIOCMBIS : TIOCMBIC), &modembits);
+}
+
+/********************************************************************
+ *
+ * restore_tty - restore the terminal to the saved settings.
+ */
+
+void restore_tty (int tty_fd)
+{
+ if (restore_term) {
+ restore_term = 0;
+/*
+ * Turn off echoing, because otherwise we can get into
+ * a loop with the tty and the modem echoing to each other.
+ * We presume we are the sole user of this tty device, so
+ * when we close it, it will revert to its defaults anyway.
+ */
+ if (!default_device)
+ inittermios.c_lflag &= ~(ECHO | ECHONL);
+
+ if (tcsetattr(tty_fd, TCSAFLUSH, &inittermios) < 0) {
+ if (! ok_error (errno))
+ warn("tcsetattr: %m");
+ }
+ }
+}
+
+/********************************************************************
+ *
+ * output - Output PPP packet.
+ */
+
+void output (int unit, unsigned char *p, int len)
+{
+ int fd = ppp_fd;
+ int proto;
+
+ if (debug)
+ dbglog("sent %P", p, len);
+
+ if (len < PPP_HDRLEN)
+ return;
+ if (new_style_driver) {
+ p += 2;
+ len -= 2;
+ proto = (p[0] << 8) + p[1];
+ if (ifunit >= 0 && !(proto >= 0xc000 || proto == PPP_CCPFRAG))
+ fd = ppp_dev_fd;
+ }
+ if (write(fd, p, len) < 0) {
+ if (errno == EWOULDBLOCK || errno == ENOBUFS
+ || errno == ENXIO || errno == EIO || errno == EINTR)
+ warn("write: warning: %m (%d)", errno);
+ else
+ error("write: %m (%d)", errno);
+ }
+}
+
+/********************************************************************
+ *
+ * wait_input - wait until there is data available,
+ * for the length of time specified by *timo (indefinite
+ * if timo is NULL).
+ */
+
+void wait_input(struct timeval *timo)
+{
+ fd_set ready, exc;
+ int n;
+
+ ready = in_fds;
+ exc = in_fds;
+ n = select(max_in_fd + 1, &ready, NULL, &exc, timo);
+ if (n < 0 && errno != EINTR)
+ fatal("select: %m(%d)", errno);
+}
+
+/*
+ * add_fd - add an fd to the set that wait_input waits for.
+ */
+void add_fd(int fd)
+{
+ FD_SET(fd, &in_fds);
+ if (fd > max_in_fd)
+ max_in_fd = fd;
+}
+
+/*
+ * remove_fd - remove an fd from the set that wait_input waits for.
+ */
+void remove_fd(int fd)
+{
+ FD_CLR(fd, &in_fds);
+}
+
+
+/********************************************************************
+ *
+ * read_packet - get a PPP packet from the serial device.
+ */
+
+int read_packet (unsigned char *buf)
+{
+ int len, nr;
+
+ len = PPP_MRU + PPP_HDRLEN;
+ if (new_style_driver) {
+ *buf++ = PPP_ALLSTATIONS;
+ *buf++ = PPP_UI;
+ len -= 2;
+ }
+ nr = -1;
+ if (ppp_fd >= 0) {
+ nr = read(ppp_fd, buf, len);
+ if (nr < 0 && errno != EWOULDBLOCK && errno != EIO && errno != EINTR)
+ error("read: %m");
+ if (nr < 0 && errno == ENXIO)
+ return 0;
+ }
+ if (nr < 0 && new_style_driver && ifunit >= 0) {
+ /* N.B. we read ppp_fd first since LCP packets come in there. */
+ nr = read(ppp_dev_fd, buf, len);
+ if (nr < 0 && errno != EWOULDBLOCK && errno != EIO && errno != EINTR)
+ error("read /dev/ppp: %m");
+ if (nr < 0 && errno == ENXIO)
+ return 0;
+ }
+ return (new_style_driver && nr > 0)? nr+2: nr;
+}
+
+/********************************************************************
+ *
+ * get_loop_output - get outgoing packets from the ppp device,
+ * and detect when we want to bring the real link up.
+ * Return value is 1 if we need to bring up the link, 0 otherwise.
+ */
+int
+get_loop_output(void)
+{
+ int rv = 0;
+ int n;
+
+ if (new_style_driver) {
+ while ((n = read_packet(inpacket_buf)) > 0)
+ if (loop_frame(inpacket_buf, n))
+ rv = 1;
+ return rv;
+ }
+
+ while ((n = read(master_fd, inbuf, sizeof(inbuf))) > 0)
+ if (loop_chars(inbuf, n))
+ rv = 1;
+
+ if (n == 0)
+ fatal("eof on loopback");
+
+ if (errno != EWOULDBLOCK)
+ fatal("read from loopback: %m(%d)", errno);
+
+ return rv;
+}
+
+/*
+ * netif_set_mtu - set the MTU on the PPP network interface.
+ */
+void
+netif_set_mtu(int unit, int mtu)
+{
+ struct ifreq ifr;
+
+ SYSDEBUG ((LOG_DEBUG, "netif_set_mtu: mtu = %d\n", mtu));
+
+ memset (&ifr, '\0', sizeof (ifr));
+ strlcpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
+ ifr.ifr_mtu = mtu;
+
+ if (ifunit >= 0 && ioctl(sock_fd, SIOCSIFMTU, (caddr_t) &ifr) < 0)
+ fatal("ioctl(SIOCSIFMTU): %m");
+}
+
+/********************************************************************
+ *
+ * tty_send_config - configure the transmit characteristics of
+ * the ppp interface.
+ */
+
+void tty_send_config (int mtu,u_int32_t asyncmap,int pcomp,int accomp)
+{
+ u_int x;
+
+/*
+ * Set the asyncmap and other parameters for the ppp device
+ */
+ if (!still_ppp())
+ return;
+ link_mtu = mtu;
+ SYSDEBUG ((LOG_DEBUG, "send_config: asyncmap = %lx\n", asyncmap));
+ if (ioctl(ppp_fd, PPPIOCSASYNCMAP, (caddr_t) &asyncmap) < 0) {
+ if (!ok_error(errno))
+ fatal("ioctl(PPPIOCSASYNCMAP): %m(%d)", errno);
+ return;
+ }
+
+ x = get_flags(ppp_fd);
+ x = pcomp ? x | SC_COMP_PROT : x & ~SC_COMP_PROT;
+ x = accomp ? x | SC_COMP_AC : x & ~SC_COMP_AC;
+ x = sync_serial ? x | SC_SYNC : x & ~SC_SYNC;
+ set_flags(ppp_fd, x);
+}
+
+/********************************************************************
+ *
+ * tty_set_xaccm - set the extended transmit ACCM for the interface.
+ */
+
+void tty_set_xaccm (ext_accm accm)
+{
+ SYSDEBUG ((LOG_DEBUG, "set_xaccm: %08lx %08lx %08lx %08lx\n",
+ accm[0], accm[1], accm[2], accm[3]));
+
+ if (!still_ppp())
+ return;
+ if (ioctl(ppp_fd, PPPIOCSXASYNCMAP, accm) < 0 && errno != ENOTTY) {
+ if ( ! ok_error (errno))
+ warn("ioctl(set extended ACCM): %m(%d)", errno);
+ }
+}
+
+/********************************************************************
+ *
+ * tty_recv_config - configure the receive-side characteristics of
+ * the ppp interface.
+ */
+
+void tty_recv_config (int mru,u_int32_t asyncmap,int pcomp,int accomp)
+{
+ SYSDEBUG ((LOG_DEBUG, "recv_config: mru = %d\n", mru));
+/*
+ * If we were called because the link has gone down then there is nothing
+ * which may be done. Just return without incident.
+ */
+ if (!still_ppp())
+ return;
+/*
+ * Set the receiver parameters
+ */
+ if (ioctl(ppp_fd, PPPIOCSMRU, (caddr_t) &mru) < 0) {
+ if ( ! ok_error (errno))
+ error("ioctl(PPPIOCSMRU): %m(%d)", errno);
+ }
+ if (new_style_driver && ifunit >= 0
+ && ioctl(ppp_dev_fd, PPPIOCSMRU, (caddr_t) &mru) < 0)
+ error("Couldn't set MRU in generic PPP layer: %m");
+
+ SYSDEBUG ((LOG_DEBUG, "recv_config: asyncmap = %lx\n", asyncmap));
+ if (ioctl(ppp_fd, PPPIOCSRASYNCMAP, (caddr_t) &asyncmap) < 0) {
+ if (!ok_error(errno))
+ error("ioctl(PPPIOCSRASYNCMAP): %m(%d)", errno);
+ }
+}
+
+/********************************************************************
+ *
+ * ccp_test - ask kernel whether a given compression method
+ * is acceptable for use.
+ */
+
+int ccp_test (int unit, u_char *opt_ptr, int opt_len, int for_transmit)
+{
+ struct ppp_option_data data;
+
+ memset (&data, '\0', sizeof (data));
+ data.ptr = opt_ptr;
+ data.length = opt_len;
+ data.transmit = for_transmit;
+
+ if (ioctl(ppp_dev_fd, PPPIOCSCOMPRESS, (caddr_t) &data) >= 0)
+ return 1;
+
+ return (errno == ENOBUFS)? 0: -1;
+}
+
+/********************************************************************
+ *
+ * ccp_flags_set - inform kernel about the current state of CCP.
+ */
+
+void ccp_flags_set (int unit, int isopen, int isup)
+{
+ if (still_ppp()) {
+ int x = get_flags(ppp_dev_fd);
+ x = isopen? x | SC_CCP_OPEN : x &~ SC_CCP_OPEN;
+ x = isup? x | SC_CCP_UP : x &~ SC_CCP_UP;
+ set_flags (ppp_dev_fd, x);
+ }
+}
+
+#ifdef PPP_FILTER
+/*
+ * set_filters - set the active and pass filters in the kernel driver.
+ */
+int set_filters(struct bpf_program *pass, struct bpf_program *active)
+{
+ struct sock_fprog fp;
+
+ fp.len = pass->bf_len;
+ fp.filter = (struct sock_filter *) pass->bf_insns;
+ if (ioctl(ppp_dev_fd, PPPIOCSPASS, &fp) < 0) {
+ if (errno == ENOTTY)
+ warn("kernel does not support PPP filtering");
+ else
+ error("Couldn't set pass-filter in kernel: %m");
+ return 0;
+ }
+ fp.len = active->bf_len;
+ fp.filter = (struct sock_filter *) active->bf_insns;
+ if (ioctl(ppp_dev_fd, PPPIOCSACTIVE, &fp) < 0) {
+ error("Couldn't set active-filter in kernel: %m");
+ return 0;
+ }
+ return 1;
+}
+#endif /* PPP_FILTER */
+
+/********************************************************************
+ *
+ * get_idle_time - return how long the link has been idle.
+ */
+int
+get_idle_time(u, ip)
+ int u;
+ struct ppp_idle *ip;
+{
+ return ioctl(ppp_dev_fd, PPPIOCGIDLE, ip) >= 0;
+}
+
+/********************************************************************
+ *
+ * get_ppp_stats - return statistics for the link.
+ */
+int
+get_ppp_stats(u, stats)
+ int u;
+ struct pppd_stats *stats;
+{
+ struct ifpppstatsreq req;
+
+ memset (&req, 0, sizeof (req));
+
+ req.stats_ptr = (caddr_t) &req.stats;
+ strlcpy(req.ifr__name, ifname, sizeof(req.ifr__name));
+ if (ioctl(sock_fd, SIOCGPPPSTATS, &req) < 0) {
+ error("Couldn't get PPP statistics: %m");
+ return 0;
+ }
+ stats->bytes_in = req.stats.p.ppp_ibytes;
+ stats->bytes_out = req.stats.p.ppp_obytes;
+ return 1;
+}
+
+/********************************************************************
+ *
+ * ccp_fatal_error - returns 1 if decompression was disabled as a
+ * result of an error detected after decompression of a packet,
+ * 0 otherwise. This is necessary because of patent nonsense.
+ */
+
+int ccp_fatal_error (int unit)
+{
+ int x = get_flags(ppp_dev_fd);
+
+ return x & SC_DC_FERROR;
+}
+
+/********************************************************************
+ *
+ * path_to_procfs - find the path to the proc file system mount point
+ */
+static char proc_path[MAXPATHLEN];
+static int proc_path_len;
+
+static char *path_to_procfs(const char *tail)
+{
+ struct mntent *mntent;
+ FILE *fp;
+
+ if (proc_path_len == 0) {
+ /* Default the mount location of /proc */
+ strlcpy (proc_path, "/proc", sizeof(proc_path));
+ proc_path_len = 5;
+ fp = fopen(MOUNTED, "r");
+ if (fp != NULL) {
+ while ((mntent = getmntent(fp)) != NULL) {
+ if (strcmp(mntent->mnt_type, MNTTYPE_IGNORE) == 0)
+ continue;
+ if (strcmp(mntent->mnt_type, "proc") == 0) {
+ strlcpy(proc_path, mntent->mnt_dir, sizeof(proc_path));
+ proc_path_len = strlen(proc_path);
+ break;
+ }
+ }
+ fclose (fp);
+ }
+ }
+
+ strlcpy(proc_path + proc_path_len, tail,
+ sizeof(proc_path) - proc_path_len);
+ return proc_path;
+}
+
+/*
+ * /proc/net/route parsing stuff.
+ */
+#define ROUTE_MAX_COLS 12
+FILE *route_fd = (FILE *) 0;
+static char route_buffer[512];
+static int route_dev_col, route_dest_col, route_gw_col;
+static int route_flags_col, route_mask_col;
+static int route_num_cols;
+
+static int open_route_table (void);
+static void close_route_table (void);
+static int read_route_table (struct rtentry *rt);
+
+/********************************************************************
+ *
+ * close_route_table - close the interface to the route table
+ */
+
+static void close_route_table (void)
+{
+ if (route_fd != (FILE *) 0) {
+ fclose (route_fd);
+ route_fd = (FILE *) 0;
+ }
+}
+
+/********************************************************************
+ *
+ * open_route_table - open the interface to the route table
+ */
+static char route_delims[] = " \t\n";
+
+static int open_route_table (void)
+{
+ char *path;
+
+ close_route_table();
+
+ path = path_to_procfs("/net/route");
+ route_fd = fopen (path, "r");
+ if (route_fd == NULL) {
+ error("can't open routing table %s: %m", path);
+ return 0;
+ }
+
+ route_dev_col = 0; /* default to usual columns */
+ route_dest_col = 1;
+ route_gw_col = 2;
+ route_flags_col = 3;
+ route_mask_col = 7;
+ route_num_cols = 8;
+
+ /* parse header line */
+ if (fgets(route_buffer, sizeof(route_buffer), route_fd) != 0) {
+ char *p = route_buffer, *q;
+ int col;
+ for (col = 0; col < ROUTE_MAX_COLS; ++col) {
+ int used = 1;
+ if ((q = strtok(p, route_delims)) == 0)
+ break;
+ if (strcasecmp(q, "iface") == 0)
+ route_dev_col = col;
+ else if (strcasecmp(q, "destination") == 0)
+ route_dest_col = col;
+ else if (strcasecmp(q, "gateway") == 0)
+ route_gw_col = col;
+ else if (strcasecmp(q, "flags") == 0)
+ route_flags_col = col;
+ else if (strcasecmp(q, "mask") == 0)
+ route_mask_col = col;
+ else
+ used = 0;
+ if (used && col >= route_num_cols)
+ route_num_cols = col + 1;
+ p = NULL;
+ }
+ }
+
+ return 1;
+}
+
+/********************************************************************
+ *
+ * read_route_table - read the next entry from the route table
+ */
+
+static int read_route_table(struct rtentry *rt)
+{
+ char *cols[ROUTE_MAX_COLS], *p;
+ int col;
+
+ memset (rt, '\0', sizeof (struct rtentry));
+
+ if (fgets (route_buffer, sizeof (route_buffer), route_fd) == (char *) 0)
+ return 0;
+
+ p = route_buffer;
+ for (col = 0; col < route_num_cols; ++col) {
+ cols[col] = strtok(p, route_delims);
+ if (cols[col] == NULL)
+ return 0; /* didn't get enough columns */
+ p = NULL;
+ }
+
+ SIN_ADDR(rt->rt_dst) = strtoul(cols[route_dest_col], NULL, 16);
+ SIN_ADDR(rt->rt_gateway) = strtoul(cols[route_gw_col], NULL, 16);
+ SIN_ADDR(rt->rt_genmask) = strtoul(cols[route_mask_col], NULL, 16);
+
+ rt->rt_flags = (short) strtoul(cols[route_flags_col], NULL, 16);
+ rt->rt_dev = cols[route_dev_col];
+
+ return 1;
+}
+
+/********************************************************************
+ *
+ * defaultroute_exists - determine if there is a default route
+ */
+
+static int defaultroute_exists (struct rtentry *rt)
+{
+ int result = 0;
+
+ if (!open_route_table())
+ return 0;
+
+ while (read_route_table(rt) != 0) {
+ if ((rt->rt_flags & RTF_UP) == 0)
+ continue;
+
+ if (kernel_version > KVERSION(2,1,0) && SIN_ADDR(rt->rt_genmask) != 0)
+ continue;
+ if (SIN_ADDR(rt->rt_dst) == 0L) {
+ result = 1;
+ break;
+ }
+ }
+
+ close_route_table();
+ return result;
+}
+
+/*
+ * have_route_to - determine if the system has any route to
+ * a given IP address. `addr' is in network byte order.
+ * Return value is 1 if yes, 0 if no, -1 if don't know.
+ * For demand mode to work properly, we have to ignore routes
+ * through our own interface.
+ */
+int have_route_to(u_int32_t addr)
+{
+ struct rtentry rt;
+ int result = 0;
+
+ if (!open_route_table())
+ return -1; /* don't know */
+
+ while (read_route_table(&rt)) {
+ if ((rt.rt_flags & RTF_UP) == 0 || strcmp(rt.rt_dev, ifname) == 0)
+ continue;
+ if ((addr & SIN_ADDR(rt.rt_genmask)) == SIN_ADDR(rt.rt_dst)) {
+ result = 1;
+ break;
+ }
+ }
+
+ close_route_table();
+ return result;
+}
+
+/********************************************************************
+ *
+ * sifdefaultroute - assign a default route through the address given.
+ */
+
+int sifdefaultroute (int unit, u_int32_t ouraddr, u_int32_t gateway)
+{
+ struct rtentry rt;
+
+ if (defaultroute_exists(&rt) && strcmp(rt.rt_dev, ifname) != 0) {
+ u_int32_t old_gateway = SIN_ADDR(rt.rt_gateway);
+
+ if (old_gateway != gateway)
+ error("not replacing existing default route to %s [%I]",
+ rt.rt_dev, old_gateway);
+ return 0;
+ }
+
+ memset (&rt, '\0', sizeof (rt));
+ SET_SA_FAMILY (rt.rt_dst, AF_INET);
+ SET_SA_FAMILY (rt.rt_gateway, AF_INET);
+
+ if (kernel_version > KVERSION(2,1,0)) {
+ SET_SA_FAMILY (rt.rt_genmask, AF_INET);
+ SIN_ADDR(rt.rt_genmask) = 0L;
+ }
+
+ SIN_ADDR(rt.rt_gateway) = gateway;
+
+ rt.rt_flags = RTF_UP | RTF_GATEWAY;
+ if (ioctl(sock_fd, SIOCADDRT, &rt) < 0) {
+ if ( ! ok_error ( errno ))
+ error("default route ioctl(SIOCADDRT): %m(%d)", errno);
+ return 0;
+ }
+
+ default_route_gateway = gateway;
+ return 1;
+}
+
+/********************************************************************
+ *
+ * cifdefaultroute - delete a default route through the address given.
+ */
+
+int cifdefaultroute (int unit, u_int32_t ouraddr, u_int32_t gateway)
+{
+ struct rtentry rt;
+
+ default_route_gateway = 0;
+
+ memset (&rt, '\0', sizeof (rt));
+ SET_SA_FAMILY (rt.rt_dst, AF_INET);
+ SET_SA_FAMILY (rt.rt_gateway, AF_INET);
+
+ if (kernel_version > KVERSION(2,1,0)) {
+ SET_SA_FAMILY (rt.rt_genmask, AF_INET);
+ SIN_ADDR(rt.rt_genmask) = 0L;
+ }
+
+ SIN_ADDR(rt.rt_gateway) = gateway;
+
+ rt.rt_flags = RTF_UP | RTF_GATEWAY;
+ if (ioctl(sock_fd, SIOCDELRT, &rt) < 0 && errno != ESRCH) {
+ if (still_ppp()) {
+ if ( ! ok_error ( errno ))
+ error("default route ioctl(SIOCDELRT): %m (%d)", errno);
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+/********************************************************************
+ *
+ * sifproxyarp - Make a proxy ARP entry for the peer.
+ */
+
+int sifproxyarp (int unit, u_int32_t his_adr)
+{
+ struct arpreq arpreq;
+ char *forw_path;
+
+ if (has_proxy_arp == 0) {
+ memset (&arpreq, '\0', sizeof(arpreq));
+
+ SET_SA_FAMILY(arpreq.arp_pa, AF_INET);
+ SIN_ADDR(arpreq.arp_pa) = his_adr;
+ arpreq.arp_flags = ATF_PERM | ATF_PUBL;
+/*
+ * Get the hardware address of an interface on the same subnet
+ * as our local address.
+ */
+ if (!get_ether_addr(his_adr, &arpreq.arp_ha, proxy_arp_dev,
+ sizeof(proxy_arp_dev))) {
+ error("Cannot determine ethernet address for proxy ARP");
+ return 0;
+ }
+ strlcpy(arpreq.arp_dev, proxy_arp_dev, sizeof(arpreq.arp_dev));
+
+ if (ioctl(sock_fd, SIOCSARP, (caddr_t)&arpreq) < 0) {
+ if ( ! ok_error ( errno ))
+ error("ioctl(SIOCSARP): %m(%d)", errno);
+ return 0;
+ }
+ proxy_arp_addr = his_adr;
+ has_proxy_arp = 1;
+
+ if (tune_kernel) {
+ forw_path = path_to_procfs("/sys/net/ipv4/ip_forward");
+ if (forw_path != 0) {
+ int fd = open(forw_path, O_WRONLY);
+ if (fd >= 0) {
+ if (write(fd, "1", 1) != 1)
+ error("Couldn't enable IP forwarding: %m");
+ close(fd);
+ }
+ }
+ }
+ }
+
+ return 1;
+}
+
+/********************************************************************
+ *
+ * cifproxyarp - Delete the proxy ARP entry for the peer.
+ */
+
+int cifproxyarp (int unit, u_int32_t his_adr)
+{
+ struct arpreq arpreq;
+
+ if (has_proxy_arp) {
+ has_proxy_arp = 0;
+ memset (&arpreq, '\0', sizeof(arpreq));
+ SET_SA_FAMILY(arpreq.arp_pa, AF_INET);
+ SIN_ADDR(arpreq.arp_pa) = his_adr;
+ arpreq.arp_flags = ATF_PERM | ATF_PUBL;
+ strlcpy(arpreq.arp_dev, proxy_arp_dev, sizeof(arpreq.arp_dev));
+
+ if (ioctl(sock_fd, SIOCDARP, (caddr_t)&arpreq) < 0) {
+ if ( ! ok_error ( errno ))
+ warn("ioctl(SIOCDARP): %m(%d)", errno);
+ return 0;
+ }
+ }
+ return 1;
+}
+
+/********************************************************************
+ *
+ * get_ether_addr - get the hardware address of an interface on the
+ * the same subnet as ipaddr.
+ */
+
+static int get_ether_addr (u_int32_t ipaddr,
+ struct sockaddr *hwaddr,
+ char *name, int namelen)
+{
+ struct ifreq *ifr, *ifend;
+ u_int32_t ina, mask;
+ char *aliasp;
+ struct ifreq ifreq;
+ struct ifconf ifc;
+ struct ifreq ifs[MAX_IFS];
+
+ ifc.ifc_len = sizeof(ifs);
+ ifc.ifc_req = ifs;
+ if (ioctl(sock_fd, SIOCGIFCONF, &ifc) < 0) {
+ if ( ! ok_error ( errno ))
+ error("ioctl(SIOCGIFCONF): %m(%d)", errno);
+ return 0;
+ }
+
+ SYSDEBUG ((LOG_DEBUG, "proxy arp: scanning %d interfaces for IP %s",
+ ifc.ifc_len / sizeof(struct ifreq), ip_ntoa(ipaddr)));
+/*
+ * Scan through looking for an interface with an Internet
+ * address on the same subnet as `ipaddr'.
+ */
+ ifend = ifs + (ifc.ifc_len / sizeof(struct ifreq));
+ for (ifr = ifc.ifc_req; ifr < ifend; ifr++) {
+ if (ifr->ifr_addr.sa_family == AF_INET) {
+ ina = SIN_ADDR(ifr->ifr_addr);
+ strlcpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name));
+ SYSDEBUG ((LOG_DEBUG, "proxy arp: examining interface %s",
+ ifreq.ifr_name));
+/*
+ * Check that the interface is up, and not point-to-point
+ * nor loopback.
+ */
+ if (ioctl(sock_fd, SIOCGIFFLAGS, &ifreq) < 0)
+ continue;
+
+ if (((ifreq.ifr_flags ^ FLAGS_GOOD) & FLAGS_MASK) != 0)
+ continue;
+/*
+ * Get its netmask and check that it's on the right subnet.
+ */
+ if (ioctl(sock_fd, SIOCGIFNETMASK, &ifreq) < 0)
+ continue;
+
+ mask = SIN_ADDR(ifreq.ifr_addr);
+ SYSDEBUG ((LOG_DEBUG, "proxy arp: interface addr %s mask %lx",
+ ip_ntoa(ina), ntohl(mask)));
+
+ if (((ipaddr ^ ina) & mask) != 0)
+ continue;
+ break;
+ }
+ }
+
+ if (ifr >= ifend)
+ return 0;
+
+ strlcpy(name, ifreq.ifr_name, namelen);
+
+ /* trim off the :1 in eth0:1 */
+ aliasp = strchr(name, ':');
+ if (aliasp != 0)
+ *aliasp = 0;
+
+ info("found interface %s for proxy arp", name);
+/*
+ * Now get the hardware address.
+ */
+ memset (&ifreq.ifr_hwaddr, 0, sizeof (struct sockaddr));
+ if (ioctl (sock_fd, SIOCGIFHWADDR, &ifreq) < 0) {
+ error("SIOCGIFHWADDR(%s): %m(%d)", ifreq.ifr_name, errno);
+ return 0;
+ }
+
+ memcpy (hwaddr,
+ &ifreq.ifr_hwaddr,
+ sizeof (struct sockaddr));
+
+ SYSDEBUG ((LOG_DEBUG,
+ "proxy arp: found hwaddr %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
+ (int) ((unsigned char *) &hwaddr->sa_data)[0],
+ (int) ((unsigned char *) &hwaddr->sa_data)[1],
+ (int) ((unsigned char *) &hwaddr->sa_data)[2],
+ (int) ((unsigned char *) &hwaddr->sa_data)[3],
+ (int) ((unsigned char *) &hwaddr->sa_data)[4],
+ (int) ((unsigned char *) &hwaddr->sa_data)[5],
+ (int) ((unsigned char *) &hwaddr->sa_data)[6],
+ (int) ((unsigned char *) &hwaddr->sa_data)[7]));
+ return 1;
+}
+
+/*
+ * get_if_hwaddr - get the hardware address for the specified
+ * network interface device.
+ */
+int
+get_if_hwaddr(u_char *addr, char *name)
+{
+ struct ifreq ifreq;
+ int ret, sock_fd;
+
+ sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (sock_fd < 0)
+ return 0;
+ memset(&ifreq.ifr_hwaddr, 0, sizeof(struct sockaddr));
+ strlcpy(ifreq.ifr_name, name, sizeof(ifreq.ifr_name));
+ ret = ioctl(sock_fd, SIOCGIFHWADDR, &ifreq);
+ close(sock_fd);
+ if (ret >= 0)
+ memcpy(addr, ifreq.ifr_hwaddr.sa_data, 6);
+ return ret;
+}
+
+/*
+ * get_first_ethernet - return the name of the first ethernet-style
+ * interface on this system.
+ */
+char *
+get_first_ethernet()
+{
+ return "eth0";
+}
+
+/********************************************************************
+ *
+ * Return user specified netmask, modified by any mask we might determine
+ * for address `addr' (in network byte order).
+ * Here we scan through the system's list of interfaces, looking for
+ * any non-point-to-point interfaces which might appear to be on the same
+ * network as `addr'. If we find any, we OR in their netmask to the
+ * user-specified netmask.
+ */
+
+u_int32_t GetMask (u_int32_t addr)
+{
+ u_int32_t mask, nmask, ina;
+ struct ifreq *ifr, *ifend, ifreq;
+ struct ifconf ifc;
+ struct ifreq ifs[MAX_IFS];
+
+ addr = ntohl(addr);
+
+ if (IN_CLASSA(addr)) /* determine network mask for address class */
+ nmask = IN_CLASSA_NET;
+ else if (IN_CLASSB(addr))
+ nmask = IN_CLASSB_NET;
+ else
+ nmask = IN_CLASSC_NET;
+
+ /* class D nets are disallowed by bad_ip_adrs */
+ mask = netmask | htonl(nmask);
+/*
+ * Scan through the system's network interfaces.
+ */
+ ifc.ifc_len = sizeof(ifs);
+ ifc.ifc_req = ifs;
+ if (ioctl(sock_fd, SIOCGIFCONF, &ifc) < 0) {
+ if ( ! ok_error ( errno ))
+ warn("ioctl(SIOCGIFCONF): %m(%d)", errno);
+ return mask;
+ }
+
+ ifend = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len);
+ for (ifr = ifc.ifc_req; ifr < ifend; ifr++) {
+/*
+ * Check the interface's internet address.
+ */
+ if (ifr->ifr_addr.sa_family != AF_INET)
+ continue;
+ ina = SIN_ADDR(ifr->ifr_addr);
+ if (((ntohl(ina) ^ addr) & nmask) != 0)
+ continue;
+/*
+ * Check that the interface is up, and not point-to-point nor loopback.
+ */
+ strlcpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name));
+ if (ioctl(sock_fd, SIOCGIFFLAGS, &ifreq) < 0)
+ continue;
+
+ if (((ifreq.ifr_flags ^ FLAGS_GOOD) & FLAGS_MASK) != 0)
+ continue;
+/*
+ * Get its netmask and OR it into our mask.
+ */
+ if (ioctl(sock_fd, SIOCGIFNETMASK, &ifreq) < 0)
+ continue;
+ mask |= SIN_ADDR(ifreq.ifr_addr);
+ break;
+ }
+ return mask;
+}
+
+/********************************************************************
+ *
+ * Internal routine to decode the version.modification.patch level
+ */
+
+static void decode_version (char *buf, int *version,
+ int *modification, int *patch)
+{
+ char *endp;
+
+ *version = (int) strtoul (buf, &endp, 10);
+ *modification = 0;
+ *patch = 0;
+
+ if (endp != buf && *endp == '.') {
+ buf = endp + 1;
+ *modification = (int) strtoul (buf, &endp, 10);
+ if (endp != buf && *endp == '.') {
+ buf = endp + 1;
+ *patch = (int) strtoul (buf, &buf, 10);
+ }
+ }
+}
+
+/********************************************************************
+ *
+ * Procedure to determine if the PPP line discipline is registered.
+ */
+
+static int
+ppp_registered(void)
+{
+ int local_fd;
+ int mfd = -1;
+ int ret = 0;
+ char slave[16];
+
+ /*
+ * We used to open the serial device and set it to the ppp line
+ * discipline here, in order to create a ppp unit. But that is
+ * not a good idea - the user might have specified a device that
+ * they can't open (permission, or maybe it doesn't really exist).
+ * So we grab a pty master/slave pair and use that.
+ */
+ if (!get_pty(&mfd, &local_fd, slave, 0)) {
+ no_ppp_msg = "Couldn't determine if PPP is supported (no free ptys)";
+ return 0;
+ }
+
+ /*
+ * Try to put the device into the PPP discipline.
+ */
+ if (ioctl(local_fd, TIOCSETD, &ppp_disc) < 0) {
+ error("ioctl(TIOCSETD(PPP)): %m(%d)", errno);
+ } else
+ ret = 1;
+
+ close(local_fd);
+ close(mfd);
+ return ret;
+}
+
+/********************************************************************
+ *
+ * ppp_available - check whether the system has any ppp interfaces
+ * (in fact we check whether we can do an ioctl on ppp0).
+ */
+
+int ppp_available(void)
+{
+ int s, ok, fd;
+ struct ifreq ifr;
+ int size;
+ int my_version, my_modification, my_patch;
+ int osmaj, osmin, ospatch;
+
+ no_ppp_msg =
+ "This system lacks kernel support for PPP. This could be because\n"
+ "the PPP kernel module could not be loaded, or because PPP was not\n"
+ "included in the kernel configuration. If PPP was included as a\n"
+ "module, try `/sbin/modprobe -v ppp'. If that fails, check that\n"
+ "ppp.o exists in /lib/modules/`uname -r`/net.\n"
+ "See README.linux file in the ppp distribution for more details.\n";
+
+ /* get the kernel version now, since we are called before sys_init */
+ uname(&utsname);
+ osmaj = osmin = ospatch = 0;
+ sscanf(utsname.release, "%d.%d.%d", &osmaj, &osmin, &ospatch);
+ kernel_version = KVERSION(osmaj, osmin, ospatch);
+
+ fd = open("/dev/ppp", O_RDWR);
+#if 0
+ if (fd < 0 && errno == ENOENT) {
+ /* try making it and see if that helps. */
+ if (mknod("/dev/ppp", S_IFCHR | S_IRUSR | S_IWUSR,
+ makedev(108, 0)) >= 0) {
+ fd = open("/dev/ppp", O_RDWR);
+ if (fd >= 0)
+ info("Created /dev/ppp device node");
+ else
+ unlink("/dev/ppp"); /* didn't work, undo the mknod */
+ } else if (errno == EEXIST) {
+ fd = open("/dev/ppp", O_RDWR);
+ }
+ }
+#endif /* 0 */
+ if (fd >= 0) {
+ new_style_driver = 1;
+
+ /* XXX should get from driver */
+ driver_version = 2;
+ driver_modification = 4;
+ driver_patch = 0;
+ close(fd);
+ return 1;
+ }
+ if (kernel_version >= KVERSION(2,3,13)) {
+ if (errno == ENOENT)
+ no_ppp_msg =
+ "pppd is unable to open the /dev/ppp device.\n"
+ "You need to create the /dev/ppp device node by\n"
+ "executing the following command as root:\n"
+ " mknod /dev/ppp c 108 0\n";
+ return 0;
+ }
+
+/*
+ * Open a socket for doing the ioctl operations.
+ */
+ s = socket(AF_INET, SOCK_DGRAM, 0);
+ if (s < 0)
+ return 0;
+
+ strlcpy (ifr.ifr_name, "ppp0", sizeof (ifr.ifr_name));
+ ok = ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) >= 0;
+/*
+ * If the device did not exist then attempt to create one by putting the
+ * current tty into the PPP discipline. If this works then obtain the
+ * flags for the device again.
+ */
+ if (!ok) {
+ if (ppp_registered()) {
+ strlcpy (ifr.ifr_name, "ppp0", sizeof (ifr.ifr_name));
+ ok = ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) >= 0;
+ }
+ }
+/*
+ * Ensure that the hardware address is for PPP and not something else
+ */
+ if (ok)
+ ok = ioctl (s, SIOCGIFHWADDR, (caddr_t) &ifr) >= 0;
+
+ if (ok && ((ifr.ifr_hwaddr.sa_family & ~0xFF) != ARPHRD_PPP))
+ ok = 0;
+
+/*
+ * This is the PPP device. Validate the version of the driver at this
+ * point to ensure that this program will work with the driver.
+ */
+ if (ok) {
+ char abBuffer [1024];
+
+ ifr.ifr_data = abBuffer;
+ size = ioctl (s, SIOCGPPPVER, (caddr_t) &ifr);
+ if (size < 0) {
+ error("Couldn't read driver version: %m");
+ ok = 0;
+ no_ppp_msg = "Sorry, couldn't verify kernel driver version\n";
+
+ } else {
+ decode_version(abBuffer,
+ &driver_version,
+ &driver_modification,
+ &driver_patch);
+/*
+ * Validate the version of the driver against the version that we used.
+ */
+ decode_version(VERSION,
+ &my_version,
+ &my_modification,
+ &my_patch);
+
+ /* The version numbers must match */
+ if (driver_version != my_version)
+ ok = 0;
+
+ /* The modification levels must be legal */
+ if (driver_modification < 3) {
+ if (driver_modification >= 2) {
+ /* we can cope with 2.2.0 and above */
+ driver_is_old = 1;
+ } else {
+ ok = 0;
+ }
+ }
+
+ close (s);
+ if (!ok) {
+ slprintf(route_buffer, sizeof(route_buffer),
+ "Sorry - PPP driver version %d.%d.%d is out of date\n",
+ driver_version, driver_modification, driver_patch);
+
+ no_ppp_msg = route_buffer;
+ }
+ }
+ }
+ return ok;
+}
+
+/********************************************************************
+ *
+ * Update the wtmp file with the appropriate user name and tty device.
+ */
+
+void logwtmp (const char *line, const char *name, const char *host)
+{
+ struct utmp ut, *utp;
+ pid_t mypid = getpid();
+#if __GLIBC__ < 2
+ int wtmp;
+#endif
+
+/*
+ * Update the signon database for users.
+ * Christoph Lameter: Copied from poeigl-1.36 Jan 3, 1996
+ */
+ utmpname(_PATH_UTMP);
+ setutent();
+ while ((utp = getutent()) && (utp->ut_pid != mypid))
+ /* nothing */;
+
+ /* Is this call really necessary? There is another one after the 'put' */
+ endutent();
+
+ if (utp)
+ memcpy(&ut, utp, sizeof(ut));
+ else
+ /* some gettys/telnetds don't initialize utmp... */
+ memset(&ut, 0, sizeof(ut));
+
+ if (ut.ut_id[0] == 0)
+ strncpy(ut.ut_id, line + 3, sizeof(ut.ut_id));
+
+ strncpy(ut.ut_user, name, sizeof(ut.ut_user));
+ strncpy(ut.ut_line, line, sizeof(ut.ut_line));
+
+ time(&ut.ut_time);
+
+ ut.ut_type = USER_PROCESS;
+ ut.ut_pid = mypid;
+
+ /* Insert the host name if one is supplied */
+ if (*host)
+ strncpy (ut.ut_host, host, sizeof(ut.ut_host));
+
+ /* Insert the IP address of the remote system if IP is enabled */
+ if (ipcp_protent.enabled_flag && ipcp_hisoptions[0].neg_addr)
+ memcpy(&ut.ut_addr, (char *) &ipcp_hisoptions[0].hisaddr,
+ sizeof(ut.ut_addr));
+
+ /* CL: Makes sure that the logout works */
+ if (*host == 0 && *name==0)
+ ut.ut_host[0]=0;
+
+ pututline(&ut);
+ endutent();
+/*
+ * Update the wtmp file.
+ */
+#if __GLIBC__ >= 2
+ updwtmp(_PATH_WTMP, &ut);
+#else
+ wtmp = open(_PATH_WTMP, O_APPEND|O_WRONLY);
+ if (wtmp >= 0) {
+ flock(wtmp, LOCK_EX);
+
+ if (write (wtmp, (char *)&ut, sizeof(ut)) != sizeof(ut))
+ warn("error writing %s: %m", _PATH_WTMP);
+
+ flock(wtmp, LOCK_UN);
+
+ close (wtmp);
+ }
+#endif
+}
+
+
+/********************************************************************
+ *
+ * sifvjcomp - config tcp header compression
+ */
+
+int sifvjcomp (int u, int vjcomp, int cidcomp, int maxcid)
+{
+ u_int x = get_flags(ppp_dev_fd);
+
+ if (vjcomp) {
+ if (ioctl (ppp_dev_fd, PPPIOCSMAXCID, (caddr_t) &maxcid) < 0) {
+ if (! ok_error (errno))
+ error("ioctl(PPPIOCSMAXCID): %m(%d)", errno);
+ vjcomp = 0;
+ }
+ }
+
+ x = vjcomp ? x | SC_COMP_TCP : x &~ SC_COMP_TCP;
+ x = cidcomp ? x & ~SC_NO_TCP_CCID : x | SC_NO_TCP_CCID;
+ set_flags (ppp_dev_fd, x);
+
+ return 1;
+}
+
+/********************************************************************
+ *
+ * sifup - Config the interface up and enable IP packets to pass.
+ */
+
+int sifup(int u)
+{
+ struct ifreq ifr;
+
+ memset (&ifr, '\0', sizeof (ifr));
+ strlcpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
+ if (ioctl(sock_fd, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
+ if (! ok_error (errno))
+ error("ioctl (SIOCGIFFLAGS): %m(%d)", errno);
+ return 0;
+ }
+
+ ifr.ifr_flags |= (IFF_UP | IFF_POINTOPOINT);
+ if (ioctl(sock_fd, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
+ if (! ok_error (errno))
+ error("ioctl(SIOCSIFFLAGS): %m(%d)", errno);
+ return 0;
+ }
+ if_is_up++;
+
+ return 1;
+}
+
+/********************************************************************
+ *
+ * sifdown - Disable the indicated protocol and config the interface
+ * down if there are no remaining protocols.
+ */
+
+int sifdown (int u)
+{
+ struct ifreq ifr;
+
+ if (if_is_up && --if_is_up > 0)
+ return 1;
+
+ memset (&ifr, '\0', sizeof (ifr));
+ strlcpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
+ if (ioctl(sock_fd, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
+ if (! ok_error (errno))
+ error("ioctl (SIOCGIFFLAGS): %m(%d)", errno);
+ return 0;
+ }
+
+ ifr.ifr_flags &= ~IFF_UP;
+ ifr.ifr_flags |= IFF_POINTOPOINT;
+ if (ioctl(sock_fd, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
+ if (! ok_error (errno))
+ error("ioctl(SIOCSIFFLAGS): %m(%d)", errno);
+ return 0;
+ }
+ return 1;
+}
+
+/********************************************************************
+ *
+ * sifaddr - Config the interface IP addresses and netmask.
+ */
+
+int sifaddr (int unit, u_int32_t our_adr, u_int32_t his_adr,
+ u_int32_t net_mask)
+{
+ struct ifreq ifr;
+ struct rtentry rt;
+
+ memset (&ifr, '\0', sizeof (ifr));
+ memset (&rt, '\0', sizeof (rt));
+
+ SET_SA_FAMILY (ifr.ifr_addr, AF_INET);
+ SET_SA_FAMILY (ifr.ifr_dstaddr, AF_INET);
+ SET_SA_FAMILY (ifr.ifr_netmask, AF_INET);
+
+ strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
+/*
+ * Set our IP address
+ */
+ SIN_ADDR(ifr.ifr_addr) = our_adr;
+ if (ioctl(sock_fd, SIOCSIFADDR, (caddr_t) &ifr) < 0) {
+ if (errno != EEXIST) {
+ if (! ok_error (errno))
+ error("ioctl(SIOCSIFADDR): %m(%d)", errno);
+ }
+ else {
+ warn("ioctl(SIOCSIFADDR): Address already exists");
+ }
+ return (0);
+ }
+/*
+ * Set the gateway address
+ */
+ SIN_ADDR(ifr.ifr_dstaddr) = his_adr;
+ if (ioctl(sock_fd, SIOCSIFDSTADDR, (caddr_t) &ifr) < 0) {
+ if (! ok_error (errno))
+ error("ioctl(SIOCSIFDSTADDR): %m(%d)", errno);
+ return (0);
+ }
+/*
+ * Set the netmask.
+ * For recent kernels, force the netmask to 255.255.255.255.
+ */
+ if (kernel_version >= KVERSION(2,1,16))
+ net_mask = ~0L;
+ if (net_mask != 0) {
+ SIN_ADDR(ifr.ifr_netmask) = net_mask;
+ if (ioctl(sock_fd, SIOCSIFNETMASK, (caddr_t) &ifr) < 0) {
+ if (! ok_error (errno))
+ error("ioctl(SIOCSIFNETMASK): %m(%d)", errno);
+ return (0);
+ }
+ }
+/*
+ * Add the device route
+ */
+ if (kernel_version < KVERSION(2,1,16)) {
+ SET_SA_FAMILY (rt.rt_dst, AF_INET);
+ SET_SA_FAMILY (rt.rt_gateway, AF_INET);
+ rt.rt_dev = ifname;
+
+ SIN_ADDR(rt.rt_gateway) = 0L;
+ SIN_ADDR(rt.rt_dst) = his_adr;
+ rt.rt_flags = RTF_UP | RTF_HOST;
+
+ if (kernel_version > KVERSION(2,1,0)) {
+ SET_SA_FAMILY (rt.rt_genmask, AF_INET);
+ SIN_ADDR(rt.rt_genmask) = -1L;
+ }
+
+ if (ioctl(sock_fd, SIOCADDRT, &rt) < 0) {
+ if (! ok_error (errno))
+ error("ioctl(SIOCADDRT) device route: %m(%d)", errno);
+ return (0);
+ }
+ }
+
+ /* set ip_dynaddr in demand mode if address changes */
+ if (demand && tune_kernel && !dynaddr_set
+ && our_old_addr && our_old_addr != our_adr) {
+ /* set ip_dynaddr if possible */
+ char *path;
+ int fd;
+
+ path = path_to_procfs("/sys/net/ipv4/ip_dynaddr");
+ if (path != 0 && (fd = open(path, O_WRONLY)) >= 0) {
+ if (write(fd, "1", 1) != 1)
+ error("Couldn't enable dynamic IP addressing: %m");
+ close(fd);
+ }
+ dynaddr_set = 1; /* only 1 attempt */
+ }
+ our_old_addr = 0;
+
+ return 1;
+}
+
+/********************************************************************
+ *
+ * cifaddr - Clear the interface IP addresses, and delete routes
+ * through the interface if possible.
+ */
+
+int cifaddr (int unit, u_int32_t our_adr, u_int32_t his_adr)
+{
+ struct ifreq ifr;
+
+ if (kernel_version < KVERSION(2,1,16)) {
+/*
+ * Delete the route through the device
+ */
+ struct rtentry rt;
+ memset (&rt, '\0', sizeof (rt));
+
+ SET_SA_FAMILY (rt.rt_dst, AF_INET);
+ SET_SA_FAMILY (rt.rt_gateway, AF_INET);
+ rt.rt_dev = ifname;
+
+ SIN_ADDR(rt.rt_gateway) = 0;
+ SIN_ADDR(rt.rt_dst) = his_adr;
+ rt.rt_flags = RTF_UP | RTF_HOST;
+
+ if (kernel_version > KVERSION(2,1,0)) {
+ SET_SA_FAMILY (rt.rt_genmask, AF_INET);
+ SIN_ADDR(rt.rt_genmask) = -1L;
+ }
+
+ if (ioctl(sock_fd, SIOCDELRT, &rt) < 0 && errno != ESRCH) {
+ if (still_ppp() && ! ok_error (errno))
+ error("ioctl(SIOCDELRT) device route: %m(%d)", errno);
+ return (0);
+ }
+ }
+
+ /* This way it is possible to have an IPX-only or IPv6-only interface */
+ memset(&ifr, 0, sizeof(ifr));
+ SET_SA_FAMILY(ifr.ifr_addr, AF_INET);
+ strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+
+ if (ioctl(sock_fd, SIOCSIFADDR, (caddr_t) &ifr) < 0) {
+ if (! ok_error (errno)) {
+ error("ioctl(SIOCSIFADDR): %m(%d)", errno);
+ return 0;
+ }
+ }
+
+ our_old_addr = our_adr;
+
+ return 1;
+}
+
+#ifdef INET6
+/********************************************************************
+ *
+ * sif6addr - Config the interface with an IPv6 link-local address
+ */
+int sif6addr (int unit, eui64_t our_eui64, eui64_t his_eui64)
+{
+ struct in6_ifreq ifr6;
+ struct ifreq ifr;
+ struct in6_rtmsg rt6;
+
+ if (sock6_fd < 0) {
+ errno = -sock6_fd;
+ error("IPv6 socket creation failed: %m");
+ return 0;
+ }
+ memset(&ifr, 0, sizeof (ifr));
+ strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+ if (ioctl(sock6_fd, SIOCGIFINDEX, (caddr_t) &ifr) < 0) {
+ error("sif6addr: ioctl(SIOCGIFINDEX): %m (%d)", errno);
+ return 0;
+ }
+
+ /* Local interface */
+ memset(&ifr6, 0, sizeof(ifr6));
+ IN6_LLADDR_FROM_EUI64(ifr6.ifr6_addr, our_eui64);
+ ifr6.ifr6_ifindex = ifr.ifr_ifindex;
+ ifr6.ifr6_prefixlen = 10;
+
+ if (ioctl(sock6_fd, SIOCSIFADDR, &ifr6) < 0) {
+ error("sif6addr: ioctl(SIOCSIFADDR): %m (%d)", errno);
+ return 0;
+ }
+
+ /* Route to remote host */
+ memset(&rt6, 0, sizeof(rt6));
+ IN6_LLADDR_FROM_EUI64(rt6.rtmsg_dst, his_eui64);
+ rt6.rtmsg_flags = RTF_UP;
+ rt6.rtmsg_dst_len = 10;
+ rt6.rtmsg_ifindex = ifr.ifr_ifindex;
+ rt6.rtmsg_metric = 1;
+
+ if (ioctl(sock6_fd, SIOCADDRT, &rt6) < 0) {
+ error("sif6addr: ioctl(SIOCADDRT): %m (%d)", errno);
+ return 0;
+ }
+
+ return 1;
+}
+
+
+/********************************************************************
+ *
+ * cif6addr - Remove IPv6 address from interface
+ */
+int cif6addr (int unit, eui64_t our_eui64, eui64_t his_eui64)
+{
+ struct ifreq ifr;
+ struct in6_ifreq ifr6;
+
+ if (sock6_fd < 0) {
+ errno = -sock6_fd;
+ error("IPv6 socket creation failed: %m");
+ return 0;
+ }
+ memset(&ifr, 0, sizeof(ifr));
+ strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+ if (ioctl(sock6_fd, SIOCGIFINDEX, (caddr_t) &ifr) < 0) {
+ error("cif6addr: ioctl(SIOCGIFINDEX): %m (%d)", errno);
+ return 0;
+ }
+
+ memset(&ifr6, 0, sizeof(ifr6));
+ IN6_LLADDR_FROM_EUI64(ifr6.ifr6_addr, our_eui64);
+ ifr6.ifr6_ifindex = ifr.ifr_ifindex;
+ ifr6.ifr6_prefixlen = 10;
+
+ if (ioctl(sock6_fd, SIOCDIFADDR, &ifr6) < 0) {
+ if (errno != EADDRNOTAVAIL) {
+ if (! ok_error (errno))
+ error("cif6addr: ioctl(SIOCDIFADDR): %m (%d)", errno);
+ }
+ else {
+ warn("cif6addr: ioctl(SIOCDIFADDR): No such address");
+ }
+ return (0);
+ }
+ return 1;
+}
+#endif /* INET6 */
+
+/*
+ * get_pty - get a pty master/slave pair and chown the slave side
+ * to the uid given. Assumes slave_name points to >= 16 bytes of space.
+ */
+int
+get_pty(master_fdp, slave_fdp, slave_name, uid)
+ int *master_fdp;
+ int *slave_fdp;
+ char *slave_name;
+ int uid;
+{
+ int i, mfd, sfd = -1;
+ char pty_name[16];
+ struct termios tios;
+
+#ifdef TIOCGPTN
+ /*
+ * Try the unix98 way first.
+ */
+ mfd = open("/dev/ptmx", O_RDWR);
+ if (mfd >= 0) {
+ int ptn;
+ if (ioctl(mfd, TIOCGPTN, &ptn) >= 0) {
+ slprintf(pty_name, sizeof(pty_name), "/dev/pts/%d", ptn);
+ chmod(pty_name, S_IRUSR | S_IWUSR);
+#ifdef TIOCSPTLCK
+ ptn = 0;
+ if (ioctl(mfd, TIOCSPTLCK, &ptn) < 0)
+ warn("Couldn't unlock pty slave %s: %m", pty_name);
+#endif
+ if ((sfd = open(pty_name, O_RDWR | O_NOCTTY)) < 0)
+ warn("Couldn't open pty slave %s: %m", pty_name);
+ }
+ }
+#endif /* TIOCGPTN */
+
+ if (sfd < 0) {
+ /* the old way - scan through the pty name space */
+ for (i = 0; i < 64; ++i) {
+ slprintf(pty_name, sizeof(pty_name), "/dev/pty%c%x",
+ 'p' + i / 16, i % 16);
+ mfd = open(pty_name, O_RDWR, 0);
+ if (mfd >= 0) {
+ pty_name[5] = 't';
+ sfd = open(pty_name, O_RDWR | O_NOCTTY, 0);
+ if (sfd >= 0) {
+ fchown(sfd, uid, -1);
+ fchmod(sfd, S_IRUSR | S_IWUSR);
+ break;
+ }
+ close(mfd);
+ }
+ }
+ }
+
+ if (sfd < 0)
+ return 0;
+
+ strlcpy(slave_name, pty_name, 16);
+ *master_fdp = mfd;
+ *slave_fdp = sfd;
+ if (tcgetattr(sfd, &tios) == 0) {
+ tios.c_cflag &= ~(CSIZE | CSTOPB | PARENB);
+ tios.c_cflag |= CS8 | CREAD | CLOCAL;
+ tios.c_iflag = IGNPAR;
+ tios.c_oflag = 0;
+ tios.c_lflag = 0;
+ if (tcsetattr(sfd, TCSAFLUSH, &tios) < 0)
+ warn("couldn't set attributes on pty: %m");
+ } else
+ warn("couldn't get attributes on pty: %m");
+
+ return 1;
+}
+
+/********************************************************************
+ *
+ * open_loopback - open the device we use for getting packets
+ * in demand mode. Under Linux, we use a pty master/slave pair.
+ */
+int
+open_ppp_loopback(void)
+{
+ int flags;
+
+ looped = 1;
+ if (new_style_driver) {
+ /* allocate ourselves a ppp unit */
+ if (make_ppp_unit() < 0)
+ die(1);
+ set_flags(ppp_dev_fd, SC_LOOP_TRAFFIC);
+ set_kdebugflag(kdebugflag);
+ ppp_fd = -1;
+ return ppp_dev_fd;
+ }
+
+ if (!get_pty(&master_fd, &slave_fd, loop_name, 0))
+ fatal("No free pty for loopback");
+ SYSDEBUG(("using %s for loopback", loop_name));
+
+ set_ppp_fd(slave_fd);
+
+ flags = fcntl(master_fd, F_GETFL);
+ if (flags == -1 ||
+ fcntl(master_fd, F_SETFL, flags | O_NONBLOCK) == -1)
+ warn("couldn't set master loopback to nonblock: %m(%d)", errno);
+
+ flags = fcntl(ppp_fd, F_GETFL);
+ if (flags == -1 ||
+ fcntl(ppp_fd, F_SETFL, flags | O_NONBLOCK) == -1)
+ warn("couldn't set slave loopback to nonblock: %m(%d)", errno);
+
+ if (ioctl(ppp_fd, TIOCSETD, &ppp_disc) < 0)
+ fatal("ioctl(TIOCSETD): %m(%d)", errno);
+/*
+ * Find out which interface we were given.
+ */
+ if (ioctl(ppp_fd, PPPIOCGUNIT, &ifunit) < 0)
+ fatal("ioctl(PPPIOCGUNIT): %m(%d)", errno);
+/*
+ * Enable debug in the driver if requested.
+ */
+ set_kdebugflag (kdebugflag);
+
+ return master_fd;
+}
+
+/********************************************************************
+ *
+ * restore_loop - reattach the ppp unit to the loopback.
+ *
+ * The kernel ppp driver automatically reattaches the ppp unit to
+ * the loopback if the serial port is set to a line discipline other
+ * than ppp, or if it detects a modem hangup. The former will happen
+ * in disestablish_ppp if the latter hasn't already happened, so we
+ * shouldn't need to do anything.
+ *
+ * Just to be sure, set the real serial port to the normal discipline.
+ */
+
+static void
+restore_loop(void)
+{
+ looped = 1;
+ if (new_style_driver) {
+ set_flags(ppp_dev_fd, get_flags(ppp_dev_fd) | SC_LOOP_TRAFFIC);
+ return;
+ }
+ if (ppp_fd != slave_fd) {
+ (void) ioctl(ppp_fd, TIOCSETD, &tty_disc);
+ set_ppp_fd(slave_fd);
+ }
+}
+
+/********************************************************************
+ *
+ * sifnpmode - Set the mode for handling packets for a given NP.
+ */
+
+int
+sifnpmode(u, proto, mode)
+ int u;
+ int proto;
+ enum NPmode mode;
+{
+ struct npioctl npi;
+
+ npi.protocol = proto;
+ npi.mode = mode;
+ if (ioctl(ppp_dev_fd, PPPIOCSNPMODE, (caddr_t) &npi) < 0) {
+ if (! ok_error (errno))
+ error("ioctl(PPPIOCSNPMODE, %d, %d): %m (%d)",
+ proto, mode, errno);
+ return 0;
+ }
+ return 1;
+}
+
+
+/********************************************************************
+ *
+ * sipxfaddr - Config the interface IPX networknumber
+ */
+
+int sipxfaddr (int unit, unsigned long int network, unsigned char * node )
+{
+ int result = 1;
+
+#ifdef IPX_CHANGE
+ int skfd;
+ struct ifreq ifr;
+ struct sockaddr_ipx *sipx = (struct sockaddr_ipx *) &ifr.ifr_addr;
+
+ skfd = socket (AF_IPX, SOCK_DGRAM, 0);
+ if (skfd < 0) {
+ if (! ok_error (errno))
+ dbglog("socket(AF_IPX): %m (%d)", errno);
+ result = 0;
+ }
+ else {
+ memset (&ifr, '\0', sizeof (ifr));
+ strlcpy (ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+
+ memcpy (sipx->sipx_node, node, IPX_NODE_LEN);
+ sipx->sipx_family = AF_IPX;
+ sipx->sipx_port = 0;
+ sipx->sipx_network = htonl (network);
+ sipx->sipx_type = IPX_FRAME_ETHERII;
+ sipx->sipx_action = IPX_CRTITF;
+/*
+ * Set the IPX device
+ */
+ if (ioctl(skfd, SIOCSIFADDR, (caddr_t) &ifr) < 0) {
+ result = 0;
+ if (errno != EEXIST) {
+ if (! ok_error (errno))
+ dbglog("ioctl(SIOCSIFADDR, CRTITF): %m (%d)", errno);
+ }
+ else {
+ warn("ioctl(SIOCSIFADDR, CRTITF): Address already exists");
+ }
+ }
+ close (skfd);
+ }
+#endif
+ return result;
+}
+
+/********************************************************************
+ *
+ * cipxfaddr - Clear the information for the IPX network. The IPX routes
+ * are removed and the device is no longer able to pass IPX
+ * frames.
+ */
+
+int cipxfaddr (int unit)
+{
+ int result = 1;
+
+#ifdef IPX_CHANGE
+ int skfd;
+ struct ifreq ifr;
+ struct sockaddr_ipx *sipx = (struct sockaddr_ipx *) &ifr.ifr_addr;
+
+ skfd = socket (AF_IPX, SOCK_DGRAM, 0);
+ if (skfd < 0) {
+ if (! ok_error (errno))
+ dbglog("socket(AF_IPX): %m (%d)", errno);
+ result = 0;
+ }
+ else {
+ memset (&ifr, '\0', sizeof (ifr));
+ strlcpy (ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+
+ sipx->sipx_type = IPX_FRAME_ETHERII;
+ sipx->sipx_action = IPX_DLTITF;
+ sipx->sipx_family = AF_IPX;
+/*
+ * Set the IPX device
+ */
+ if (ioctl(skfd, SIOCSIFADDR, (caddr_t) &ifr) < 0) {
+ if (! ok_error (errno))
+ info("ioctl(SIOCSIFADDR, IPX_DLTITF): %m (%d)", errno);
+ result = 0;
+ }
+ close (skfd);
+ }
+#endif
+ return result;
+}
+
+/*
+ * Use the hostname as part of the random number seed.
+ */
+int
+get_host_seed()
+{
+ int h;
+ char *p = hostname;
+
+ h = 407;
+ for (p = hostname; *p != 0; ++p)
+ h = h * 37 + *p;
+ return h;
+}
+
+/********************************************************************
+ *
+ * sys_check_options - check the options that the user specified
+ */
+
+int
+sys_check_options(void)
+{
+#ifdef IPX_CHANGE
+/*
+ * Disable the IPX protocol if the support is not present in the kernel.
+ */
+ char *path;
+
+ if (ipxcp_protent.enabled_flag) {
+ struct stat stat_buf;
+ if ((path = path_to_procfs("/net/ipx_interface")) == 0
+ || lstat(path, &stat_buf) < 0) {
+ error("IPX support is not present in the kernel\n");
+ ipxcp_protent.enabled_flag = 0;
+ }
+ }
+#endif
+ if (demand && driver_is_old) {
+ option_error("demand dialling is not supported by kernel driver "
+ "version %d.%d.%d", driver_version, driver_modification,
+ driver_patch);
+ return 0;
+ }
+ if (multilink && !new_style_driver) {
+ warn("Warning: multilink is not supported by the kernel driver");
+ multilink = 0;
+ }
+ return 1;
+}
diff --git a/mdk-stage1/ppp/pppd/sys-solaris.c b/mdk-stage1/ppp/pppd/sys-solaris.c
new file mode 100644
index 000000000..60b3003ed
--- /dev/null
+++ b/mdk-stage1/ppp/pppd/sys-solaris.c
@@ -0,0 +1,2737 @@
+/*
+ * System-dependent procedures for pppd under Solaris 2.
+ *
+ * Parts re-written by Adi Masputra <adi.masputra@sun.com>, based on
+ * the original sys-svr4.c
+ *
+ * Copyright (c) 2000 by Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation is hereby granted, provided that the above copyright
+ * notice appears in all copies.
+ *
+ * SUN MAKES NO REPRESENTATION OR WARRANTIES ABOUT THE SUITABILITY OF
+ * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
+ * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES
+ *
+ * Copyright (c) 1994 The Australian National University.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation is hereby granted, provided that the above copyright
+ * notice appears in all copies. This software is provided without any
+ * warranty, express or implied. The Australian National University
+ * makes no representations about the suitability of this software for
+ * any purpose.
+ *
+ * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
+ * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
+ * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
+ * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
+ * OR MODIFICATIONS.
+ */
+
+#define RCSID "$Id: sys-solaris.c 195720 2001-06-11 11:44:34Z gc $"
+
+#include <limits.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <termios.h>
+#ifndef CRTSCTS
+#include <sys/termiox.h>
+#endif
+#include <signal.h>
+#include <utmpx.h>
+#include <sys/types.h>
+#include <sys/ioccom.h>
+#include <sys/stream.h>
+#include <sys/stropts.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <sys/sysmacros.h>
+#include <sys/systeminfo.h>
+#include <sys/dlpi.h>
+#include <sys/stat.h>
+#include <sys/mkdev.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <net/route.h>
+#include <net/ppp_defs.h>
+#include <net/pppio.h>
+#include <netinet/in.h>
+#ifdef SOL2
+#include <sys/tihdr.h>
+#include <sys/tiuser.h>
+#include <inet/common.h>
+#include <inet/mib2.h>
+#include <sys/ethernet.h>
+#endif
+
+#include "pppd.h"
+#include "fsm.h"
+#include "lcp.h"
+#include "ipcp.h"
+#include "ccp.h"
+
+#if !defined(PPP_DRV_NAME)
+#define PPP_DRV_NAME "ppp"
+#endif /* !defined(PPP_DRV_NAME) */
+
+#if !defined(PPP_DEV_NAME)
+#define PPP_DEV_NAME "/dev/" PPP_DRV_NAME
+#endif /* !defined(PPP_DEV_NAME) */
+
+#if !defined(AHDLC_MOD_NAME)
+#define AHDLC_MOD_NAME "ppp_ahdl"
+#endif /* !defined(AHDLC_MOD_NAME) */
+
+#if !defined(COMP_MOD_NAME)
+#define COMP_MOD_NAME "ppp_comp"
+#endif /* !defined(COMP_MOD_NAME) */
+
+#if !defined(IP_DEV_NAME)
+#define IP_DEV_NAME "/dev/ip"
+#endif /* !defined(IP_DEV_NAME) */
+
+#if !defined(IP_MOD_NAME)
+#define IP_MOD_NAME "ip"
+#endif /* !defined(IP_MOD_NAME) */
+
+#if !defined(UDP_DEV_NAME) && defined(SOL2)
+#define UDP_DEV_NAME "/dev/udp"
+#endif /* !defined(UDP_DEV_NAME) && defined(SOL2) */
+
+#if !defined(UDP6_DEV_NAME) && defined(SOL2)
+#define UDP6_DEV_NAME "/dev/udp6"
+#endif /* !defined(UDP6_DEV_NAME) && defined(SOL2) */
+
+static const char rcsid[] = RCSID;
+
+#if defined(SOL2)
+/*
+ * "/dev/udp" is used as a multiplexor to PLINK the interface stream
+ * under. It is used in place of "/dev/ip" since STREAMS will not let
+ * a driver be PLINK'ed under itself, and "/dev/ip" is typically the
+ * driver at the bottom of the tunneling interfaces stream.
+ */
+static char *mux_dev_name = UDP_DEV_NAME;
+#else
+static char *mux_dev_name = IP_DEV_NAME;
+#endif
+static int pppfd;
+static int fdmuxid = -1;
+static int ipfd;
+static int ipmuxid = -1;
+
+#if defined(INET6) && defined(SOL2)
+static int ip6fd; /* IP file descriptor */
+static int ip6muxid = -1; /* Multiplexer file descriptor */
+static int if6_is_up = 0; /* IPv6 interface has been marked up */
+
+#define _IN6_LLX_FROM_EUI64(l, s, eui64, as) do { \
+ s->sin6_addr.s6_addr32[0] = htonl(as); \
+ eui64_copy(eui64, s->sin6_addr.s6_addr32[2]); \
+ s->sin6_family = AF_INET6; \
+ l.lifr_addr.ss_family = AF_INET6; \
+ l.lifr_addrlen = 10; \
+ l.lifr_addr = laddr; \
+ } while (0)
+
+#define IN6_LLADDR_FROM_EUI64(l, s, eui64) \
+ _IN6_LLX_FROM_EUI64(l, s, eui64, 0xfe800000)
+
+#define IN6_LLTOKEN_FROM_EUI64(l, s, eui64) \
+ _IN6_LLX_FROM_EUI64(l, s, eui64, 0)
+
+#endif /* defined(INET6) && defined(SOL2) */
+
+#if defined(INET6) && defined(SOL2)
+static char first_ether_name[LIFNAMSIZ]; /* Solaris 8 and above */
+#else
+static char first_ether_name[IFNAMSIZ]; /* Before Solaris 8 */
+#define MAXIFS 256 /* Max # of interfaces */
+#endif /* defined(INET6) && defined(SOL2) */
+
+static int restore_term;
+static struct termios inittermios;
+#ifndef CRTSCTS
+static struct termiox inittermiox;
+static int termiox_ok;
+#endif
+static struct winsize wsinfo; /* Initial window size info */
+static pid_t tty_sid; /* original session ID for terminal */
+
+extern u_char inpacket_buf[]; /* borrowed from main.c */
+
+#define MAX_POLLFDS 32
+static struct pollfd pollfds[MAX_POLLFDS];
+static int n_pollfds;
+
+static int link_mtu, link_mru;
+
+#define NMODULES 32
+static int tty_nmodules;
+static char tty_modules[NMODULES][FMNAMESZ+1];
+static int tty_npushed;
+
+static int if_is_up; /* Interface has been marked up */
+static u_int32_t remote_addr; /* IP address of peer */
+static u_int32_t default_route_gateway; /* Gateway for default route added */
+static u_int32_t proxy_arp_addr; /* Addr for proxy arp entry added */
+
+/* Prototypes for procedures local to this file. */
+static int translate_speed __P((int));
+static int baud_rate_of __P((int));
+static int get_ether_addr __P((u_int32_t, struct sockaddr *));
+static int get_hw_addr __P((char *, u_int32_t, struct sockaddr *));
+static int get_hw_addr_dlpi __P((char *, struct sockaddr *));
+static int dlpi_attach __P((int, int));
+static int dlpi_info_req __P((int));
+static int dlpi_get_reply __P((int, union DL_primitives *, int, int));
+static int strioctl __P((int, int, void *, int, int));
+
+#ifdef SOL2
+/*
+ * sifppa - Sets interface ppa
+ *
+ * without setting the ppa, ip module will return EINVAL upon setting the
+ * interface UP (SIOCSxIFFLAGS). This is because ip module in 2.8 expects
+ * two DLPI_INFO_REQ to be sent down to the driver (below ip) before
+ * IFF_UP can be set. Plumbing the device causes one DLPI_INFO_REQ to
+ * be sent down, and the second DLPI_INFO_REQ is sent upon receiving
+ * IF_UNITSEL (old) or SIOCSLIFNAME (new) ioctls. Such setting of the ppa
+ * is required because the ppp DLPI provider advertises itself as
+ * a DLPI style 2 type, which requires a point of attachment to be
+ * specified. The only way the user can specify a point of attachment
+ * is via SIOCSLIFNAME or IF_UNITSEL.
+ *
+ * Such changes in the behavior of ip module was made to meet new or
+ * evolving standards requirements.
+ *
+ */
+static int
+sifppa(fd, ppa)
+ int fd;
+ int ppa;
+{
+ return (int)ioctl(fd, IF_UNITSEL, (char *)&ppa);
+}
+#endif /* SOL2 */
+
+#if defined(SOL2) && defined(INET6)
+/*
+ * get_first_ethernet - returns the first Ethernet interface name found in
+ * the system, or NULL if none is found
+ *
+ * NOTE: This is the lifreq version (Solaris 8 and above)
+ */
+char *
+get_first_ethernet()
+{
+ struct lifnum lifn;
+ struct lifconf lifc;
+ struct lifreq *plifreq;
+ struct lifreq lifr;
+ int fd, num_ifs, i, found;
+ uint_t fl, req_size;
+ char *req;
+
+ fd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (fd < 0) {
+ return 0;
+ }
+
+ /*
+ * Find out how many interfaces are running
+ */
+ lifn.lifn_family = AF_UNSPEC;
+ lifn.lifn_flags = LIFC_NOXMIT;
+ if (ioctl(fd, SIOCGLIFNUM, &lifn) < 0) {
+ close(fd);
+ error("could not determine number of interfaces: %m");
+ return 0;
+ }
+
+ num_ifs = lifn.lifn_count;
+ req_size = num_ifs * sizeof(struct lifreq);
+ req = malloc(req_size);
+ if (req == NULL) {
+ close(fd);
+ error("out of memory");
+ return 0;
+ }
+
+ /*
+ * Get interface configuration info for all interfaces
+ */
+ lifc.lifc_family = AF_UNSPEC;
+ lifc.lifc_flags = LIFC_NOXMIT;
+ lifc.lifc_len = req_size;
+ lifc.lifc_buf = req;
+ if (ioctl(fd, SIOCGLIFCONF, &lifc) < 0) {
+ close(fd);
+ free(req);
+ error("SIOCGLIFCONF: %m");
+ return 0;
+ }
+
+ /*
+ * And traverse each interface to look specifically for the first
+ * occurence of an Ethernet interface which has been marked up
+ */
+ plifreq = lifc.lifc_req;
+ found = 0;
+ for (i = lifc.lifc_len / sizeof(struct lifreq); i > 0; i--, plifreq++) {
+
+ if (strchr(plifreq->lifr_name, ':') != NULL)
+ continue;
+
+ memset(&lifr, 0, sizeof(lifr));
+ strncpy(lifr.lifr_name, plifreq->lifr_name, sizeof(lifr.lifr_name));
+ if (ioctl(fd, SIOCGLIFFLAGS, &lifr) < 0) {
+ close(fd);
+ free(req);
+ error("SIOCGLIFFLAGS: %m");
+ return 0;
+ }
+ fl = lifr.lifr_flags;
+
+ if ((fl & (IFF_UP|IFF_BROADCAST|IFF_POINTOPOINT|IFF_LOOPBACK|IFF_NOARP))
+ != (IFF_UP | IFF_BROADCAST))
+ continue;
+
+ found = 1;
+ break;
+ }
+ free(req);
+ close(fd);
+
+ if (found) {
+ strncpy(first_ether_name, lifr.lifr_name, sizeof(first_ether_name));
+ return (char *)first_ether_name;
+ } else
+ return NULL;
+}
+#else
+/*
+ * get_first_ethernet - returns the first Ethernet interface name found in
+ * the system, or NULL if none is found
+ *
+ * NOTE: This is the ifreq version (before Solaris 8).
+ */
+char *
+get_first_ethernet()
+{
+ struct ifconf ifc;
+ struct ifreq *pifreq;
+ struct ifreq ifr;
+ int fd, num_ifs, i, found;
+ uint_t fl, req_size;
+ char *req;
+
+ fd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (fd < 0) {
+ return 0;
+ }
+
+ /*
+ * Find out how many interfaces are running
+ */
+ if (ioctl(fd, SIOCGIFNUM, (char *)&num_ifs) < 0) {
+ num_ifs = MAXIFS;
+ }
+
+ req_size = num_ifs * sizeof(struct ifreq);
+ req = malloc(req_size);
+ if (req == NULL) {
+ close(fd);
+ error("out of memory");
+ return 0;
+ }
+
+ /*
+ * Get interface configuration info for all interfaces
+ */
+ ifc.ifc_len = req_size;
+ ifc.ifc_buf = req;
+ if (ioctl(fd, SIOCGIFCONF, &ifc) < 0) {
+ close(fd);
+ free(req);
+ error("SIOCGIFCONF: %m");
+ return 0;
+ }
+
+ /*
+ * And traverse each interface to look specifically for the first
+ * occurence of an Ethernet interface which has been marked up
+ */
+ pifreq = ifc.ifc_req;
+ found = 0;
+ for (i = ifc.ifc_len / sizeof(struct ifreq); i > 0; i--, pifreq++) {
+
+ if (strchr(pifreq->ifr_name, ':') != NULL)
+ continue;
+
+ memset(&ifr, 0, sizeof(ifr));
+ strncpy(ifr.ifr_name, pifreq->ifr_name, sizeof(ifr.ifr_name));
+ if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) {
+ close(fd);
+ free(req);
+ error("SIOCGIFFLAGS: %m");
+ return 0;
+ }
+ fl = ifr.ifr_flags;
+
+ if ((fl & (IFF_UP|IFF_BROADCAST|IFF_POINTOPOINT|IFF_LOOPBACK|IFF_NOARP))
+ != (IFF_UP | IFF_BROADCAST))
+ continue;
+
+ found = 1;
+ break;
+ }
+ free(req);
+ close(fd);
+
+ if (found) {
+ strncpy(first_ether_name, ifr.ifr_name, sizeof(first_ether_name));
+ return (char *)first_ether_name;
+ } else
+ return NULL;
+}
+#endif /* defined(SOL2) && defined(INET6) */
+
+#if defined(SOL2)
+/*
+ * get_if_hwaddr - get the hardware address for the specified
+ * network interface device.
+ */
+int
+get_if_hwaddr(u_char *addr, char *if_name)
+{
+ struct sockaddr s_eth_addr;
+ struct ether_addr *eth_addr = (struct ether_addr *)&s_eth_addr.sa_data;
+
+ if (if_name == NULL)
+ return -1;
+
+ /*
+ * Send DL_INFO_REQ to the driver to solicit its MAC address
+ */
+ if (!get_hw_addr_dlpi(if_name, &s_eth_addr)) {
+ error("could not obtain hardware address for %s", if_name);
+ return -1;
+ }
+
+ memcpy(addr, eth_addr->ether_addr_octet, 6);
+ return 1;
+}
+#endif /* SOL2 */
+
+#if defined(SOL2) && defined(INET6)
+/*
+ * slifname - Sets interface ppa and flags
+ *
+ * in addition to the comments stated in sifppa(), IFF_IPV6 bit must
+ * be set in order to declare this as an IPv6 interface
+ */
+static int
+slifname(fd, ppa)
+ int fd;
+ int ppa;
+{
+ struct lifreq lifr;
+ int ret;
+
+ memset(&lifr, 0, sizeof(lifr));
+ ret = ioctl(fd, SIOCGLIFFLAGS, &lifr);
+ if (ret < 0)
+ goto slifname_done;
+
+ lifr.lifr_flags |= IFF_IPV6;
+ lifr.lifr_flags &= ~(IFF_BROADCAST | IFF_IPV4);
+ lifr.lifr_ppa = ppa;
+ strlcpy(lifr.lifr_name, ifname, sizeof(lifr.lifr_name));
+
+ ret = ioctl(fd, SIOCSLIFNAME, &lifr);
+
+slifname_done:
+ return ret;
+
+
+}
+
+
+/*
+ * ether_to_eui64 - Convert 48-bit Ethernet address into 64-bit EUI
+ *
+ * walks the list of valid ethernet interfaces, and convert the first
+ * found 48-bit MAC address into EUI 64. caller also assumes that
+ * the system has a properly configured Ethernet interface for this
+ * function to return non-zero.
+ */
+int
+ether_to_eui64(eui64_t *p_eui64)
+{
+ struct sockaddr s_eth_addr;
+ struct ether_addr *eth_addr = (struct ether_addr *)&s_eth_addr.sa_data;
+ char *if_name;
+
+ if ((if_name = get_first_ethernet()) == NULL) {
+ error("no persistent id can be found");
+ return 0;
+ }
+
+ /*
+ * Send DL_INFO_REQ to the driver to solicit its MAC address
+ */
+ if (!get_hw_addr_dlpi(if_name, &s_eth_addr)) {
+ error("could not obtain hardware address for %s", if_name);
+ return 0;
+ }
+
+ /*
+ * And convert the EUI-48 into EUI-64, per RFC 2472 [sec 4.1]
+ */
+ p_eui64->e8[0] = (eth_addr->ether_addr_octet[0] & 0xFF) | 0x02;
+ p_eui64->e8[1] = (eth_addr->ether_addr_octet[1] & 0xFF);
+ p_eui64->e8[2] = (eth_addr->ether_addr_octet[2] & 0xFF);
+ p_eui64->e8[3] = 0xFF;
+ p_eui64->e8[4] = 0xFE;
+ p_eui64->e8[5] = (eth_addr->ether_addr_octet[3] & 0xFF);
+ p_eui64->e8[6] = (eth_addr->ether_addr_octet[4] & 0xFF);
+ p_eui64->e8[7] = (eth_addr->ether_addr_octet[5] & 0xFF);
+
+ return 1;
+}
+#endif /* defined(SOL2) && defined(INET6) */
+
+/*
+ * sys_init - System-dependent initialization.
+ */
+void
+sys_init()
+{
+ int ifd, x;
+ struct ifreq ifr;
+#if defined(INET6) && defined(SOL2)
+ int i6fd;
+ struct lifreq lifr;
+#endif /* defined(INET6) && defined(SOL2) */
+#if !defined(SOL2)
+ struct {
+ union DL_primitives prim;
+ char space[64];
+ } reply;
+#endif /* !defined(SOL2) */
+
+ ipfd = open(mux_dev_name, O_RDWR, 0);
+ if (ipfd < 0)
+ fatal("Couldn't open IP device: %m");
+
+#if defined(INET6) && defined(SOL2)
+ ip6fd = open(UDP6_DEV_NAME, O_RDWR, 0);
+ if (ip6fd < 0)
+ fatal("Couldn't open IP device (2): %m");
+#endif /* defined(INET6) && defined(SOL2) */
+
+ if (default_device && !notty)
+ tty_sid = getsid((pid_t)0);
+
+ pppfd = open(PPP_DEV_NAME, O_RDWR | O_NONBLOCK, 0);
+ if (pppfd < 0)
+ fatal("Can't open %s: %m", PPP_DEV_NAME);
+ if (kdebugflag & 1) {
+ x = PPPDBG_LOG + PPPDBG_DRIVER;
+ strioctl(pppfd, PPPIO_DEBUG, &x, sizeof(int), 0);
+ }
+
+ /* Assign a new PPA and get its unit number. */
+ if (strioctl(pppfd, PPPIO_NEWPPA, &ifunit, 0, sizeof(int)) < 0)
+ fatal("Can't create new PPP interface: %m");
+
+#if defined(SOL2)
+ /*
+ * Since sys_init() is called prior to ifname being set in main(),
+ * we need to get the ifname now, otherwise slifname(), and others,
+ * will fail, or maybe, I should move them to a later point ?
+ * <adi.masputra@sun.com>
+ */
+ sprintf(ifname, PPP_DRV_NAME "%d", ifunit);
+#endif /* defined(SOL2) */
+ /*
+ * Open the ppp device again and link it under the ip multiplexor.
+ * IP will assign a unit number which hopefully is the same as ifunit.
+ * I don't know any way to be certain they will be the same. :-(
+ */
+ ifd = open(PPP_DEV_NAME, O_RDWR, 0);
+ if (ifd < 0)
+ fatal("Can't open %s (2): %m", PPP_DEV_NAME);
+ if (kdebugflag & 1) {
+ x = PPPDBG_LOG + PPPDBG_DRIVER;
+ strioctl(ifd, PPPIO_DEBUG, &x, sizeof(int), 0);
+ }
+
+#if defined(INET6) && defined(SOL2)
+ i6fd = open(PPP_DEV_NAME, O_RDWR, 0);
+ if (i6fd < 0) {
+ close(ifd);
+ fatal("Can't open %s (3): %m", PPP_DEV_NAME);
+ }
+ if (kdebugflag & 1) {
+ x = PPPDBG_LOG + PPPDBG_DRIVER;
+ strioctl(i6fd, PPPIO_DEBUG, &x, sizeof(int), 0);
+ }
+#endif /* defined(INET6) && defined(SOL2) */
+
+#if defined(SOL2)
+ if (ioctl(ifd, I_PUSH, IP_MOD_NAME) < 0) {
+ close(ifd);
+#if defined(INET6)
+ close(i6fd);
+#endif /* defined(INET6) */
+ fatal("Can't push IP module: %m");
+ }
+
+ /*
+ * Assign ppa according to the unit number returned by ppp device
+ * after plumbing is completed above.
+ */
+ if (sifppa(ifd, ifunit) < 0) {
+ close (ifd);
+#if defined(INET6)
+ close(i6fd);
+#endif /* defined(INET6) */
+ fatal("Can't set ppa for unit %d: %m", ifunit);
+ }
+
+#if defined(INET6)
+ /*
+ * An IPv6 interface is created anyway, even when the user does not
+ * explicitly enable it. Note that the interface will be marked
+ * IPv6 during slifname().
+ */
+ if (ioctl(i6fd, I_PUSH, IP_MOD_NAME) < 0) {
+ close(ifd);
+ close(i6fd);
+ fatal("Can't push IP module (2): %m");
+ }
+
+ /*
+ * Assign ppa according to the unit number returned by ppp device
+ * after plumbing is completed above. In addition, mark the interface
+ * as an IPv6 interface.
+ */
+ if (slifname(i6fd, ifunit) < 0) {
+ close(ifd);
+ close(i6fd);
+ fatal("Can't set ifname for unit %d: %m", ifunit);
+ }
+#endif /* defined(INET6) */
+
+ ipmuxid = ioctl(ipfd, I_PLINK, ifd);
+ close(ifd);
+ if (ipmuxid < 0) {
+#if defined(INET6)
+ close(i6fd);
+#endif /* defined(INET6) */
+ fatal("Can't I_PLINK PPP device to IP: %m");
+ }
+
+ memset(&ifr, 0, sizeof(ifr));
+ sprintf(ifr.ifr_name, "%s", ifname);
+ ifr.ifr_ip_muxid = ipmuxid;
+
+ /*
+ * In Sol 8 and later, STREAMS dynamic module plumbing feature exists.
+ * This is so that an arbitrary module can be inserted, or deleted,
+ * between ip module and the device driver without tearing down the
+ * existing stream. Such feature requires the mux ids, which is set
+ * by SIOCSIFMUXID (or SIOCLSIFMUXID).
+ */
+ if (ioctl(ipfd, SIOCSIFMUXID, &ifr) < 0) {
+ ioctl(ipfd, I_PUNLINK, ipmuxid);
+#if defined(INET6)
+ close(i6fd);
+#endif /* defined(INET6) */
+ fatal("SIOCSIFMUXID: %m");
+ }
+
+#else /* else if !defined(SOL2) */
+
+ if (dlpi_attach(ifd, ifunit) < 0 ||
+ dlpi_get_reply(ifd, &reply.prim, DL_OK_ACK, sizeof(reply)) < 0) {
+ close(ifd);
+ fatal("Can't attach to ppp%d: %m", ifunit);
+ }
+
+ ipmuxid = ioctl(ipfd, I_LINK, ifd);
+ close(ifd);
+ if (ipmuxid < 0)
+ fatal("Can't link PPP device to IP: %m");
+#endif /* defined(SOL2) */
+
+#if defined(INET6) && defined(SOL2)
+ ip6muxid = ioctl(ip6fd, I_PLINK, i6fd);
+ close(i6fd);
+ if (ip6muxid < 0) {
+ ioctl(ipfd, I_PUNLINK, ipmuxid);
+ fatal("Can't I_PLINK PPP device to IP (2): %m");
+ }
+
+ memset(&lifr, 0, sizeof(lifr));
+ sprintf(lifr.lifr_name, "%s", ifname);
+ lifr.lifr_ip_muxid = ip6muxid;
+
+ /*
+ * Let IP know of the mux id [see comment for SIOCSIFMUXID above]
+ */
+ if (ioctl(ip6fd, SIOCSLIFMUXID, &lifr) < 0) {
+ ioctl(ipfd, I_PUNLINK, ipmuxid);
+ ioctl(ip6fd, I_PUNLINK, ip6muxid);
+ fatal("Can't link PPP device to IP (2): %m");
+ }
+#endif /* defined(INET6) && defined(SOL2) */
+
+#if !defined(SOL2)
+ /* Set the interface name for the link. */
+ slprintf(ifr.ifr_name, sizeof(ifr.ifr_name), PPP_DRV_NAME "%d", ifunit);
+ ifr.ifr_metric = ipmuxid;
+ if (strioctl(ipfd, SIOCSIFNAME, (char *)&ifr, sizeof ifr, 0) < 0)
+ fatal("Can't set interface name %s: %m", ifr.ifr_name);
+#endif /* !defined(SOL2) */
+
+ n_pollfds = 0;
+}
+
+/*
+ * sys_cleanup - restore any system state we modified before exiting:
+ * mark the interface down, delete default route and/or proxy arp entry.
+ * This should call die() because it's called from die().
+ */
+void
+sys_cleanup()
+{
+#if defined(SOL2)
+ struct ifreq ifr;
+#if defined(INET6)
+ struct lifreq lifr;
+#endif /* defined(INET6) */
+#endif /* defined(SOL2) */
+
+#if defined(SOL2) && defined(INET6)
+ if (if6_is_up)
+ sif6down(0);
+#endif /* defined(SOL2) && defined(INET6) */
+ if (if_is_up)
+ sifdown(0);
+ if (default_route_gateway)
+ cifdefaultroute(0, default_route_gateway, default_route_gateway);
+ if (proxy_arp_addr)
+ cifproxyarp(0, proxy_arp_addr);
+#if defined(SOL2)
+ /*
+ * Make sure we ask ip what the muxid, because 'ifconfig modlist' will
+ * unlink and re-link the modules, causing the muxid to change.
+ */
+ memset(&ifr, 0, sizeof(ifr));
+ sprintf(ifr.ifr_name, "%s", ifname);
+ if (ioctl(ipfd, SIOCGIFFLAGS, &ifr) < 0) {
+ error("SIOCGIFFLAGS: %m");
+ return;
+ }
+
+ if (ioctl(ipfd, SIOCGIFMUXID, &ifr) < 0) {
+ error("SIOCGIFMUXID: %m");
+ return;
+ }
+
+ ipmuxid = ifr.ifr_ip_muxid;
+
+ if (ioctl(ipfd, I_PUNLINK, ipmuxid) < 0) {
+ error("Can't I_PUNLINK PPP from IP: %m");
+ return;
+ }
+#if defined(INET6)
+ /*
+ * Make sure we ask ip what the muxid, because 'ifconfig modlist' will
+ * unlink and re-link the modules, causing the muxid to change.
+ */
+ memset(&lifr, 0, sizeof(lifr));
+ sprintf(lifr.lifr_name, "%s", ifname);
+ if (ioctl(ip6fd, SIOCGLIFFLAGS, &lifr) < 0) {
+ error("SIOCGLIFFLAGS: %m");
+ return;
+ }
+
+ if (ioctl(ip6fd, SIOCGLIFMUXID, &lifr) < 0) {
+ error("SIOCGLIFMUXID: %m");
+ return;
+ }
+
+ ip6muxid = lifr.lifr_ip_muxid;
+
+ if (ioctl(ip6fd, I_PUNLINK, ip6muxid) < 0) {
+ error("Can't I_PUNLINK PPP from IP (2): %m");
+ }
+#endif /* defined(INET6) */
+#endif /* defined(SOL2) */
+}
+
+/*
+ * sys_close - Clean up in a child process before execing.
+ */
+void
+sys_close()
+{
+ close(ipfd);
+#if defined(INET6) && defined(SOL2)
+ close(ip6fd);
+#endif /* defined(INET6) && defined(SOL2) */
+ if (pppfd >= 0)
+ close(pppfd);
+}
+
+/*
+ * sys_check_options - check the options that the user specified
+ */
+int
+sys_check_options()
+{
+ return 1;
+}
+
+#if 0
+/*
+ * daemon - Detach us from controlling terminal session.
+ */
+int
+daemon(nochdir, noclose)
+ int nochdir, noclose;
+{
+ int pid;
+
+ if ((pid = fork()) < 0)
+ return -1;
+ if (pid != 0)
+ exit(0); /* parent dies */
+ setsid();
+ if (!nochdir)
+ chdir("/");
+ if (!noclose) {
+ fclose(stdin); /* don't need stdin, stdout, stderr */
+ fclose(stdout);
+ fclose(stderr);
+ }
+ return 0;
+}
+#endif
+
+/*
+ * ppp_available - check whether the system has any ppp interfaces
+ */
+int
+ppp_available()
+{
+ struct stat buf;
+
+ return stat(PPP_DEV_NAME, &buf) >= 0;
+}
+
+/*
+ * any_compressions - see if compression is enabled or not
+ *
+ * In the STREAMS implementation of kernel-portion pppd,
+ * the comp STREAMS module performs the ACFC, PFC, as well
+ * CCP and VJ compressions. However, if the user has explicitly
+ * declare to not enable them from the command line, there is
+ * no point of having the comp module be pushed on the stream.
+ */
+static int
+any_compressions()
+{
+ if ((!lcp_wantoptions[0].neg_accompression) &&
+ (!lcp_wantoptions[0].neg_pcompression) &&
+ (!ccp_protent.enabled_flag) &&
+ (!ipcp_wantoptions[0].neg_vj)) {
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * tty_establish_ppp - Turn the serial port into a ppp interface.
+ */
+int
+tty_establish_ppp(fd)
+ int fd;
+{
+ int i;
+
+ /* Pop any existing modules off the tty stream. */
+ for (i = 0;; ++i)
+ if (ioctl(fd, I_LOOK, tty_modules[i]) < 0
+ || strcmp(tty_modules[i], "ptem") == 0
+ || ioctl(fd, I_POP, 0) < 0)
+ break;
+ tty_nmodules = i;
+
+ /* Push the async hdlc module and the compressor module. */
+ tty_npushed = 0;
+
+ if(!sync_serial) {
+ if (ioctl(fd, I_PUSH, AHDLC_MOD_NAME) < 0) {
+ error("Couldn't push PPP Async HDLC module: %m");
+ return -1;
+ }
+ ++tty_npushed;
+ }
+ if (kdebugflag & 4) {
+ i = PPPDBG_LOG + PPPDBG_AHDLC;
+ strioctl(pppfd, PPPIO_DEBUG, &i, sizeof(int), 0);
+ }
+ /*
+ * There's no need to push comp module if we don't intend
+ * to compress anything
+ */
+ if (any_compressions()) {
+ if (ioctl(fd, I_PUSH, COMP_MOD_NAME) < 0)
+ error("Couldn't push PPP compression module: %m");
+ else
+ ++tty_npushed;
+ }
+
+ if (kdebugflag & 2) {
+ i = PPPDBG_LOG;
+ if (any_compressions())
+ i += PPPDBG_COMP;
+ strioctl(pppfd, PPPIO_DEBUG, &i, sizeof(int), 0);
+ }
+
+ /* Link the serial port under the PPP multiplexor. */
+ if ((fdmuxid = ioctl(pppfd, I_LINK, fd)) < 0) {
+ error("Can't link tty to PPP mux: %m");
+ return -1;
+ }
+
+ return pppfd;
+}
+
+/*
+ * tty_disestablish_ppp - Restore the serial port to normal operation.
+ * It attempts to reconstruct the stream with the previously popped
+ * modules. This shouldn't call die() because it's called from die().
+ */
+void
+tty_disestablish_ppp(fd)
+ int fd;
+{
+ int i;
+
+ if (fdmuxid >= 0) {
+ if (ioctl(pppfd, I_UNLINK, fdmuxid) < 0) {
+ if (!hungup)
+ error("Can't unlink tty from PPP mux: %m");
+ }
+ fdmuxid = -1;
+
+ if (!hungup) {
+ while (tty_npushed > 0 && ioctl(fd, I_POP, 0) >= 0)
+ --tty_npushed;
+ for (i = tty_nmodules - 1; i >= 0; --i)
+ if (ioctl(fd, I_PUSH, tty_modules[i]) < 0)
+ error("Couldn't restore tty module %s: %m",
+ tty_modules[i]);
+ }
+ if (hungup && default_device && tty_sid > 0) {
+ /*
+ * If we have received a hangup, we need to send a SIGHUP
+ * to the terminal's controlling process. The reason is
+ * that the original stream head for the terminal hasn't
+ * seen the M_HANGUP message (it went up through the ppp
+ * driver to the stream head for our fd to /dev/ppp).
+ */
+ kill(tty_sid, SIGHUP);
+ }
+ }
+}
+
+/*
+ * Check whether the link seems not to be 8-bit clean.
+ */
+void
+clean_check()
+{
+ int x;
+ char *s;
+
+ if (strioctl(pppfd, PPPIO_GCLEAN, &x, 0, sizeof(x)) < 0)
+ return;
+ s = NULL;
+ switch (~x) {
+ case RCV_B7_0:
+ s = "bit 7 set to 1";
+ break;
+ case RCV_B7_1:
+ s = "bit 7 set to 0";
+ break;
+ case RCV_EVNP:
+ s = "odd parity";
+ break;
+ case RCV_ODDP:
+ s = "even parity";
+ break;
+ }
+ if (s != NULL) {
+ warn("Serial link is not 8-bit clean:");
+ warn("All received characters had %s", s);
+ }
+}
+
+/*
+ * List of valid speeds.
+ */
+struct speed {
+ int speed_int, speed_val;
+} speeds[] = {
+#ifdef B50
+ { 50, B50 },
+#endif
+#ifdef B75
+ { 75, B75 },
+#endif
+#ifdef B110
+ { 110, B110 },
+#endif
+#ifdef B134
+ { 134, B134 },
+#endif
+#ifdef B150
+ { 150, B150 },
+#endif
+#ifdef B200
+ { 200, B200 },
+#endif
+#ifdef B300
+ { 300, B300 },
+#endif
+#ifdef B600
+ { 600, B600 },
+#endif
+#ifdef B1200
+ { 1200, B1200 },
+#endif
+#ifdef B1800
+ { 1800, B1800 },
+#endif
+#ifdef B2000
+ { 2000, B2000 },
+#endif
+#ifdef B2400
+ { 2400, B2400 },
+#endif
+#ifdef B3600
+ { 3600, B3600 },
+#endif
+#ifdef B4800
+ { 4800, B4800 },
+#endif
+#ifdef B7200
+ { 7200, B7200 },
+#endif
+#ifdef B9600
+ { 9600, B9600 },
+#endif
+#ifdef B19200
+ { 19200, B19200 },
+#endif
+#ifdef B38400
+ { 38400, B38400 },
+#endif
+#ifdef EXTA
+ { 19200, EXTA },
+#endif
+#ifdef EXTB
+ { 38400, EXTB },
+#endif
+#ifdef B57600
+ { 57600, B57600 },
+#endif
+#ifdef B76800
+ { 76800, B76800 },
+#endif
+#ifdef B115200
+ { 115200, B115200 },
+#endif
+#ifdef B153600
+ { 153600, B153600 },
+#endif
+#ifdef B230400
+ { 230400, B230400 },
+#endif
+#ifdef B307200
+ { 307200, B307200 },
+#endif
+#ifdef B460800
+ { 460800, B460800 },
+#endif
+ { 0, 0 }
+};
+
+/*
+ * Translate from bits/second to a speed_t.
+ */
+static int
+translate_speed(bps)
+ int bps;
+{
+ struct speed *speedp;
+
+ if (bps == 0)
+ return 0;
+ for (speedp = speeds; speedp->speed_int; speedp++)
+ if (bps == speedp->speed_int)
+ return speedp->speed_val;
+ warn("speed %d not supported", bps);
+ return 0;
+}
+
+/*
+ * Translate from a speed_t to bits/second.
+ */
+static int
+baud_rate_of(speed)
+ int speed;
+{
+ struct speed *speedp;
+
+ if (speed == 0)
+ return 0;
+ for (speedp = speeds; speedp->speed_int; speedp++)
+ if (speed == speedp->speed_val)
+ return speedp->speed_int;
+ return 0;
+}
+
+/*
+ * set_up_tty: Set up the serial port on `fd' for 8 bits, no parity,
+ * at the requested speed, etc. If `local' is true, set CLOCAL
+ * regardless of whether the modem option was specified.
+ */
+void
+set_up_tty(fd, local)
+ int fd, local;
+{
+ int speed;
+ struct termios tios;
+#if !defined (CRTSCTS)
+ struct termiox tiox;
+#endif
+
+ if (!sync_serial && tcgetattr(fd, &tios) < 0)
+ fatal("tcgetattr: %m");
+
+#ifndef CRTSCTS
+ termiox_ok = 1;
+ if (!sync_serial && ioctl (fd, TCGETX, &tiox) < 0) {
+ termiox_ok = 0;
+ if (errno != ENOTTY)
+ error("TCGETX: %m");
+ }
+#endif
+
+ if (!restore_term) {
+ inittermios = tios;
+#ifndef CRTSCTS
+ inittermiox = tiox;
+#endif
+ if (!sync_serial)
+ ioctl(fd, TIOCGWINSZ, &wsinfo);
+ }
+
+ tios.c_cflag &= ~(CSIZE | CSTOPB | PARENB | CLOCAL);
+#ifdef CRTSCTS
+ if (crtscts > 0)
+ tios.c_cflag |= CRTSCTS;
+ else if (crtscts < 0)
+ tios.c_cflag &= ~CRTSCTS;
+#else
+ if (crtscts != 0 && !termiox_ok) {
+ error("Can't set RTS/CTS flow control");
+ } else if (crtscts > 0) {
+ tiox.x_hflag |= RTSXOFF|CTSXON;
+ } else if (crtscts < 0) {
+ tiox.x_hflag &= ~(RTSXOFF|CTSXON);
+ }
+#endif
+
+ tios.c_cflag |= CS8 | CREAD | HUPCL;
+ if (local || !modem)
+ tios.c_cflag |= CLOCAL;
+ tios.c_iflag = IGNBRK | IGNPAR;
+ tios.c_oflag = 0;
+ tios.c_lflag = 0;
+ tios.c_cc[VMIN] = 1;
+ tios.c_cc[VTIME] = 0;
+
+ if (crtscts == -2) {
+ tios.c_iflag |= IXON | IXOFF;
+ tios.c_cc[VSTOP] = 0x13; /* DC3 = XOFF = ^S */
+ tios.c_cc[VSTART] = 0x11; /* DC1 = XON = ^Q */
+ }
+
+ speed = translate_speed(inspeed);
+ if (speed) {
+ cfsetospeed(&tios, speed);
+ cfsetispeed(&tios, speed);
+ } else {
+ speed = cfgetospeed(&tios);
+ /*
+ * We can't proceed if the serial port speed is 0,
+ * since that implies that the serial port is disabled.
+ */
+ if ((speed == B0) && !sync_serial)
+ fatal("Baud rate for %s is 0; need explicit baud rate", devnam);
+ }
+
+ if (!sync_serial && tcsetattr(fd, TCSAFLUSH, &tios) < 0)
+ fatal("tcsetattr: %m");
+
+#ifndef CRTSCTS
+ if (!sync_serial && termiox_ok && ioctl (fd, TCSETXF, &tiox) < 0){
+ error("TCSETXF: %m");
+ }
+#endif
+
+ baud_rate = inspeed = baud_rate_of(speed);
+ if (!sync_serial)
+ restore_term = 1;
+}
+
+/*
+ * restore_tty - restore the terminal to the saved settings.
+ */
+void
+restore_tty(fd)
+ int fd;
+{
+ if (restore_term) {
+ if (!default_device) {
+ /*
+ * Turn off echoing, because otherwise we can get into
+ * a loop with the tty and the modem echoing to each other.
+ * We presume we are the sole user of this tty device, so
+ * when we close it, it will revert to its defaults anyway.
+ */
+ inittermios.c_lflag &= ~(ECHO | ECHONL);
+ }
+ if (!sync_serial && tcsetattr(fd, TCSAFLUSH, &inittermios) < 0)
+ if (!hungup && errno != ENXIO)
+ warn("tcsetattr: %m");
+#ifndef CRTSCTS
+ if (!sync_serial && ioctl (fd, TCSETXF, &inittermiox) < 0){
+ if (!hungup && errno != ENXIO)
+ error("TCSETXF: %m");
+ }
+#endif
+ if (!sync_serial)
+ ioctl(fd, TIOCSWINSZ, &wsinfo);
+ restore_term = 0;
+ }
+}
+
+/*
+ * setdtr - control the DTR line on the serial port.
+ * This is called from die(), so it shouldn't call die().
+ */
+void
+setdtr(fd, on)
+int fd, on;
+{
+ int modembits = TIOCM_DTR;
+
+ ioctl(fd, (on? TIOCMBIS: TIOCMBIC), &modembits);
+}
+
+/*
+ * open_loopback - open the device we use for getting packets
+ * in demand mode. Under Solaris 2, we use our existing fd
+ * to the ppp driver.
+ */
+int
+open_ppp_loopback()
+{
+ return pppfd;
+}
+
+/*
+ * output - Output PPP packet.
+ */
+void
+output(unit, p, len)
+ int unit;
+ u_char *p;
+ int len;
+{
+ struct strbuf data;
+ int retries;
+ struct pollfd pfd;
+
+ if (debug)
+ dbglog("sent %P", p, len);
+
+ data.len = len;
+ data.buf = (caddr_t) p;
+ retries = 4;
+ while (putmsg(pppfd, NULL, &data, 0) < 0) {
+ if (--retries < 0 || (errno != EWOULDBLOCK && errno != EAGAIN)) {
+ if (errno != ENXIO)
+ error("Couldn't send packet: %m");
+ break;
+ }
+ pfd.fd = pppfd;
+ pfd.events = POLLOUT;
+ poll(&pfd, 1, 250); /* wait for up to 0.25 seconds */
+ }
+}
+
+
+/*
+ * wait_input - wait until there is data available,
+ * for the length of time specified by *timo (indefinite
+ * if timo is NULL).
+ */
+void
+wait_input(timo)
+ struct timeval *timo;
+{
+ int t;
+
+ t = timo == NULL? -1: timo->tv_sec * 1000 + timo->tv_usec / 1000;
+ if (poll(pollfds, n_pollfds, t) < 0 && errno != EINTR)
+ fatal("poll: %m");
+}
+
+/*
+ * add_fd - add an fd to the set that wait_input waits for.
+ */
+void add_fd(fd)
+ int fd;
+{
+ int n;
+
+ for (n = 0; n < n_pollfds; ++n)
+ if (pollfds[n].fd == fd)
+ return;
+ if (n_pollfds < MAX_POLLFDS) {
+ pollfds[n_pollfds].fd = fd;
+ pollfds[n_pollfds].events = POLLIN | POLLPRI | POLLHUP;
+ ++n_pollfds;
+ } else
+ error("Too many inputs!");
+}
+
+/*
+ * remove_fd - remove an fd from the set that wait_input waits for.
+ */
+void remove_fd(fd)
+ int fd;
+{
+ int n;
+
+ for (n = 0; n < n_pollfds; ++n) {
+ if (pollfds[n].fd == fd) {
+ while (++n < n_pollfds)
+ pollfds[n-1] = pollfds[n];
+ --n_pollfds;
+ break;
+ }
+ }
+}
+
+#if 0
+/*
+ * wait_loop_output - wait until there is data available on the
+ * loopback, for the length of time specified by *timo (indefinite
+ * if timo is NULL).
+ */
+void
+wait_loop_output(timo)
+ struct timeval *timo;
+{
+ wait_input(timo);
+}
+
+/*
+ * wait_time - wait for a given length of time or until a
+ * signal is received.
+ */
+void
+wait_time(timo)
+ struct timeval *timo;
+{
+ int n;
+
+ n = select(0, NULL, NULL, NULL, timo);
+ if (n < 0 && errno != EINTR)
+ fatal("select: %m");
+}
+#endif
+
+
+/*
+ * read_packet - get a PPP packet from the serial device.
+ */
+int
+read_packet(buf)
+ u_char *buf;
+{
+ struct strbuf ctrl, data;
+ int flags, len;
+ unsigned char ctrlbuf[sizeof(union DL_primitives) + 64];
+
+ for (;;) {
+ data.maxlen = PPP_MRU + PPP_HDRLEN;
+ data.buf = (caddr_t) buf;
+ ctrl.maxlen = sizeof(ctrlbuf);
+ ctrl.buf = (caddr_t) ctrlbuf;
+ flags = 0;
+ len = getmsg(pppfd, &ctrl, &data, &flags);
+ if (len < 0) {
+ if (errno == EAGAIN || errno == EINTR)
+ return -1;
+ fatal("Error reading packet: %m");
+ }
+
+ if (ctrl.len <= 0)
+ return data.len;
+
+ /*
+ * Got a M_PROTO or M_PCPROTO message. Interpret it
+ * as a DLPI primitive??
+ */
+ if (debug)
+ dbglog("got dlpi prim 0x%x, len=%d",
+ ((union DL_primitives *)ctrlbuf)->dl_primitive, ctrl.len);
+
+ }
+}
+
+/*
+ * get_loop_output - get outgoing packets from the ppp device,
+ * and detect when we want to bring the real link up.
+ * Return value is 1 if we need to bring up the link, 0 otherwise.
+ */
+int
+get_loop_output()
+{
+ int len;
+ int rv = 0;
+
+ while ((len = read_packet(inpacket_buf)) > 0) {
+ if (loop_frame(inpacket_buf, len))
+ rv = 1;
+ }
+ return rv;
+}
+
+/*
+ * netif_set_mtu - set the MTU on the PPP network interface.
+ */
+void
+netif_set_mtu(unit, mtu)
+ int unit, mtu;
+{
+ struct ifreq ifr;
+#if defined(INET6) && defined(SOL2)
+ struct lifreq lifr;
+ int fd;
+#endif /* defined(INET6) && defined(SOL2) */
+
+ memset(&ifr, 0, sizeof(ifr));
+ strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+ ifr.ifr_metric = link_mtu;
+ if (ioctl(ipfd, SIOCSIFMTU, &ifr) < 0) {
+ error("Couldn't set IP MTU (%s): %m", ifr.ifr_name);
+ }
+
+#if defined(INET6) && defined(SOL2)
+ fd = socket(AF_INET6, SOCK_DGRAM, 0);
+ if (fd < 0)
+ error("Couldn't open IPv6 socket: %m");
+
+ memset(&lifr, 0, sizeof(lifr));
+ strlcpy(lifr.lifr_name, ifname, sizeof(lifr.lifr_name));
+ lifr.lifr_mtu = link_mtu;
+ if (ioctl(fd, SIOCSLIFMTU, &lifr) < 0) {
+ close(fd);
+ error("Couldn't set IPv6 MTU (%s): %m", ifr.ifr_name);
+ }
+ close(fd);
+#endif /* defined(INET6) && defined(SOL2) */
+}
+
+/*
+ * tty_send_config - configure the transmit characteristics of
+ * the ppp interface.
+ */
+void
+tty_send_config(mtu, asyncmap, pcomp, accomp)
+ int mtu;
+ u_int32_t asyncmap;
+ int pcomp, accomp;
+{
+ int cf[2];
+
+ link_mtu = mtu;
+ if (strioctl(pppfd, PPPIO_MTU, &mtu, sizeof(mtu), 0) < 0) {
+ if (hungup && errno == ENXIO)
+ return;
+ error("Couldn't set MTU: %m");
+ }
+ if (fdmuxid >= 0) {
+ if (!sync_serial) {
+ if (strioctl(pppfd, PPPIO_XACCM, &asyncmap, sizeof(asyncmap), 0) < 0) {
+ error("Couldn't set transmit ACCM: %m");
+ }
+ }
+ cf[0] = (pcomp? COMP_PROT: 0) + (accomp? COMP_AC: 0);
+ cf[1] = COMP_PROT | COMP_AC;
+ if (any_compressions() &&
+ strioctl(pppfd, PPPIO_CFLAGS, cf, sizeof(cf), sizeof(int)) < 0) {
+ error("Couldn't set prot/AC compression: %m");
+ }
+ }
+}
+
+/*
+ * ppp_set_xaccm - set the extended transmit ACCM for the interface.
+ */
+void
+tty_set_xaccm(accm)
+ ext_accm accm;
+{
+ if (sync_serial)
+ return;
+
+ if (fdmuxid >= 0
+ && strioctl(pppfd, PPPIO_XACCM, accm, sizeof(ext_accm), 0) < 0) {
+ if (!hungup || errno != ENXIO)
+ warn("Couldn't set extended ACCM: %m");
+ }
+}
+
+/*
+ * ppp_recv_config - configure the receive-side characteristics of
+ * the ppp interface.
+ */
+void
+tty_recv_config(mru, asyncmap, pcomp, accomp)
+ int mru;
+ u_int32_t asyncmap;
+ int pcomp, accomp;
+{
+ int cf[2];
+
+ link_mru = mru;
+ if (strioctl(pppfd, PPPIO_MRU, &mru, sizeof(mru), 0) < 0) {
+ if (hungup && errno == ENXIO)
+ return;
+ error("Couldn't set MRU: %m");
+ }
+ if (fdmuxid >= 0) {
+ if (!sync_serial) {
+ if (strioctl(pppfd, PPPIO_RACCM, &asyncmap, sizeof(asyncmap), 0) < 0) {
+ error("Couldn't set receive ACCM: %m");
+ }
+ }
+ cf[0] = (pcomp? DECOMP_PROT: 0) + (accomp? DECOMP_AC: 0);
+ cf[1] = DECOMP_PROT | DECOMP_AC;
+ if (any_compressions() &&
+ strioctl(pppfd, PPPIO_CFLAGS, cf, sizeof(cf), sizeof(int)) < 0) {
+ error("Couldn't set prot/AC decompression: %m");
+ }
+ }
+}
+
+/*
+ * ccp_test - ask kernel whether a given compression method
+ * is acceptable for use.
+ */
+int
+ccp_test(unit, opt_ptr, opt_len, for_transmit)
+ int unit, opt_len, for_transmit;
+ u_char *opt_ptr;
+{
+ if (strioctl(pppfd, (for_transmit? PPPIO_XCOMP: PPPIO_RCOMP),
+ opt_ptr, opt_len, 0) >= 0)
+ return 1;
+ return (errno == ENOSR)? 0: -1;
+}
+
+/*
+ * ccp_flags_set - inform kernel about the current state of CCP.
+ */
+void
+ccp_flags_set(unit, isopen, isup)
+ int unit, isopen, isup;
+{
+ int cf[2];
+
+ cf[0] = (isopen? CCP_ISOPEN: 0) + (isup? CCP_ISUP: 0);
+ cf[1] = CCP_ISOPEN | CCP_ISUP | CCP_ERROR | CCP_FATALERROR;
+ if (strioctl(pppfd, PPPIO_CFLAGS, cf, sizeof(cf), sizeof(int)) < 0) {
+ if (!hungup || errno != ENXIO)
+ error("Couldn't set kernel CCP state: %m");
+ }
+}
+
+/*
+ * get_idle_time - return how long the link has been idle.
+ */
+int
+get_idle_time(u, ip)
+ int u;
+ struct ppp_idle *ip;
+{
+ return strioctl(pppfd, PPPIO_GIDLE, ip, 0, sizeof(struct ppp_idle)) >= 0;
+}
+
+/*
+ * get_ppp_stats - return statistics for the link.
+ */
+int
+get_ppp_stats(u, stats)
+ int u;
+ struct pppd_stats *stats;
+{
+ struct ppp_stats s;
+
+ if (!sync_serial &&
+ strioctl(pppfd, PPPIO_GETSTAT, &s, 0, sizeof(s)) < 0) {
+ error("Couldn't get link statistics: %m");
+ return 0;
+ }
+ stats->bytes_in = s.p.ppp_ibytes;
+ stats->bytes_out = s.p.ppp_obytes;
+ return 1;
+}
+
+#if 0
+/*
+ * set_filters - transfer the pass and active filters to the kernel.
+ */
+int
+set_filters(pass, active)
+ struct bpf_program *pass, *active;
+{
+ int ret = 1;
+
+ if (pass->bf_len > 0) {
+ if (strioctl(pppfd, PPPIO_PASSFILT, pass,
+ sizeof(struct bpf_program), 0) < 0) {
+ error("Couldn't set pass-filter in kernel: %m");
+ ret = 0;
+ }
+ }
+ if (active->bf_len > 0) {
+ if (strioctl(pppfd, PPPIO_ACTIVEFILT, active,
+ sizeof(struct bpf_program), 0) < 0) {
+ error("Couldn't set active-filter in kernel: %m");
+ ret = 0;
+ }
+ }
+ return ret;
+}
+#endif
+
+/*
+ * ccp_fatal_error - returns 1 if decompression was disabled as a
+ * result of an error detected after decompression of a packet,
+ * 0 otherwise. This is necessary because of patent nonsense.
+ */
+int
+ccp_fatal_error(unit)
+ int unit;
+{
+ int cf[2];
+
+ cf[0] = cf[1] = 0;
+ if (strioctl(pppfd, PPPIO_CFLAGS, cf, sizeof(cf), sizeof(int)) < 0) {
+ if (errno != ENXIO && errno != EINVAL)
+ error("Couldn't get compression flags: %m");
+ return 0;
+ }
+ return cf[0] & CCP_FATALERROR;
+}
+
+/*
+ * sifvjcomp - config tcp header compression
+ */
+int
+sifvjcomp(u, vjcomp, xcidcomp, xmaxcid)
+ int u, vjcomp, xcidcomp, xmaxcid;
+{
+ int cf[2];
+ char maxcid[2];
+
+ if (vjcomp) {
+ maxcid[0] = xcidcomp;
+ maxcid[1] = 15; /* XXX should be rmaxcid */
+ if (strioctl(pppfd, PPPIO_VJINIT, maxcid, sizeof(maxcid), 0) < 0) {
+ error("Couldn't initialize VJ compression: %m");
+ }
+ }
+
+ cf[0] = (vjcomp? COMP_VJC + DECOMP_VJC: 0) /* XXX this is wrong */
+ + (xcidcomp? COMP_VJCCID + DECOMP_VJCCID: 0);
+ cf[1] = COMP_VJC + DECOMP_VJC + COMP_VJCCID + DECOMP_VJCCID;
+ if (strioctl(pppfd, PPPIO_CFLAGS, cf, sizeof(cf), sizeof(int)) < 0) {
+ if (vjcomp)
+ error("Couldn't enable VJ compression: %m");
+ }
+
+ return 1;
+}
+
+/*
+ * sifup - Config the interface up and enable IP packets to pass.
+ */
+int
+sifup(u)
+ int u;
+{
+ struct ifreq ifr;
+
+ strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+ if (ioctl(ipfd, SIOCGIFFLAGS, &ifr) < 0) {
+ error("Couldn't mark interface up (get): %m");
+ return 0;
+ }
+ ifr.ifr_flags |= IFF_UP;
+ if (ioctl(ipfd, SIOCSIFFLAGS, &ifr) < 0) {
+ error("Couldn't mark interface up (set): %m");
+ return 0;
+ }
+ if_is_up = 1;
+ return 1;
+}
+
+/*
+ * sifdown - Config the interface down and disable IP.
+ */
+int
+sifdown(u)
+ int u;
+{
+ struct ifreq ifr;
+
+ if (ipmuxid < 0)
+ return 1;
+ strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+ if (ioctl(ipfd, SIOCGIFFLAGS, &ifr) < 0) {
+ error("Couldn't mark interface down (get): %m");
+ return 0;
+ }
+ ifr.ifr_flags &= ~IFF_UP;
+ if (ioctl(ipfd, SIOCSIFFLAGS, &ifr) < 0) {
+ error("Couldn't mark interface down (set): %m");
+ return 0;
+ }
+ if_is_up = 0;
+ return 1;
+}
+
+/*
+ * sifnpmode - Set the mode for handling packets for a given NP.
+ */
+int
+sifnpmode(u, proto, mode)
+ int u;
+ int proto;
+ enum NPmode mode;
+{
+ int npi[2];
+
+ npi[0] = proto;
+ npi[1] = (int) mode;
+ if (strioctl(pppfd, PPPIO_NPMODE, &npi, 2 * sizeof(int), 0) < 0) {
+ error("ioctl(set NP %d mode to %d): %m", proto, mode);
+ return 0;
+ }
+ return 1;
+}
+
+#if defined(SOL2) && defined(INET6)
+/*
+ * sif6up - Config the IPv6 interface up and enable IPv6 packets to pass.
+ */
+int
+sif6up(u)
+ int u;
+{
+ struct lifreq lifr;
+ int fd;
+
+ fd = socket(AF_INET6, SOCK_DGRAM, 0);
+ if (fd < 0) {
+ return 0;
+ }
+
+ memset(&lifr, 0, sizeof(lifr));
+ strlcpy(lifr.lifr_name, ifname, sizeof(lifr.lifr_name));
+ if (ioctl(fd, SIOCGLIFFLAGS, &lifr) < 0) {
+ close(fd);
+ return 0;
+ }
+
+ lifr.lifr_flags |= IFF_UP;
+ strlcpy(lifr.lifr_name, ifname, sizeof(lifr.lifr_name));
+ if (ioctl(fd, SIOCSLIFFLAGS, &lifr) < 0) {
+ close(fd);
+ return 0;
+ }
+
+ if6_is_up = 1;
+ close(fd);
+ return 1;
+}
+
+/*
+ * sifdown - Config the IPv6 interface down and disable IPv6.
+ */
+int
+sif6down(u)
+ int u;
+{
+ struct lifreq lifr;
+ int fd;
+
+ fd = socket(AF_INET6, SOCK_DGRAM, 0);
+ if (fd < 0)
+ return 0;
+
+ memset(&lifr, 0, sizeof(lifr));
+ strlcpy(lifr.lifr_name, ifname, sizeof(lifr.lifr_name));
+ if (ioctl(fd, SIOCGLIFFLAGS, &lifr) < 0) {
+ close(fd);
+ return 0;
+ }
+
+ lifr.lifr_flags &= ~IFF_UP;
+ strlcpy(lifr.lifr_name, ifname, sizeof(lifr.lifr_name));
+ if (ioctl(fd, SIOCGLIFFLAGS, &lifr) < 0) {
+ close(fd);
+ return 0;
+ }
+
+ if6_is_up = 0;
+ close(fd);
+ return 1;
+}
+
+/*
+ * sif6addr - Config the interface with an IPv6 link-local address
+ */
+int
+sif6addr(u, o, h)
+ int u;
+ eui64_t o, h;
+{
+ struct lifreq lifr;
+ struct sockaddr_storage laddr;
+ struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&laddr;
+ int fd;
+
+ fd = socket(AF_INET6, SOCK_DGRAM, 0);
+ if (fd < 0)
+ return 0;
+
+ memset(&lifr, 0, sizeof(lifr));
+ strlcpy(lifr.lifr_name, ifname, sizeof(lifr.lifr_name));
+
+ /*
+ * Do this because /dev/ppp responds to DL_PHYS_ADDR_REQ with
+ * zero values, hence the interface token came to be zero too,
+ * and without this, in.ndpd will complain
+ */
+ IN6_LLTOKEN_FROM_EUI64(lifr, sin6, o);
+ if (ioctl(fd, SIOCSLIFTOKEN, &lifr) < 0) {
+ close(fd);
+ return 0;
+ }
+
+ /*
+ * Set the interface address and destination address
+ */
+ IN6_LLADDR_FROM_EUI64(lifr, sin6, o);
+ if (ioctl(fd, SIOCSLIFADDR, &lifr) < 0) {
+ close(fd);
+ return 0;
+ }
+
+ memset(&lifr, 0, sizeof(lifr));
+ strlcpy(lifr.lifr_name, ifname, sizeof(lifr.lifr_name));
+ IN6_LLADDR_FROM_EUI64(lifr, sin6, h);
+ if (ioctl(fd, SIOCSLIFDSTADDR, &lifr) < 0) {
+ close(fd);
+ return 0;
+ }
+
+ return 1;
+}
+
+/*
+ * cif6addr - Remove the IPv6 address from interface
+ */
+int
+cif6addr(u, o, h)
+ int u;
+ eui64_t o, h;
+{
+ return 1;
+}
+
+#endif /* defined(SOL2) && defined(INET6) */
+
+
+#define INET_ADDR(x) (((struct sockaddr_in *) &(x))->sin_addr.s_addr)
+
+/*
+ * sifaddr - Config the interface IP addresses and netmask.
+ */
+int
+sifaddr(u, o, h, m)
+ int u;
+ u_int32_t o, h, m;
+{
+ struct ifreq ifr;
+ int ret = 1;
+
+ memset(&ifr, 0, sizeof(ifr));
+ strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+ ifr.ifr_addr.sa_family = AF_INET;
+ INET_ADDR(ifr.ifr_addr) = m;
+ if (ioctl(ipfd, SIOCSIFNETMASK, &ifr) < 0) {
+ error("Couldn't set IP netmask: %m");
+ ret = 0;
+ }
+ ifr.ifr_addr.sa_family = AF_INET;
+ INET_ADDR(ifr.ifr_addr) = o;
+ if (ioctl(ipfd, SIOCSIFADDR, &ifr) < 0) {
+ error("Couldn't set local IP address: %m");
+ ret = 0;
+ }
+
+ /*
+ * On some systems, we have to explicitly set the point-to-point
+ * flag bit before we can set a destination address.
+ */
+ if (ioctl(ipfd, SIOCGIFFLAGS, &ifr) >= 0
+ && (ifr.ifr_flags & IFF_POINTOPOINT) == 0) {
+ ifr.ifr_flags |= IFF_POINTOPOINT;
+ if (ioctl(ipfd, SIOCSIFFLAGS, &ifr) < 0) {
+ error("Couldn't mark interface pt-to-pt: %m");
+ ret = 0;
+ }
+ }
+ ifr.ifr_dstaddr.sa_family = AF_INET;
+ INET_ADDR(ifr.ifr_dstaddr) = h;
+ if (ioctl(ipfd, SIOCSIFDSTADDR, &ifr) < 0) {
+ error("Couldn't set remote IP address: %m");
+ ret = 0;
+ }
+#if 0 /* now done in ppp_send_config */
+ ifr.ifr_metric = link_mtu;
+ if (ioctl(ipfd, SIOCSIFMTU, &ifr) < 0) {
+ error("Couldn't set IP MTU: %m");
+ }
+#endif
+
+ remote_addr = h;
+ return ret;
+}
+
+/*
+ * cifaddr - Clear the interface IP addresses, and delete routes
+ * through the interface if possible.
+ */
+int
+cifaddr(u, o, h)
+ int u;
+ u_int32_t o, h;
+{
+#if defined(__USLC__) /* was: #if 0 */
+ cifroute(unit, ouraddr, hisaddr);
+ if (ipmuxid >= 0) {
+ notice("Removing ppp interface unit");
+ if (ioctl(ipfd, I_UNLINK, ipmuxid) < 0) {
+ error("Can't remove ppp interface unit: %m");
+ return 0;
+ }
+ ipmuxid = -1;
+ }
+#endif
+ remote_addr = 0;
+ return 1;
+}
+
+/*
+ * sifdefaultroute - assign a default route through the address given.
+ */
+int
+sifdefaultroute(u, l, g)
+ int u;
+ u_int32_t l, g;
+{
+ struct rtentry rt;
+
+#if defined(__USLC__)
+ g = l; /* use the local address as gateway */
+#endif
+ memset(&rt, 0, sizeof(rt));
+ rt.rt_dst.sa_family = AF_INET;
+ INET_ADDR(rt.rt_dst) = 0;
+ rt.rt_gateway.sa_family = AF_INET;
+ INET_ADDR(rt.rt_gateway) = g;
+ rt.rt_flags = RTF_GATEWAY;
+
+ if (ioctl(ipfd, SIOCADDRT, &rt) < 0) {
+ error("Can't add default route: %m");
+ return 0;
+ }
+
+ default_route_gateway = g;
+ return 1;
+}
+
+/*
+ * cifdefaultroute - delete a default route through the address given.
+ */
+int
+cifdefaultroute(u, l, g)
+ int u;
+ u_int32_t l, g;
+{
+ struct rtentry rt;
+
+#if defined(__USLC__)
+ g = l; /* use the local address as gateway */
+#endif
+ memset(&rt, 0, sizeof(rt));
+ rt.rt_dst.sa_family = AF_INET;
+ INET_ADDR(rt.rt_dst) = 0;
+ rt.rt_gateway.sa_family = AF_INET;
+ INET_ADDR(rt.rt_gateway) = g;
+ rt.rt_flags = RTF_GATEWAY;
+
+ if (ioctl(ipfd, SIOCDELRT, &rt) < 0) {
+ error("Can't delete default route: %m");
+ return 0;
+ }
+
+ default_route_gateway = 0;
+ return 1;
+}
+
+/*
+ * sifproxyarp - Make a proxy ARP entry for the peer.
+ */
+int
+sifproxyarp(unit, hisaddr)
+ int unit;
+ u_int32_t hisaddr;
+{
+ struct arpreq arpreq;
+
+ memset(&arpreq, 0, sizeof(arpreq));
+ if (!get_ether_addr(hisaddr, &arpreq.arp_ha))
+ return 0;
+
+ arpreq.arp_pa.sa_family = AF_INET;
+ INET_ADDR(arpreq.arp_pa) = hisaddr;
+ arpreq.arp_flags = ATF_PERM | ATF_PUBL;
+ if (ioctl(ipfd, SIOCSARP, (caddr_t) &arpreq) < 0) {
+ error("Couldn't set proxy ARP entry: %m");
+ return 0;
+ }
+
+ proxy_arp_addr = hisaddr;
+ return 1;
+}
+
+/*
+ * cifproxyarp - Delete the proxy ARP entry for the peer.
+ */
+int
+cifproxyarp(unit, hisaddr)
+ int unit;
+ u_int32_t hisaddr;
+{
+ struct arpreq arpreq;
+
+ memset(&arpreq, 0, sizeof(arpreq));
+ arpreq.arp_pa.sa_family = AF_INET;
+ INET_ADDR(arpreq.arp_pa) = hisaddr;
+ if (ioctl(ipfd, SIOCDARP, (caddr_t)&arpreq) < 0) {
+ error("Couldn't delete proxy ARP entry: %m");
+ return 0;
+ }
+
+ proxy_arp_addr = 0;
+ return 1;
+}
+
+/*
+ * get_ether_addr - get the hardware address of an interface on the
+ * the same subnet as ipaddr.
+ */
+#define MAX_IFS 32
+
+static int
+get_ether_addr(ipaddr, hwaddr)
+ u_int32_t ipaddr;
+ struct sockaddr *hwaddr;
+{
+ struct ifreq *ifr, *ifend, ifreq;
+ int nif;
+ struct ifconf ifc;
+ u_int32_t ina, mask;
+
+ /*
+ * Scan through the system's network interfaces.
+ */
+#ifdef SIOCGIFNUM
+ if (ioctl(ipfd, SIOCGIFNUM, &nif) < 0)
+#endif
+ nif = MAX_IFS;
+ ifc.ifc_len = nif * sizeof(struct ifreq);
+ ifc.ifc_buf = (caddr_t) malloc(ifc.ifc_len);
+ if (ifc.ifc_buf == 0)
+ return 0;
+ if (ioctl(ipfd, SIOCGIFCONF, &ifc) < 0) {
+ warn("Couldn't get system interface list: %m");
+ free(ifc.ifc_buf);
+ return 0;
+ }
+ ifend = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len);
+ for (ifr = ifc.ifc_req; ifr < ifend; ++ifr) {
+ if (ifr->ifr_addr.sa_family != AF_INET)
+ continue;
+ /*
+ * Check that the interface is up, and not point-to-point or loopback.
+ */
+ strlcpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name));
+ if (ioctl(ipfd, SIOCGIFFLAGS, &ifreq) < 0)
+ continue;
+ if ((ifreq.ifr_flags &
+ (IFF_UP|IFF_BROADCAST|IFF_POINTOPOINT|IFF_LOOPBACK|IFF_NOARP))
+ != (IFF_UP|IFF_BROADCAST))
+ continue;
+ /*
+ * Get its netmask and check that it's on the right subnet.
+ */
+ if (ioctl(ipfd, SIOCGIFNETMASK, &ifreq) < 0)
+ continue;
+ ina = INET_ADDR(ifr->ifr_addr);
+ mask = INET_ADDR(ifreq.ifr_addr);
+ if ((ipaddr & mask) == (ina & mask))
+ break;
+ }
+
+ if (ifr >= ifend) {
+ warn("No suitable interface found for proxy ARP");
+ free(ifc.ifc_buf);
+ return 0;
+ }
+
+ info("found interface %s for proxy ARP", ifr->ifr_name);
+ if (!get_hw_addr(ifr->ifr_name, ina, hwaddr)) {
+ error("Couldn't get hardware address for %s", ifr->ifr_name);
+ free(ifc.ifc_buf);
+ return 0;
+ }
+
+ free(ifc.ifc_buf);
+ return 1;
+}
+
+/*
+ * get_hw_addr_dlpi - obtain the hardware address using DLPI
+ */
+static int
+get_hw_addr_dlpi(name, hwaddr)
+ char *name;
+ struct sockaddr *hwaddr;
+{
+ char *p, *q;
+ int unit, iffd, adrlen;
+ unsigned char *adrp;
+ char ifdev[24];
+ struct {
+ union DL_primitives prim;
+ char space[64];
+ } reply;
+
+ /*
+ * We have to open the device and ask it for its hardware address.
+ * First split apart the device name and unit.
+ */
+ slprintf(ifdev, sizeof(ifdev), "/dev/%s", name);
+ for (q = ifdev + strlen(ifdev); --q >= ifdev; )
+ if (!isdigit(*q))
+ break;
+ unit = atoi(q+1);
+ q[1] = 0;
+
+ /*
+ * Open the device and do a DLPI attach and phys_addr_req.
+ */
+ iffd = open(ifdev, O_RDWR);
+ if (iffd < 0) {
+ error("Can't open %s: %m", ifdev);
+ return 0;
+ }
+ if (dlpi_attach(iffd, unit) < 0
+ || dlpi_get_reply(iffd, &reply.prim, DL_OK_ACK, sizeof(reply)) < 0
+ || dlpi_info_req(iffd) < 0
+ || dlpi_get_reply(iffd, &reply.prim, DL_INFO_ACK, sizeof(reply)) < 0) {
+ close(iffd);
+ return 0;
+ }
+
+ adrlen = reply.prim.info_ack.dl_addr_length;
+ adrp = (unsigned char *)&reply + reply.prim.info_ack.dl_addr_offset;
+
+#if DL_CURRENT_VERSION >= 2
+ if (reply.prim.info_ack.dl_sap_length < 0)
+ adrlen += reply.prim.info_ack.dl_sap_length;
+ else
+ adrp += reply.prim.info_ack.dl_sap_length;
+#endif
+
+ hwaddr->sa_family = AF_UNSPEC;
+ memcpy(hwaddr->sa_data, adrp, adrlen);
+
+ return 1;
+}
+/*
+ * get_hw_addr - obtain the hardware address for a named interface.
+ */
+static int
+get_hw_addr(name, ina, hwaddr)
+ char *name;
+ u_int32_t ina;
+ struct sockaddr *hwaddr;
+{
+ /* New way - get the address by doing an arp request. */
+ int s;
+ struct arpreq req;
+
+ s = socket(AF_INET, SOCK_DGRAM, 0);
+ if (s < 0)
+ return 0;
+ memset(&req, 0, sizeof(req));
+ req.arp_pa.sa_family = AF_INET;
+ INET_ADDR(req.arp_pa) = ina;
+ if (ioctl(s, SIOCGARP, &req) < 0) {
+ error("Couldn't get ARP entry for %s: %m", ip_ntoa(ina));
+ return 0;
+ }
+ *hwaddr = req.arp_ha;
+ hwaddr->sa_family = AF_UNSPEC;
+
+ return 1;
+}
+
+static int
+dlpi_attach(fd, ppa)
+ int fd, ppa;
+{
+ dl_attach_req_t req;
+ struct strbuf buf;
+
+ req.dl_primitive = DL_ATTACH_REQ;
+ req.dl_ppa = ppa;
+ buf.len = sizeof(req);
+ buf.buf = (void *) &req;
+ return putmsg(fd, &buf, NULL, RS_HIPRI);
+}
+
+static int
+dlpi_info_req(fd)
+ int fd;
+{
+ dl_info_req_t req;
+ struct strbuf buf;
+
+ req.dl_primitive = DL_INFO_REQ;
+ buf.len = sizeof(req);
+ buf.buf = (void *) &req;
+ return putmsg(fd, &buf, NULL, RS_HIPRI);
+}
+
+static int
+dlpi_get_reply(fd, reply, expected_prim, maxlen)
+ union DL_primitives *reply;
+ int fd, expected_prim, maxlen;
+{
+ struct strbuf buf;
+ int flags, n;
+ struct pollfd pfd;
+
+ /*
+ * Use poll to wait for a message with a timeout.
+ */
+ pfd.fd = fd;
+ pfd.events = POLLIN | POLLPRI;
+ do {
+ n = poll(&pfd, 1, 1000);
+ } while (n == -1 && errno == EINTR);
+ if (n <= 0)
+ return -1;
+
+ /*
+ * Get the reply.
+ */
+ buf.maxlen = maxlen;
+ buf.buf = (void *) reply;
+ flags = 0;
+ if (getmsg(fd, &buf, NULL, &flags) < 0)
+ return -1;
+
+ if (buf.len < sizeof(ulong)) {
+ if (debug)
+ dbglog("dlpi response short (len=%d)\n", buf.len);
+ return -1;
+ }
+
+ if (reply->dl_primitive == expected_prim)
+ return 0;
+
+ if (debug) {
+ if (reply->dl_primitive == DL_ERROR_ACK) {
+ dbglog("dlpi error %d (unix errno %d) for prim %x\n",
+ reply->error_ack.dl_errno, reply->error_ack.dl_unix_errno,
+ reply->error_ack.dl_error_primitive);
+ } else {
+ dbglog("dlpi unexpected response prim %x\n",
+ reply->dl_primitive);
+ }
+ }
+
+ return -1;
+}
+
+/*
+ * Return user specified netmask, modified by any mask we might determine
+ * for address `addr' (in network byte order).
+ * Here we scan through the system's list of interfaces, looking for
+ * any non-point-to-point interfaces which might appear to be on the same
+ * network as `addr'. If we find any, we OR in their netmask to the
+ * user-specified netmask.
+ */
+u_int32_t
+GetMask(addr)
+ u_int32_t addr;
+{
+ u_int32_t mask, nmask, ina;
+ struct ifreq *ifr, *ifend, ifreq;
+ int nif;
+ struct ifconf ifc;
+
+ addr = ntohl(addr);
+ if (IN_CLASSA(addr)) /* determine network mask for address class */
+ nmask = IN_CLASSA_NET;
+ else if (IN_CLASSB(addr))
+ nmask = IN_CLASSB_NET;
+ else
+ nmask = IN_CLASSC_NET;
+ /* class D nets are disallowed by bad_ip_adrs */
+ mask = netmask | htonl(nmask);
+
+ /*
+ * Scan through the system's network interfaces.
+ */
+#ifdef SIOCGIFNUM
+ if (ioctl(ipfd, SIOCGIFNUM, &nif) < 0)
+#endif
+ nif = MAX_IFS;
+ ifc.ifc_len = nif * sizeof(struct ifreq);
+ ifc.ifc_buf = (caddr_t) malloc(ifc.ifc_len);
+ if (ifc.ifc_buf == 0)
+ return mask;
+ if (ioctl(ipfd, SIOCGIFCONF, &ifc) < 0) {
+ warn("Couldn't get system interface list: %m");
+ free(ifc.ifc_buf);
+ return mask;
+ }
+ ifend = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len);
+ for (ifr = ifc.ifc_req; ifr < ifend; ++ifr) {
+ /*
+ * Check the interface's internet address.
+ */
+ if (ifr->ifr_addr.sa_family != AF_INET)
+ continue;
+ ina = INET_ADDR(ifr->ifr_addr);
+ if ((ntohl(ina) & nmask) != (addr & nmask))
+ continue;
+ /*
+ * Check that the interface is up, and not point-to-point or loopback.
+ */
+ strlcpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name));
+ if (ioctl(ipfd, SIOCGIFFLAGS, &ifreq) < 0)
+ continue;
+ if ((ifreq.ifr_flags & (IFF_UP|IFF_POINTOPOINT|IFF_LOOPBACK))
+ != IFF_UP)
+ continue;
+ /*
+ * Get its netmask and OR it into our mask.
+ */
+ if (ioctl(ipfd, SIOCGIFNETMASK, &ifreq) < 0)
+ continue;
+ mask |= INET_ADDR(ifreq.ifr_addr);
+ }
+
+ free(ifc.ifc_buf);
+ return mask;
+}
+
+/*
+ * logwtmp - write an accounting record to the /var/adm/wtmp file.
+ */
+void
+logwtmp(line, name, host)
+ const char *line, *name, *host;
+{
+ static struct utmpx utmpx;
+
+ if (name[0] != 0) {
+ /* logging in */
+ strncpy(utmpx.ut_user, name, sizeof(utmpx.ut_user));
+ strncpy(utmpx.ut_id, ifname, sizeof(utmpx.ut_id));
+ strncpy(utmpx.ut_line, line, sizeof(utmpx.ut_line));
+ utmpx.ut_pid = getpid();
+ utmpx.ut_type = USER_PROCESS;
+ } else {
+ utmpx.ut_type = DEAD_PROCESS;
+ }
+ gettimeofday(&utmpx.ut_tv, NULL);
+ updwtmpx("/var/adm/wtmpx", &utmpx);
+}
+
+/*
+ * get_host_seed - return the serial number of this machine.
+ */
+int
+get_host_seed()
+{
+ char buf[32];
+
+ if (sysinfo(SI_HW_SERIAL, buf, sizeof(buf)) < 0) {
+ error("sysinfo: %m");
+ return 0;
+ }
+ return (int) strtoul(buf, NULL, 16);
+}
+
+static int
+strioctl(fd, cmd, ptr, ilen, olen)
+ int fd, cmd, ilen, olen;
+ void *ptr;
+{
+ struct strioctl str;
+
+ str.ic_cmd = cmd;
+ str.ic_timout = 0;
+ str.ic_len = ilen;
+ str.ic_dp = ptr;
+ if (ioctl(fd, I_STR, &str) == -1)
+ return -1;
+ if (str.ic_len != olen)
+ dbglog("strioctl: expected %d bytes, got %d for cmd %x\n",
+ olen, str.ic_len, cmd);
+ return 0;
+}
+
+#if 0
+/*
+ * lock - create a lock file for the named lock device
+ */
+
+#define LOCK_PREFIX "/var/spool/locks/LK."
+static char lock_file[40]; /* name of lock file created */
+
+int
+lock(dev)
+ char *dev;
+{
+ int n, fd, pid;
+ struct stat sbuf;
+ char ascii_pid[12];
+
+ if (stat(dev, &sbuf) < 0) {
+ error("Can't get device number for %s: %m", dev);
+ return -1;
+ }
+ if ((sbuf.st_mode & S_IFMT) != S_IFCHR) {
+ error("Can't lock %s: not a character device", dev);
+ return -1;
+ }
+ slprintf(lock_file, sizeof(lock_file), "%s%03d.%03d.%03d",
+ LOCK_PREFIX, major(sbuf.st_dev),
+ major(sbuf.st_rdev), minor(sbuf.st_rdev));
+
+ while ((fd = open(lock_file, O_EXCL | O_CREAT | O_RDWR, 0644)) < 0) {
+ if (errno == EEXIST
+ && (fd = open(lock_file, O_RDONLY, 0)) >= 0) {
+ /* Read the lock file to find out who has the device locked */
+ n = read(fd, ascii_pid, 11);
+ if (n <= 0) {
+ error("Can't read pid from lock file %s", lock_file);
+ close(fd);
+ } else {
+ ascii_pid[n] = 0;
+ pid = atoi(ascii_pid);
+ if (pid > 0 && kill(pid, 0) == -1 && errno == ESRCH) {
+ /* pid no longer exists - remove the lock file */
+ if (unlink(lock_file) == 0) {
+ close(fd);
+ notice("Removed stale lock on %s (pid %d)",
+ dev, pid);
+ continue;
+ } else
+ warn("Couldn't remove stale lock on %s",
+ dev);
+ } else
+ notice("Device %s is locked by pid %d",
+ dev, pid);
+ }
+ close(fd);
+ } else
+ error("Can't create lock file %s: %m", lock_file);
+ lock_file[0] = 0;
+ return -1;
+ }
+
+ slprintf(ascii_pid, sizeof(ascii_pid), "%10d\n", getpid());
+ write(fd, ascii_pid, 11);
+
+ close(fd);
+ return 1;
+}
+
+/*
+ * unlock - remove our lockfile
+ */
+void
+unlock()
+{
+ if (lock_file[0]) {
+ unlink(lock_file);
+ lock_file[0] = 0;
+ }
+}
+#endif
+
+/*
+ * cifroute - delete a route through the addresses given.
+ */
+int
+cifroute(u, our, his)
+ int u;
+ u_int32_t our, his;
+{
+ struct rtentry rt;
+
+ memset(&rt, 0, sizeof(rt));
+ rt.rt_dst.sa_family = AF_INET;
+ INET_ADDR(rt.rt_dst) = his;
+ rt.rt_gateway.sa_family = AF_INET;
+ INET_ADDR(rt.rt_gateway) = our;
+ rt.rt_flags = RTF_HOST;
+
+ if (ioctl(ipfd, SIOCDELRT, &rt) < 0) {
+ error("Can't delete route: %m");
+ return 0;
+ }
+
+ return 1;
+}
+
+/*
+ * have_route_to - determine if the system has a route to the specified
+ * IP address. Returns 0 if not, 1 if so, -1 if we can't tell.
+ * `addr' is in network byte order.
+ * For demand mode to work properly, we have to ignore routes
+ * through our own interface.
+ */
+#ifndef T_CURRENT /* needed for Solaris 2.5 */
+#define T_CURRENT MI_T_CURRENT
+#endif
+
+int
+have_route_to(addr)
+ u_int32_t addr;
+{
+#ifdef SOL2
+ int fd, r, flags, i;
+ struct {
+ struct T_optmgmt_req req;
+ struct opthdr hdr;
+ } req;
+ union {
+ struct T_optmgmt_ack ack;
+ unsigned char space[64];
+ } ack;
+ struct opthdr *rh;
+ struct strbuf cbuf, dbuf;
+ int nroutes;
+ mib2_ipRouteEntry_t routes[8];
+ mib2_ipRouteEntry_t *rp;
+
+ fd = open(mux_dev_name, O_RDWR);
+ if (fd < 0) {
+ warn("have_route_to: couldn't open %s: %m", mux_dev_name);
+ return -1;
+ }
+
+ req.req.PRIM_type = T_OPTMGMT_REQ;
+ req.req.OPT_offset = (char *) &req.hdr - (char *) &req;
+ req.req.OPT_length = sizeof(req.hdr);
+ req.req.MGMT_flags = T_CURRENT;
+
+ req.hdr.level = MIB2_IP;
+ req.hdr.name = 0;
+ req.hdr.len = 0;
+
+ cbuf.buf = (char *) &req;
+ cbuf.len = sizeof(req);
+
+ if (putmsg(fd, &cbuf, NULL, 0) == -1) {
+ warn("have_route_to: putmsg: %m");
+ close(fd);
+ return -1;
+ }
+
+ for (;;) {
+ cbuf.buf = (char *) &ack;
+ cbuf.maxlen = sizeof(ack);
+ dbuf.buf = (char *) routes;
+ dbuf.maxlen = sizeof(routes);
+ flags = 0;
+ r = getmsg(fd, &cbuf, &dbuf, &flags);
+ if (r == -1) {
+ warn("have_route_to: getmsg: %m");
+ close(fd);
+ return -1;
+ }
+
+ if (cbuf.len < sizeof(struct T_optmgmt_ack)
+ || ack.ack.PRIM_type != T_OPTMGMT_ACK
+ || ack.ack.MGMT_flags != T_SUCCESS
+ || ack.ack.OPT_length < sizeof(struct opthdr)) {
+ dbglog("have_route_to: bad message len=%d prim=%d",
+ cbuf.len, ack.ack.PRIM_type);
+ close(fd);
+ return -1;
+ }
+
+ rh = (struct opthdr *) ((char *)&ack + ack.ack.OPT_offset);
+ if (rh->level == 0 && rh->name == 0)
+ break;
+ if (rh->level != MIB2_IP || rh->name != MIB2_IP_21) {
+ while (r == MOREDATA)
+ r = getmsg(fd, NULL, &dbuf, &flags);
+ continue;
+ }
+
+ for (;;) {
+ nroutes = dbuf.len / sizeof(mib2_ipRouteEntry_t);
+ for (rp = routes, i = 0; i < nroutes; ++i, ++rp) {
+ if (rp->ipRouteMask != ~0) {
+ dbglog("have_route_to: dest=%x gw=%x mask=%x\n",
+ rp->ipRouteDest, rp->ipRouteNextHop,
+ rp->ipRouteMask);
+ if (((addr ^ rp->ipRouteDest) & rp->ipRouteMask) == 0
+ && rp->ipRouteNextHop != remote_addr)
+ return 1;
+ }
+ }
+ if (r == 0)
+ break;
+ r = getmsg(fd, NULL, &dbuf, &flags);
+ }
+ }
+ close(fd);
+ return 0;
+#else
+ return -1;
+#endif /* SOL2 */
+}
+
+/*
+ * get_pty - get a pty master/slave pair and chown the slave side to
+ * the uid given. Assumes slave_name points to MAXPATHLEN bytes of space.
+ */
+int
+get_pty(master_fdp, slave_fdp, slave_name, uid)
+ int *master_fdp;
+ int *slave_fdp;
+ char *slave_name;
+ int uid;
+{
+ int mfd, sfd;
+ char *pty_name;
+ struct termios tios;
+
+ mfd = open("/dev/ptmx", O_RDWR);
+ if (mfd < 0) {
+ error("Couldn't open pty master: %m");
+ return 0;
+ }
+
+ pty_name = ptsname(mfd);
+ if (pty_name == NULL) {
+ error("Couldn't get name of pty slave");
+ close(mfd);
+ return 0;
+ }
+ if (chown(pty_name, uid, -1) < 0)
+ warn("Couldn't change owner of pty slave: %m");
+ if (chmod(pty_name, S_IRUSR | S_IWUSR) < 0)
+ warn("Couldn't change permissions on pty slave: %m");
+ if (unlockpt(mfd) < 0)
+ warn("Couldn't unlock pty slave: %m");
+
+ sfd = open(pty_name, O_RDWR);
+ if (sfd < 0) {
+ error("Couldn't open pty slave %s: %m", pty_name);
+ close(mfd);
+ return 0;
+ }
+ if (ioctl(sfd, I_PUSH, "ptem") < 0)
+ warn("Couldn't push ptem module on pty slave: %m");
+
+ dbglog("Using %s", pty_name);
+ strlcpy(slave_name, pty_name, MAXPATHLEN);
+ *master_fdp = mfd;
+ *slave_fdp = sfd;
+
+ return 1;
+}
diff --git a/mdk-stage1/ppp/pppd/sys-sunos4.c b/mdk-stage1/ppp/pppd/sys-sunos4.c
new file mode 100644
index 000000000..8365e3894
--- /dev/null
+++ b/mdk-stage1/ppp/pppd/sys-sunos4.c
@@ -0,0 +1,1559 @@
+/*
+ * System-dependent procedures for pppd under SunOS 4.
+ *
+ * Copyright (c) 1994 The Australian National University.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation is hereby granted, provided that the above copyright
+ * notice appears in all copies. This software is provided without any
+ * warranty, express or implied. The Australian National University
+ * makes no representations about the suitability of this software for
+ * any purpose.
+ *
+ * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
+ * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
+ * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
+ * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
+ * OR MODIFICATIONS.
+ */
+
+#define RCSID "$Id: sys-sunos4.c 195720 2001-06-11 11:44:34Z gc $"
+
+#include <stdio.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <termios.h>
+#include <signal.h>
+#include <malloc.h>
+#include <utmp.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <sys/stream.h>
+#include <sys/stropts.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/poll.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <net/nit_if.h>
+#include <net/route.h>
+#include <net/ppp_defs.h>
+#include <net/pppio.h>
+#include <netinet/in.h>
+
+#include "pppd.h"
+
+#if defined(sun) && defined(sparc)
+#include <alloca.h>
+#ifndef __GNUC__
+extern void *alloca();
+#endif
+#endif /*sparc*/
+
+static const char rcsid[] = RCSID;
+
+static int pppfd;
+static int fdmuxid = -1;
+static int iffd;
+static int sockfd;
+
+static int restore_term;
+static struct termios inittermios;
+static struct winsize wsinfo; /* Initial window size info */
+static pid_t parent_pid; /* PID of our parent */
+
+extern u_char inpacket_buf[]; /* borrowed from main.c */
+
+#define MAX_POLLFDS 32
+static struct pollfd pollfds[MAX_POLLFDS];
+static int n_pollfds;
+
+static int link_mtu, link_mru;
+
+#define NMODULES 32
+static int tty_nmodules;
+static char tty_modules[NMODULES][FMNAMESZ+1];
+
+static int if_is_up; /* Interface has been marked up */
+static u_int32_t ifaddrs[2]; /* local and remote addresses */
+static u_int32_t default_route_gateway; /* Gateway for default route added */
+static u_int32_t proxy_arp_addr; /* Addr for proxy arp entry added */
+
+/* Prototypes for procedures local to this file. */
+static int translate_speed __P((int));
+static int baud_rate_of __P((int));
+static int get_ether_addr __P((u_int32_t, struct sockaddr *));
+static int strioctl __P((int, int, void *, int, int));
+
+
+/*
+ * sys_init - System-dependent initialization.
+ */
+void
+sys_init()
+{
+ int x;
+
+ /* Get an internet socket for doing socket ioctl's on. */
+ if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
+ fatal("Couldn't create IP socket: %m");
+
+ /*
+ * We may want to send a SIGHUP to the session leader associated
+ * with our controlling terminal later. Because SunOS doesn't
+ * have getsid(), we make do with sending the signal to our
+ * parent process.
+ */
+ parent_pid = getppid();
+
+ /*
+ * Open the ppp device.
+ */
+ pppfd = open("/dev/ppp", O_RDWR | O_NONBLOCK, 0);
+ if (pppfd < 0)
+ fatal("Can't open /dev/ppp: %m");
+ if (kdebugflag) {
+ x = PPPDBG_LOG + PPPDBG_DRIVER;
+ strioctl(pppfd, PPPIO_DEBUG, &x, sizeof(int), 0);
+ }
+
+ /* Assign a new PPA and get its unit number. */
+ if (strioctl(pppfd, PPPIO_NEWPPA, &ifunit, 0, sizeof(int)) < 0)
+ fatal("Can't create new PPP interface: %m");
+
+ /*
+ * Open the ppp device again and push the if_ppp module on it.
+ */
+ iffd = open("/dev/ppp", O_RDWR, 0);
+ if (iffd < 0)
+ fatal("Can't open /dev/ppp (2): %m");
+ if (kdebugflag) {
+ x = PPPDBG_LOG + PPPDBG_DRIVER;
+ strioctl(iffd, PPPIO_DEBUG, &x, sizeof(int), 0);
+ }
+ if (strioctl(iffd, PPPIO_ATTACH, &ifunit, sizeof(int), 0) < 0)
+ fatal("Couldn't attach ppp interface to device: %m");
+ if (ioctl(iffd, I_PUSH, "if_ppp") < 0)
+ fatal("Can't push ppp interface module: %m");
+ if (kdebugflag) {
+ x = PPPDBG_LOG + PPPDBG_IF;
+ strioctl(iffd, PPPIO_DEBUG, &x, sizeof(int), 0);
+ }
+ if (strioctl(iffd, PPPIO_NEWPPA, &ifunit, sizeof(int), 0) < 0)
+ fatal("Couldn't create ppp interface unit: %m");
+ x = PPP_IP;
+ if (strioctl(iffd, PPPIO_BIND, &x, sizeof(int), 0) < 0)
+ fatal("Couldn't bind ppp interface to IP SAP: %m");
+
+ n_pollfds = 0;
+}
+
+/*
+ * sys_cleanup - restore any system state we modified before exiting:
+ * mark the interface down, delete default route and/or proxy arp entry.
+ * This shouldn't call die() because it's called from die().
+ */
+void
+sys_cleanup()
+{
+ if (if_is_up)
+ sifdown(0);
+ if (ifaddrs[0])
+ cifaddr(0, ifaddrs[0], ifaddrs[1]);
+ if (default_route_gateway)
+ cifdefaultroute(0, 0, default_route_gateway);
+ if (proxy_arp_addr)
+ cifproxyarp(0, proxy_arp_addr);
+}
+
+/*
+ * sys_close - Clean up in a child process before execing.
+ */
+void
+sys_close()
+{
+ close(iffd);
+ close(pppfd);
+ close(sockfd);
+}
+
+/*
+ * sys_check_options - check the options that the user specified
+ */
+int
+sys_check_options()
+{
+ return 1;
+}
+
+#if 0
+/*
+ * daemon - Detach us from controlling terminal session.
+ */
+int
+daemon(nochdir, noclose)
+ int nochdir, noclose;
+{
+ int pid;
+
+ if ((pid = fork()) < 0)
+ return -1;
+ if (pid != 0)
+ exit(0); /* parent dies */
+ setsid();
+ if (!nochdir)
+ chdir("/");
+ if (!noclose) {
+ fclose(stdin); /* don't need stdin, stdout, stderr */
+ fclose(stdout);
+ fclose(stderr);
+ }
+ return 0;
+}
+#endif
+
+/*
+ * ppp_available - check whether the system has any ppp interfaces
+ */
+int
+ppp_available()
+{
+ struct stat buf;
+
+ return stat("/dev/ppp", &buf) >= 0;
+}
+
+/*
+ * tty_establish_ppp - Turn the serial port into a ppp interface.
+ */
+int
+tty_establish_ppp(fd)
+ int fd;
+{
+ int i;
+
+ /* Pop any existing modules off the tty stream. */
+ for (i = 0;; ++i)
+ if (ioctl(fd, I_LOOK, tty_modules[i]) < 0
+ || ioctl(fd, I_POP, 0) < 0)
+ break;
+ tty_nmodules = i;
+
+ /* Push the async hdlc module and the compressor module. */
+ if (ioctl(fd, I_PUSH, "ppp_ahdl") < 0)
+ fatal("Couldn't push PPP Async HDLC module: %m");
+ if (ioctl(fd, I_PUSH, "ppp_comp") < 0)
+ error("Couldn't push PPP compression module: %m");
+
+ /* Link the serial port under the PPP multiplexor. */
+ if ((fdmuxid = ioctl(pppfd, I_LINK, fd)) < 0)
+ fatal("Can't link tty to PPP mux: %m");
+
+ return pppfd;
+}
+
+/*
+ * disestablish_ppp - Restore the serial port to normal operation.
+ * It attempts to reconstruct the stream with the previously popped
+ * modules. This shouldn't call die() because it's called from die().
+ */
+void
+tty_disestablish_ppp(fd)
+ int fd;
+{
+ int i;
+
+ if (fdmuxid >= 0) {
+ if (ioctl(pppfd, I_UNLINK, fdmuxid) < 0) {
+ if (!hungup)
+ error("Can't unlink tty from PPP mux: %m");
+ }
+ fdmuxid = -1;
+
+ if (!hungup) {
+ while (ioctl(fd, I_POP, 0) >= 0)
+ ;
+ for (i = tty_nmodules - 1; i >= 0; --i)
+ if (ioctl(fd, I_PUSH, tty_modules[i]) < 0)
+ error("Couldn't restore tty module %s: %m",
+ tty_modules[i]);
+ }
+ if (hungup && default_device && parent_pid > 0) {
+ /*
+ * If we have received a hangup, we need to send a SIGHUP
+ * to the terminal's controlling process. The reason is
+ * that the original stream head for the terminal hasn't
+ * seen the M_HANGUP message (it went up through the ppp
+ * driver to the stream head for our fd to /dev/ppp).
+ * Actually we send the signal to the process that invoked
+ * pppd, since SunOS doesn't have getsid().
+ */
+ kill(parent_pid, SIGHUP);
+ }
+ }
+}
+
+/*
+ * Check whether the link seems not to be 8-bit clean.
+ */
+void
+clean_check()
+{
+ int x;
+ char *s;
+
+ if (strioctl(pppfd, PPPIO_GCLEAN, &x, 0, sizeof(x)) < 0)
+ return;
+ s = NULL;
+ switch (~x) {
+ case RCV_B7_0:
+ s = "bit 7 set to 1";
+ break;
+ case RCV_B7_1:
+ s = "bit 7 set to 0";
+ break;
+ case RCV_EVNP:
+ s = "odd parity";
+ break;
+ case RCV_ODDP:
+ s = "even parity";
+ break;
+ }
+ if (s != NULL) {
+ warn("Serial link is not 8-bit clean:");
+ warn("All received characters had %s", s);
+ }
+}
+
+/*
+ * List of valid speeds.
+ */
+struct speed {
+ int speed_int, speed_val;
+} speeds[] = {
+#ifdef B50
+ { 50, B50 },
+#endif
+#ifdef B75
+ { 75, B75 },
+#endif
+#ifdef B110
+ { 110, B110 },
+#endif
+#ifdef B134
+ { 134, B134 },
+#endif
+#ifdef B150
+ { 150, B150 },
+#endif
+#ifdef B200
+ { 200, B200 },
+#endif
+#ifdef B300
+ { 300, B300 },
+#endif
+#ifdef B600
+ { 600, B600 },
+#endif
+#ifdef B1200
+ { 1200, B1200 },
+#endif
+#ifdef B1800
+ { 1800, B1800 },
+#endif
+#ifdef B2000
+ { 2000, B2000 },
+#endif
+#ifdef B2400
+ { 2400, B2400 },
+#endif
+#ifdef B3600
+ { 3600, B3600 },
+#endif
+#ifdef B4800
+ { 4800, B4800 },
+#endif
+#ifdef B7200
+ { 7200, B7200 },
+#endif
+#ifdef B9600
+ { 9600, B9600 },
+#endif
+#ifdef B19200
+ { 19200, B19200 },
+#endif
+#ifdef B38400
+ { 38400, B38400 },
+#endif
+#ifdef EXTA
+ { 19200, EXTA },
+#endif
+#ifdef EXTB
+ { 38400, EXTB },
+#endif
+#ifdef B57600
+ { 57600, B57600 },
+#endif
+#ifdef B115200
+ { 115200, B115200 },
+#endif
+ { 0, 0 }
+};
+
+/*
+ * Translate from bits/second to a speed_t.
+ */
+static int
+translate_speed(bps)
+ int bps;
+{
+ struct speed *speedp;
+
+ if (bps == 0)
+ return 0;
+ for (speedp = speeds; speedp->speed_int; speedp++)
+ if (bps == speedp->speed_int)
+ return speedp->speed_val;
+ warn("speed %d not supported", bps);
+ return 0;
+}
+
+/*
+ * Translate from a speed_t to bits/second.
+ */
+static int
+baud_rate_of(speed)
+ int speed;
+{
+ struct speed *speedp;
+
+ if (speed == 0)
+ return 0;
+ for (speedp = speeds; speedp->speed_int; speedp++)
+ if (speed == speedp->speed_val)
+ return speedp->speed_int;
+ return 0;
+}
+
+/*
+ * set_up_tty: Set up the serial port on `fd' for 8 bits, no parity,
+ * at the requested speed, etc. If `local' is true, set CLOCAL
+ * regardless of whether the modem option was specified.
+ */
+void
+set_up_tty(fd, local)
+ int fd, local;
+{
+ int speed;
+ struct termios tios;
+
+ if (tcgetattr(fd, &tios) < 0)
+ fatal("tcgetattr: %m");
+
+ if (!restore_term) {
+ inittermios = tios;
+ ioctl(fd, TIOCGWINSZ, &wsinfo);
+ }
+
+ tios.c_cflag &= ~(CSIZE | CSTOPB | PARENB | CLOCAL);
+ if (crtscts > 0)
+ tios.c_cflag |= CRTSCTS;
+ else if (crtscts < 0)
+ tios.c_cflag &= ~CRTSCTS;
+
+ tios.c_cflag |= CS8 | CREAD | HUPCL;
+ if (local || !modem)
+ tios.c_cflag |= CLOCAL;
+ tios.c_iflag = IGNBRK | IGNPAR;
+ tios.c_oflag = 0;
+ tios.c_lflag = 0;
+ tios.c_cc[VMIN] = 1;
+ tios.c_cc[VTIME] = 0;
+
+ if (crtscts == -2) {
+ tios.c_iflag |= IXON | IXOFF;
+ tios.c_cc[VSTOP] = 0x13; /* DC3 = XOFF = ^S */
+ tios.c_cc[VSTART] = 0x11; /* DC1 = XON = ^Q */
+ }
+
+ speed = translate_speed(inspeed);
+ if (speed) {
+ cfsetospeed(&tios, speed);
+ cfsetispeed(&tios, speed);
+ } else {
+ speed = cfgetospeed(&tios);
+ /*
+ * We can't proceed if the serial port speed is 0,
+ * since that implies that the serial port is disabled.
+ */
+ if (speed == B0)
+ fatal("Baud rate for %s is 0; need explicit baud rate", devnam);
+ }
+
+ if (tcsetattr(fd, TCSAFLUSH, &tios) < 0)
+ fatal("tcsetattr: %m");
+
+ baud_rate = inspeed = baud_rate_of(speed);
+ restore_term = 1;
+}
+
+/*
+ * restore_tty - restore the terminal to the saved settings.
+ */
+void
+restore_tty(fd)
+ int fd;
+{
+ if (restore_term) {
+ if (!default_device) {
+ /*
+ * Turn off echoing, because otherwise we can get into
+ * a loop with the tty and the modem echoing to each other.
+ * We presume we are the sole user of this tty device, so
+ * when we close it, it will revert to its defaults anyway.
+ */
+ inittermios.c_lflag &= ~(ECHO | ECHONL);
+ }
+ if (tcsetattr(fd, TCSAFLUSH, &inittermios) < 0)
+ if (!hungup && errno != ENXIO)
+ warn("tcsetattr: %m");
+ ioctl(fd, TIOCSWINSZ, &wsinfo);
+ restore_term = 0;
+ }
+}
+
+/*
+ * setdtr - control the DTR line on the serial port.
+ * This is called from die(), so it shouldn't call die().
+ */
+void
+setdtr(fd, on)
+int fd, on;
+{
+ int modembits = TIOCM_DTR;
+
+ ioctl(fd, (on? TIOCMBIS: TIOCMBIC), &modembits);
+}
+
+/*
+ * open_loopback - open the device we use for getting packets
+ * in demand mode. Under SunOS, we use our existing fd
+ * to the ppp driver.
+ */
+int
+open_ppp_loopback()
+{
+ return pppfd;
+}
+
+/*
+ * output - Output PPP packet.
+ */
+void
+output(unit, p, len)
+ int unit;
+ u_char *p;
+ int len;
+{
+ struct strbuf data;
+ int retries;
+ struct pollfd pfd;
+
+ if (debug)
+ dbglog("sent %P", p, len);
+
+ data.len = len;
+ data.buf = (caddr_t) p;
+ retries = 4;
+ while (putmsg(pppfd, NULL, &data, 0) < 0) {
+ if (--retries < 0 || (errno != EWOULDBLOCK && errno != EAGAIN)) {
+ if (errno != ENXIO)
+ error("Couldn't send packet: %m");
+ break;
+ }
+ pfd.fd = pppfd;
+ pfd.events = POLLOUT;
+ poll(&pfd, 1, 250); /* wait for up to 0.25 seconds */
+ }
+}
+
+
+/*
+ * wait_input - wait until there is data available,
+ * for the length of time specified by *timo (indefinite
+ * if timo is NULL).
+ */
+void
+wait_input(timo)
+ struct timeval *timo;
+{
+ int t;
+
+ t = timo == NULL? -1: timo->tv_sec * 1000 + timo->tv_usec / 1000;
+ if (poll(pollfds, n_pollfds, t) < 0 && errno != EINTR) {
+ if (errno != EAGAIN)
+ fatal("poll: %m");
+ /* we can get EAGAIN on a heavily loaded system,
+ * just wait a short time and try again. */
+ usleep(50000);
+ }
+}
+
+/*
+ * add_fd - add an fd to the set that wait_input waits for.
+ */
+void add_fd(fd)
+ int fd;
+{
+ int n;
+
+ for (n = 0; n < n_pollfds; ++n)
+ if (pollfds[n].fd == fd)
+ return;
+ if (n_pollfds < MAX_POLLFDS) {
+ pollfds[n_pollfds].fd = fd;
+ pollfds[n_pollfds].events = POLLIN | POLLPRI | POLLHUP;
+ ++n_pollfds;
+ } else
+ error("Too many inputs!");
+}
+
+/*
+ * remove_fd - remove an fd from the set that wait_input waits for.
+ */
+void remove_fd(fd)
+ int fd;
+{
+ int n;
+
+ for (n = 0; n < n_pollfds; ++n) {
+ if (pollfds[n].fd == fd) {
+ while (++n < n_pollfds)
+ pollfds[n-1] = pollfds[n];
+ --n_pollfds;
+ break;
+ }
+ }
+}
+
+#if 0
+/*
+ * wait_loop_output - wait until there is data available on the
+ * loopback, for the length of time specified by *timo (indefinite
+ * if timo is NULL).
+ */
+void
+wait_loop_output(timo)
+ struct timeval *timo;
+{
+ wait_input(timo);
+}
+
+/*
+ * wait_time - wait for a given length of time or until a
+ * signal is received.
+ */
+void
+wait_time(timo)
+ struct timeval *timo;
+{
+ int n;
+
+ n = select(0, NULL, NULL, NULL, timo);
+ if (n < 0 && errno != EINTR)
+ fatal("select: %m");
+}
+#endif
+
+/*
+ * read_packet - get a PPP packet from the serial device.
+ */
+int
+read_packet(buf)
+ u_char *buf;
+{
+ struct strbuf ctrl, data;
+ int flags, len;
+ unsigned char ctrlbuf[64];
+
+ for (;;) {
+ data.maxlen = PPP_MRU + PPP_HDRLEN;
+ data.buf = (caddr_t) buf;
+ ctrl.maxlen = sizeof(ctrlbuf);
+ ctrl.buf = (caddr_t) ctrlbuf;
+ flags = 0;
+ len = getmsg(pppfd, &ctrl, &data, &flags);
+ if (len < 0) {
+ if (errno == EAGAIN || errno == EINTR)
+ return -1;
+ fatal("Error reading packet: %m");
+ }
+
+ if (ctrl.len <= 0)
+ return data.len;
+
+ /*
+ * Got a M_PROTO or M_PCPROTO message. Huh?
+ */
+ if (debug)
+ dbglog("got ctrl msg len=%d", ctrl.len);
+
+ }
+}
+
+/*
+ * get_loop_output - get outgoing packets from the ppp device,
+ * and detect when we want to bring the real link up.
+ * Return value is 1 if we need to bring up the link, 0 otherwise.
+ */
+int
+get_loop_output()
+{
+ int len;
+ int rv = 0;
+
+ while ((len = read_packet(inpacket_buf)) > 0) {
+ if (loop_frame(inpacket_buf, len))
+ rv = 1;
+ }
+ return rv;
+}
+
+/*
+ * ppp_send_config - configure the transmit characteristics of
+ * the ppp interface.
+ */
+void
+ppp_send_config(unit, mtu, asyncmap, pcomp, accomp)
+ int unit, mtu;
+ u_int32_t asyncmap;
+ int pcomp, accomp;
+{
+ int cf[2];
+ struct ifreq ifr;
+
+ link_mtu = mtu;
+ if (strioctl(pppfd, PPPIO_MTU, &mtu, sizeof(mtu), 0) < 0) {
+ if (hungup && errno == ENXIO)
+ return;
+ error("Couldn't set MTU: %m");
+ }
+ if (strioctl(pppfd, PPPIO_XACCM, &asyncmap, sizeof(asyncmap), 0) < 0) {
+ error("Couldn't set transmit ACCM: %m");
+ }
+ cf[0] = (pcomp? COMP_PROT: 0) + (accomp? COMP_AC: 0);
+ cf[1] = COMP_PROT | COMP_AC;
+ if (strioctl(pppfd, PPPIO_CFLAGS, cf, sizeof(cf), sizeof(int)) < 0) {
+ error("Couldn't set prot/AC compression: %m");
+ }
+
+ /* set mtu for ip as well */
+ memset(&ifr, 0, sizeof(ifr));
+ strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+ ifr.ifr_metric = link_mtu;
+ if (ioctl(sockfd, SIOCSIFMTU, &ifr) < 0) {
+ error("Couldn't set IP MTU: %m");
+ }
+}
+
+/*
+ * ppp_set_xaccm - set the extended transmit ACCM for the interface.
+ */
+void
+ppp_set_xaccm(unit, accm)
+ int unit;
+ ext_accm accm;
+{
+ if (strioctl(pppfd, PPPIO_XACCM, accm, sizeof(ext_accm), 0) < 0) {
+ if (!hungup || errno != ENXIO)
+ warn("Couldn't set extended ACCM: %m");
+ }
+}
+
+/*
+ * ppp_recv_config - configure the receive-side characteristics of
+ * the ppp interface.
+ */
+void
+ppp_recv_config(unit, mru, asyncmap, pcomp, accomp)
+ int unit, mru;
+ u_int32_t asyncmap;
+ int pcomp, accomp;
+{
+ int cf[2];
+
+ link_mru = mru;
+ if (strioctl(pppfd, PPPIO_MRU, &mru, sizeof(mru), 0) < 0) {
+ if (hungup && errno == ENXIO)
+ return;
+ error("Couldn't set MRU: %m");
+ }
+ if (strioctl(pppfd, PPPIO_RACCM, &asyncmap, sizeof(asyncmap), 0) < 0) {
+ error("Couldn't set receive ACCM: %m");
+ }
+ cf[0] = (pcomp? DECOMP_PROT: 0) + (accomp? DECOMP_AC: 0);
+ cf[1] = DECOMP_PROT | DECOMP_AC;
+ if (strioctl(pppfd, PPPIO_CFLAGS, cf, sizeof(cf), sizeof(int)) < 0) {
+ error("Couldn't set prot/AC decompression: %m");
+ }
+}
+
+/*
+ * ccp_test - ask kernel whether a given compression method
+ * is acceptable for use.
+ */
+int
+ccp_test(unit, opt_ptr, opt_len, for_transmit)
+ int unit, opt_len, for_transmit;
+ u_char *opt_ptr;
+{
+ if (strioctl(pppfd, (for_transmit? PPPIO_XCOMP: PPPIO_RCOMP),
+ opt_ptr, opt_len, 0) >= 0)
+ return 1;
+ return (errno == ENOSR)? 0: -1;
+}
+
+/*
+ * ccp_flags_set - inform kernel about the current state of CCP.
+ */
+void
+ccp_flags_set(unit, isopen, isup)
+ int unit, isopen, isup;
+{
+ int cf[2];
+
+ cf[0] = (isopen? CCP_ISOPEN: 0) + (isup? CCP_ISUP: 0);
+ cf[1] = CCP_ISOPEN | CCP_ISUP | CCP_ERROR | CCP_FATALERROR;
+ if (strioctl(pppfd, PPPIO_CFLAGS, cf, sizeof(cf), sizeof(int)) < 0) {
+ if (!hungup || errno != ENXIO)
+ error("Couldn't set kernel CCP state: %m");
+ }
+}
+
+/*
+ * get_idle_time - return how long the link has been idle.
+ */
+int
+get_idle_time(u, ip)
+ int u;
+ struct ppp_idle *ip;
+{
+ return strioctl(pppfd, PPPIO_GIDLE, ip, 0, sizeof(struct ppp_idle)) >= 0;
+}
+
+/*
+ * get_ppp_stats - return statistics for the link.
+ */
+int
+get_ppp_stats(u, stats)
+ int u;
+ struct pppd_stats *stats;
+{
+ struct ppp_stats s;
+
+ if (strioctl(pppfd, PPPIO_GETSTAT, &s, 0, sizeof(s)) < 0) {
+ error("Couldn't get link statistics: %m");
+ return 0;
+ }
+ stats->bytes_in = s.p.ppp_ibytes;
+ stats->bytes_out = s.p.ppp_obytes;
+ return 1;
+}
+
+
+/*
+ * ccp_fatal_error - returns 1 if decompression was disabled as a
+ * result of an error detected after decompression of a packet,
+ * 0 otherwise. This is necessary because of patent nonsense.
+ */
+int
+ccp_fatal_error(unit)
+ int unit;
+{
+ int cf[2];
+
+ cf[0] = cf[1] = 0;
+ if (strioctl(pppfd, PPPIO_CFLAGS, cf, sizeof(cf), sizeof(int)) < 0) {
+ if (errno != ENXIO && errno != EINVAL)
+ error("Couldn't get compression flags: %m");
+ return 0;
+ }
+ return cf[0] & CCP_FATALERROR;
+}
+
+/*
+ * sifvjcomp - config tcp header compression
+ */
+int
+sifvjcomp(u, vjcomp, xcidcomp, xmaxcid)
+ int u, vjcomp, xcidcomp, xmaxcid;
+{
+ int cf[2];
+ char maxcid[2];
+
+ if (vjcomp) {
+ maxcid[0] = xcidcomp;
+ maxcid[1] = 15; /* XXX should be rmaxcid */
+ if (strioctl(pppfd, PPPIO_VJINIT, maxcid, sizeof(maxcid), 0) < 0) {
+ error("Couldn't initialize VJ compression: %m");
+ }
+ }
+
+ cf[0] = (vjcomp? COMP_VJC + DECOMP_VJC: 0) /* XXX this is wrong */
+ + (xcidcomp? COMP_VJCCID + DECOMP_VJCCID: 0);
+ cf[1] = COMP_VJC + DECOMP_VJC + COMP_VJCCID + DECOMP_VJCCID;
+ if (strioctl(pppfd, PPPIO_CFLAGS, cf, sizeof(cf), sizeof(int)) < 0) {
+ if (vjcomp)
+ error("Couldn't enable VJ compression: %m");
+ }
+
+ return 1;
+}
+
+/*
+ * sifup - Config the interface up and enable IP packets to pass.
+ */
+int
+sifup(u)
+ int u;
+{
+ struct ifreq ifr;
+
+ strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+ if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0) {
+ error("Couldn't mark interface up (get): %m");
+ return 0;
+ }
+ ifr.ifr_flags |= IFF_UP;
+ if (ioctl(sockfd, SIOCSIFFLAGS, &ifr) < 0) {
+ error("Couldn't mark interface up (set): %m");
+ return 0;
+ }
+ if_is_up = 1;
+ return 1;
+}
+
+/*
+ * sifdown - Config the interface down and disable IP.
+ */
+int
+sifdown(u)
+ int u;
+{
+ struct ifreq ifr;
+
+ strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+ if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0) {
+ error("Couldn't mark interface down (get): %m");
+ return 0;
+ }
+ if ((ifr.ifr_flags & IFF_UP) != 0) {
+ ifr.ifr_flags &= ~IFF_UP;
+ if (ioctl(sockfd, SIOCSIFFLAGS, &ifr) < 0) {
+ error("Couldn't mark interface down (set): %m");
+ return 0;
+ }
+ }
+ if_is_up = 0;
+ return 1;
+}
+
+/*
+ * sifnpmode - Set the mode for handling packets for a given NP.
+ */
+int
+sifnpmode(u, proto, mode)
+ int u;
+ int proto;
+ enum NPmode mode;
+{
+ int npi[2];
+
+ npi[0] = proto;
+ npi[1] = (int) mode;
+ if (strioctl(pppfd, PPPIO_NPMODE, npi, 2 * sizeof(int), 0) < 0) {
+ error("ioctl(set NP %d mode to %d): %m", proto, mode);
+ return 0;
+ }
+ return 1;
+}
+
+#define INET_ADDR(x) (((struct sockaddr_in *) &(x))->sin_addr.s_addr)
+
+/*
+ * sifaddr - Config the interface IP addresses and netmask.
+ */
+int
+sifaddr(u, o, h, m)
+ int u;
+ u_int32_t o, h, m;
+{
+ struct ifreq ifr;
+
+ memset(&ifr, 0, sizeof(ifr));
+ strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+ ifr.ifr_addr.sa_family = AF_INET;
+ INET_ADDR(ifr.ifr_addr) = m;
+ if (ioctl(sockfd, SIOCSIFNETMASK, &ifr) < 0) {
+ error("Couldn't set IP netmask: %m");
+ }
+ ifr.ifr_addr.sa_family = AF_INET;
+ INET_ADDR(ifr.ifr_addr) = o;
+ if (ioctl(sockfd, SIOCSIFADDR, &ifr) < 0) {
+ error("Couldn't set local IP address: %m");
+ }
+ ifr.ifr_dstaddr.sa_family = AF_INET;
+ INET_ADDR(ifr.ifr_dstaddr) = h;
+ if (ioctl(sockfd, SIOCSIFDSTADDR, &ifr) < 0) {
+ error("Couldn't set remote IP address: %m");
+ }
+#if 0 /* now done in ppp_send_config */
+ ifr.ifr_metric = link_mtu;
+ if (ioctl(sockfd, SIOCSIFMTU, &ifr) < 0) {
+ error("Couldn't set IP MTU: %m");
+ }
+#endif
+ ifaddrs[0] = o;
+ ifaddrs[1] = h;
+
+ return 1;
+}
+
+/*
+ * cifaddr - Clear the interface IP addresses, and delete routes
+ * through the interface if possible.
+ */
+int
+cifaddr(u, o, h)
+ int u;
+ u_int32_t o, h;
+{
+ struct rtentry rt;
+
+ bzero(&rt, sizeof(rt));
+ rt.rt_dst.sa_family = AF_INET;
+ INET_ADDR(rt.rt_dst) = h;
+ rt.rt_gateway.sa_family = AF_INET;
+ INET_ADDR(rt.rt_gateway) = o;
+ rt.rt_flags = RTF_HOST;
+ if (ioctl(sockfd, SIOCDELRT, &rt) < 0)
+ error("Couldn't delete route through interface: %m");
+ ifaddrs[0] = 0;
+ return 1;
+}
+
+/*
+ * sifdefaultroute - assign a default route through the address given.
+ */
+int
+sifdefaultroute(u, l, g)
+ int u;
+ u_int32_t l, g;
+{
+ struct rtentry rt;
+
+ bzero(&rt, sizeof(rt));
+ rt.rt_dst.sa_family = AF_INET;
+ INET_ADDR(rt.rt_dst) = 0;
+ rt.rt_gateway.sa_family = AF_INET;
+ INET_ADDR(rt.rt_gateway) = g;
+ rt.rt_flags = RTF_GATEWAY;
+
+ if (ioctl(sockfd, SIOCADDRT, &rt) < 0) {
+ error("Can't add default route: %m");
+ return 0;
+ }
+
+ default_route_gateway = g;
+ return 1;
+}
+
+/*
+ * cifdefaultroute - delete a default route through the address given.
+ */
+int
+cifdefaultroute(u, l, g)
+ int u;
+ u_int32_t l, g;
+{
+ struct rtentry rt;
+
+ bzero(&rt, sizeof(rt));
+ rt.rt_dst.sa_family = AF_INET;
+ INET_ADDR(rt.rt_dst) = 0;
+ rt.rt_gateway.sa_family = AF_INET;
+ INET_ADDR(rt.rt_gateway) = g;
+ rt.rt_flags = RTF_GATEWAY;
+
+ if (ioctl(sockfd, SIOCDELRT, &rt) < 0) {
+ error("Can't delete default route: %m");
+ return 0;
+ }
+
+ default_route_gateway = 0;
+ return 1;
+}
+
+/*
+ * sifproxyarp - Make a proxy ARP entry for the peer.
+ */
+int
+sifproxyarp(unit, hisaddr)
+ int unit;
+ u_int32_t hisaddr;
+{
+ struct arpreq arpreq;
+
+ bzero(&arpreq, sizeof(arpreq));
+ if (!get_ether_addr(hisaddr, &arpreq.arp_ha))
+ return 0;
+
+ arpreq.arp_pa.sa_family = AF_INET;
+ INET_ADDR(arpreq.arp_pa) = hisaddr;
+ arpreq.arp_flags = ATF_PERM | ATF_PUBL;
+ if (ioctl(sockfd, SIOCSARP, (caddr_t) &arpreq) < 0) {
+ error("Couldn't set proxy ARP entry: %m");
+ return 0;
+ }
+
+ proxy_arp_addr = hisaddr;
+ return 1;
+}
+
+/*
+ * cifproxyarp - Delete the proxy ARP entry for the peer.
+ */
+int
+cifproxyarp(unit, hisaddr)
+ int unit;
+ u_int32_t hisaddr;
+{
+ struct arpreq arpreq;
+
+ bzero(&arpreq, sizeof(arpreq));
+ arpreq.arp_pa.sa_family = AF_INET;
+ INET_ADDR(arpreq.arp_pa) = hisaddr;
+ if (ioctl(sockfd, SIOCDARP, (caddr_t)&arpreq) < 0) {
+ error("Couldn't delete proxy ARP entry: %m");
+ return 0;
+ }
+
+ proxy_arp_addr = 0;
+ return 1;
+}
+
+/*
+ * get_ether_addr - get the hardware address of an interface on the
+ * the same subnet as ipaddr.
+ */
+#define MAX_IFS 32
+
+static int
+get_ether_addr(ipaddr, hwaddr)
+ u_int32_t ipaddr;
+ struct sockaddr *hwaddr;
+{
+ struct ifreq *ifr, *ifend;
+ u_int32_t ina, mask;
+ struct ifreq ifreq;
+ struct ifconf ifc;
+ struct ifreq ifs[MAX_IFS];
+ int nit_fd;
+
+ ifc.ifc_len = sizeof(ifs);
+ ifc.ifc_req = ifs;
+ if (ioctl(sockfd, SIOCGIFCONF, &ifc) < 0) {
+ error("ioctl(SIOCGIFCONF): %m");
+ return 0;
+ }
+
+ /*
+ * Scan through looking for an interface with an Internet
+ * address on the same subnet as `ipaddr'.
+ */
+ ifend = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len);
+ for (ifr = ifc.ifc_req; ifr < ifend; ifr = (struct ifreq *)
+ ((char *)&ifr->ifr_addr + sizeof(struct sockaddr))) {
+ if (ifr->ifr_addr.sa_family == AF_INET) {
+
+ /*
+ * Check that the interface is up, and not point-to-point
+ * or loopback.
+ */
+ strlcpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name));
+ if (ioctl(sockfd, SIOCGIFFLAGS, &ifreq) < 0)
+ continue;
+ if ((ifreq.ifr_flags &
+ (IFF_UP|IFF_BROADCAST|IFF_POINTOPOINT|IFF_LOOPBACK|IFF_NOARP))
+ != (IFF_UP|IFF_BROADCAST))
+ continue;
+
+ /*
+ * Get its netmask and check that it's on the right subnet.
+ */
+ if (ioctl(sockfd, SIOCGIFNETMASK, &ifreq) < 0)
+ continue;
+ ina = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr.s_addr;
+ mask = ((struct sockaddr_in *) &ifreq.ifr_addr)->sin_addr.s_addr;
+ if ((ipaddr & mask) != (ina & mask))
+ continue;
+
+ break;
+ }
+ }
+
+ if (ifr >= ifend)
+ return 0;
+ info("found interface %s for proxy arp", ifr->ifr_name);
+
+ /*
+ * Grab the physical address for this interface.
+ */
+ if ((nit_fd = open("/dev/nit", O_RDONLY)) < 0) {
+ error("Couldn't open /dev/nit: %m");
+ return 0;
+ }
+ strlcpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name));
+ if (ioctl(nit_fd, NIOCBIND, &ifreq) < 0
+ || ioctl(nit_fd, SIOCGIFADDR, &ifreq) < 0) {
+ error("Couldn't get hardware address for %s: %m",
+ ifreq.ifr_name);
+ close(nit_fd);
+ return 0;
+ }
+
+ hwaddr->sa_family = AF_UNSPEC;
+ memcpy(hwaddr->sa_data, ifreq.ifr_addr.sa_data, 6);
+ close(nit_fd);
+ return 1;
+}
+
+/*
+ * have_route_to - determine if the system has any route to
+ * a given IP address.
+ * For demand mode to work properly, we have to ignore routes
+ * through our own interface.
+ */
+int have_route_to(addr)
+ u_int32_t addr;
+{
+ return -1;
+}
+
+#define WTMPFILE "/usr/adm/wtmp"
+
+void
+logwtmp(line, name, host)
+ const char *line, *name, *host;
+{
+ int fd;
+ struct stat buf;
+ struct utmp ut;
+
+ if ((fd = open(WTMPFILE, O_WRONLY|O_APPEND, 0)) < 0)
+ return;
+ if (!fstat(fd, &buf)) {
+ strncpy(ut.ut_line, line, sizeof(ut.ut_line));
+ strncpy(ut.ut_name, name, sizeof(ut.ut_name));
+ strncpy(ut.ut_host, host, sizeof(ut.ut_host));
+ (void)time(&ut.ut_time);
+ if (write(fd, (char *)&ut, sizeof(struct utmp)) != sizeof(struct utmp))
+ (void)ftruncate(fd, buf.st_size);
+ }
+ close(fd);
+}
+
+/*
+ * Return user specified netmask, modified by any mask we might determine
+ * for address `addr' (in network byte order).
+ * Here we scan through the system's list of interfaces, looking for
+ * any non-point-to-point interfaces which might appear to be on the same
+ * network as `addr'. If we find any, we OR in their netmask to the
+ * user-specified netmask.
+ */
+u_int32_t
+GetMask(addr)
+ u_int32_t addr;
+{
+ u_int32_t mask, nmask, ina;
+ struct ifreq *ifr, *ifend, ifreq;
+ struct ifconf ifc;
+
+ addr = ntohl(addr);
+ if (IN_CLASSA(addr)) /* determine network mask for address class */
+ nmask = IN_CLASSA_NET;
+ else if (IN_CLASSB(addr))
+ nmask = IN_CLASSB_NET;
+ else
+ nmask = IN_CLASSC_NET;
+ /* class D nets are disallowed by bad_ip_adrs */
+ mask = netmask | htonl(nmask);
+
+ /*
+ * Scan through the system's network interfaces.
+ */
+ ifc.ifc_len = MAX_IFS * sizeof(struct ifreq);
+ ifc.ifc_req = alloca(ifc.ifc_len);
+ if (ifc.ifc_req == 0)
+ return mask;
+ if (ioctl(sockfd, SIOCGIFCONF, &ifc) < 0) {
+ warn("Couldn't get system interface list: %m");
+ return mask;
+ }
+ ifend = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len);
+ for (ifr = ifc.ifc_req; ifr < ifend; ++ifr) {
+ /*
+ * Check the interface's internet address.
+ */
+ if (ifr->ifr_addr.sa_family != AF_INET)
+ continue;
+ ina = INET_ADDR(ifr->ifr_addr);
+ if ((ntohl(ina) & nmask) != (addr & nmask))
+ continue;
+ /*
+ * Check that the interface is up, and not point-to-point or loopback.
+ */
+ strlcpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name));
+ if (ioctl(sockfd, SIOCGIFFLAGS, &ifreq) < 0)
+ continue;
+ if ((ifreq.ifr_flags & (IFF_UP|IFF_POINTOPOINT|IFF_LOOPBACK))
+ != IFF_UP)
+ continue;
+ /*
+ * Get its netmask and OR it into our mask.
+ */
+ if (ioctl(sockfd, SIOCGIFNETMASK, &ifreq) < 0)
+ continue;
+ mask |= INET_ADDR(ifreq.ifr_addr);
+ }
+
+ return mask;
+}
+
+static int
+strioctl(fd, cmd, ptr, ilen, olen)
+ int fd, cmd, ilen, olen;
+ void *ptr;
+{
+ struct strioctl str;
+
+ str.ic_cmd = cmd;
+ str.ic_timout = 0;
+ str.ic_len = ilen;
+ str.ic_dp = ptr;
+ if (ioctl(fd, I_STR, &str) == -1)
+ return -1;
+ if (str.ic_len != olen)
+ dbglog("strioctl: expected %d bytes, got %d for cmd %x\n",
+ olen, str.ic_len, cmd);
+ return 0;
+}
+
+/*
+ * Use the hostid as part of the random number seed.
+ */
+int
+get_host_seed()
+{
+ return gethostid();
+}
+
+#if 0
+/*
+ * Code for locking/unlocking the serial device.
+ * This code is derived from chat.c.
+ */
+
+#if !defined(HDB) && !defined(SUNOS3)
+#define HDB 1 /* ascii lock files are the default */
+#endif
+
+#ifndef LOCK_DIR
+# if HDB
+# define PIDSTRING
+# define LOCK_PREFIX "/usr/spool/locks/LCK.."
+# else /* HDB */
+# define LOCK_PREFIX "/usr/spool/uucp/LCK.."
+# endif /* HDB */
+#endif /* LOCK_DIR */
+
+static char *lock_file; /* name of lock file created */
+
+/*
+ * lock - create a lock file for the named device.
+ */
+int
+lock(dev)
+ char *dev;
+{
+ char hdb_lock_buffer[12];
+ int fd, pid, n;
+ char *p;
+ size_t l;
+
+ if ((p = strrchr(dev, '/')) != NULL)
+ dev = p + 1;
+ l = strlen(LOCK_PREFIX) + strlen(dev) + 1;
+ lock_file = malloc(l);
+ if (lock_file == NULL)
+ novm("lock file name");
+ slprintf(lock_file, l, "%s%s", LOCK_PREFIX, dev);
+
+ while ((fd = open(lock_file, O_EXCL | O_CREAT | O_RDWR, 0644)) < 0) {
+ if (errno == EEXIST
+ && (fd = open(lock_file, O_RDONLY, 0)) >= 0) {
+ /* Read the lock file to find out who has the device locked */
+#ifdef PIDSTRING
+ n = read(fd, hdb_lock_buffer, 11);
+ if (n > 0) {
+ hdb_lock_buffer[n] = 0;
+ pid = atoi(hdb_lock_buffer);
+ }
+#else
+ n = read(fd, &pid, sizeof(pid));
+#endif
+ if (n <= 0) {
+ error("Can't read pid from lock file %s", lock_file);
+ close(fd);
+ } else {
+ if (kill(pid, 0) == -1 && errno == ESRCH) {
+ /* pid no longer exists - remove the lock file */
+ if (unlink(lock_file) == 0) {
+ close(fd);
+ notice("Removed stale lock on %s (pid %d)",
+ dev, pid);
+ continue;
+ } else
+ warn("Couldn't remove stale lock on %s",
+ dev);
+ } else
+ notice("Device %s is locked by pid %d",
+ dev, pid);
+ }
+ close(fd);
+ } else
+ error("Can't create lock file %s: %m", lock_file);
+ free(lock_file);
+ lock_file = NULL;
+ return -1;
+ }
+
+#ifdef PIDSTRING
+ slprintf(hdb_lock_buffer, sizeof(hdb_lock_buffer), "%10d\n", getpid());
+ write(fd, hdb_lock_buffer, 11);
+#else
+ pid = getpid();
+ write(fd, &pid, sizeof pid);
+#endif
+
+ close(fd);
+ return 0;
+}
+
+/*
+ * unlock - remove our lockfile
+ */
+void
+unlock()
+{
+ if (lock_file) {
+ unlink(lock_file);
+ free(lock_file);
+ lock_file = NULL;
+ }
+}
+#endif /* lock stuff removed */
+
+/*
+ * get_pty - get a pty master/slave pair and chown the slave side
+ * to the uid given. Assumes slave_name points to >= 12 bytes of space.
+ */
+int
+get_pty(master_fdp, slave_fdp, slave_name, uid)
+ int *master_fdp;
+ int *slave_fdp;
+ char *slave_name;
+ int uid;
+{
+ int i, mfd, sfd;
+ char pty_name[12];
+ struct termios tios;
+
+ sfd = -1;
+ for (i = 0; i < 64; ++i) {
+ slprintf(pty_name, sizeof(pty_name), "/dev/pty%c%x",
+ 'p' + i / 16, i % 16);
+ mfd = open(pty_name, O_RDWR, 0);
+ if (mfd >= 0) {
+ pty_name[5] = 't';
+ sfd = open(pty_name, O_RDWR | O_NOCTTY, 0);
+ if (sfd >= 0)
+ break;
+ close(mfd);
+ }
+ }
+ if (sfd < 0)
+ return 0;
+
+ strlcpy(slave_name, pty_name, 12);
+ *master_fdp = mfd;
+ *slave_fdp = sfd;
+ fchown(sfd, uid, -1);
+ fchmod(sfd, S_IRUSR | S_IWUSR);
+ if (tcgetattr(sfd, &tios) == 0) {
+ tios.c_cflag &= ~(CSIZE | CSTOPB | PARENB);
+ tios.c_cflag |= CS8 | CREAD;
+ tios.c_iflag = IGNPAR | CLOCAL;
+ tios.c_oflag = 0;
+ tios.c_lflag = 0;
+ if (tcsetattr(sfd, TCSAFLUSH, &tios) < 0)
+ warn("couldn't set attributes on pty: %m");
+ } else
+ warn("couldn't get attributes on pty: %m");
+
+ return 1;
+}
+
+/*
+ * SunOS doesn't have strtoul :-(
+ */
+unsigned long
+strtoul(str, ptr, base)
+ char *str, **ptr;
+ int base;
+{
+ return (unsigned long) strtol(str, ptr, base);
+}
+
+/*
+ * Or strerror :-(
+ */
+extern char *sys_errlist[];
+extern int sys_nerr;
+
+char *
+strerror(n)
+ int n;
+{
+ static char unknown[32];
+
+ if (n > 0 && n < sys_nerr)
+ return sys_errlist[n];
+ slprintf(unknown, sizeof(unknown), "Error %d", n);
+ return unknown;
+}
diff --git a/mdk-stage1/ppp/pppd/tdb.c b/mdk-stage1/ppp/pppd/tdb.c
new file mode 100644
index 000000000..7fd58291e
--- /dev/null
+++ b/mdk-stage1/ppp/pppd/tdb.c
@@ -0,0 +1,1282 @@
+/*
+ * Database functions
+ * Copyright (C) Andrew Tridgell 1999
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms AND provided that this software or
+ * any derived work is only used as part of the PPP daemon (pppd)
+ * and related utilities.
+ * The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Note: this software is also available under the Gnu Public License
+ * version 2 or later.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include "tdb.h"
+
+#define TDB_VERSION (0x26011967 + 1)
+#define TDB_MAGIC (0x26011999U)
+#define TDB_FREE_MAGIC (~TDB_MAGIC)
+#define TDB_ALIGN 4
+#define MIN_REC_SIZE (2*sizeof(struct list_struct) + TDB_ALIGN)
+#define DEFAULT_HASH_SIZE 128
+#define TDB_PAGE_SIZE 0x2000
+#define TDB_LEN_MULTIPLIER 10
+#define FREELIST_TOP (sizeof(struct tdb_header))
+
+#define LOCK_SET 1
+#define LOCK_CLEAR 0
+
+/* lock offsets */
+#define GLOBAL_LOCK 0
+#define ACTIVE_LOCK 4
+#define LIST_LOCK_BASE 1024
+
+#define BUCKET(hash) ((hash) % tdb->header.hash_size)
+
+#ifndef MAP_FILE
+#define MAP_FILE 0
+#endif
+
+/* the body of the database is made of one list_struct for the free space
+ plus a separate data list for each hash value */
+struct list_struct {
+ tdb_len rec_len; /* total byte length of record */
+ tdb_off next; /* offset of the next record in the list */
+ tdb_len key_len; /* byte length of key */
+ tdb_len data_len; /* byte length of data */
+ unsigned full_hash; /* the full 32 bit hash of the key */
+ unsigned magic; /* try to catch errors */
+ /*
+ the following union is implied
+ union {
+ char record[rec_len];
+ struct {
+ char key[key_len];
+ char data[data_len];
+ }
+ }
+ */
+};
+
+/* a null data record - useful for error returns */
+static TDB_DATA null_data;
+
+/* a byte range locking function - return 0 on success
+ this functions locks/unlocks 1 byte at the specified offset */
+static int tdb_brlock(TDB_CONTEXT *tdb, tdb_off offset,
+ int set, int rw_type, int lck_type)
+{
+#if NOLOCK
+ return 0;
+#else
+ struct flock fl;
+
+ if (tdb->fd == -1) return 0; /* for in memory tdb */
+
+ if (tdb->read_only) return -1;
+
+ fl.l_type = set==LOCK_SET?rw_type:F_UNLCK;
+ fl.l_whence = SEEK_SET;
+ fl.l_start = offset;
+ fl.l_len = 1;
+ fl.l_pid = 0;
+
+ if (fcntl(tdb->fd, lck_type, &fl) != 0) {
+#if TDB_DEBUG
+ if (lck_type == F_SETLKW) {
+ printf("lock %d failed at %d (%s)\n",
+ set, offset, strerror(errno));
+ }
+#endif
+ tdb->ecode = TDB_ERR_LOCK;
+ return -1;
+ }
+ return 0;
+#endif
+}
+
+/* lock a list in the database. list -1 is the alloc list */
+static int tdb_lock(TDB_CONTEXT *tdb, int list)
+{
+ if (list < -1 || list >= (int)tdb->header.hash_size) {
+#if TDB_DEBUG
+ printf("bad list %d\n", list);
+#endif
+ return -1;
+ }
+ if (tdb->locked[list+1] == 0) {
+ if (tdb_brlock(tdb, LIST_LOCK_BASE + 4*list, LOCK_SET,
+ F_WRLCK, F_SETLKW) != 0) {
+ return -1;
+ }
+ }
+ tdb->locked[list+1]++;
+ return 0;
+}
+
+/* unlock the database. */
+static int tdb_unlock(TDB_CONTEXT *tdb, int list)
+{
+ if (list < -1 || list >= (int)tdb->header.hash_size) {
+#if TDB_DEBUG
+ printf("bad unlock list %d\n", list);
+#endif
+ return -1;
+ }
+
+ if (tdb->locked[list+1] == 0) {
+#if TDB_DEBUG
+ printf("not locked %d\n", list);
+#endif
+ tdb->ecode = TDB_ERR_LOCK;
+ return -1;
+ }
+ if (tdb->locked[list+1] == 1) {
+ if (tdb_brlock(tdb, LIST_LOCK_BASE + 4*list, LOCK_CLEAR,
+ F_WRLCK, F_SETLKW) != 0) {
+ return -1;
+ }
+ }
+ tdb->locked[list+1]--;
+ return 0;
+}
+
+/* the hash algorithm - turn a key into an integer
+ This is based on the hash agorithm from gdbm */
+static unsigned tdb_hash(TDB_DATA *key)
+{
+ unsigned value; /* Used to compute the hash value. */
+ unsigned i; /* Used to cycle through random values. */
+
+ /* Set the initial value from the key size. */
+ value = 0x238F13AF * key->dsize;
+ for (i=0; i < key->dsize; i++) {
+ value = (value + (key->dptr[i] << (i*5 % 24)));
+ }
+
+ value = (1103515243 * value + 12345);
+
+ return value;
+}
+
+/* find the top of the hash chain for an open database */
+static tdb_off tdb_hash_top(TDB_CONTEXT *tdb, unsigned hash)
+{
+ tdb_off ret;
+ hash = BUCKET(hash);
+ ret = FREELIST_TOP + (hash+1)*sizeof(tdb_off);
+ return ret;
+}
+
+
+/* check for an out of bounds access - if it is out of bounds then
+ see if the database has been expanded by someone else and expand
+ if necessary */
+static int tdb_oob(TDB_CONTEXT *tdb, tdb_off offset)
+{
+ struct stat st;
+ if ((offset <= tdb->map_size) || (tdb->fd == -1)) return 0;
+
+ fstat(tdb->fd, &st);
+ if (st.st_size <= (ssize_t)offset) {
+ tdb->ecode = TDB_ERR_IO;
+ return -1;
+ }
+
+#if HAVE_MMAP
+ if (tdb->map_ptr) {
+ munmap(tdb->map_ptr, tdb->map_size);
+ tdb->map_ptr = NULL;
+ }
+#endif
+
+ tdb->map_size = st.st_size;
+#if HAVE_MMAP
+ tdb->map_ptr = (void *)mmap(NULL, tdb->map_size,
+ tdb->read_only?PROT_READ:PROT_READ|PROT_WRITE,
+ MAP_SHARED | MAP_FILE, tdb->fd, 0);
+#endif
+ return 0;
+}
+
+
+/* write a lump of data at a specified offset */
+static int tdb_write(TDB_CONTEXT *tdb, tdb_off offset, const char *buf, tdb_len len)
+{
+ if (tdb_oob(tdb, offset + len) != 0) {
+ /* oops - trying to write beyond the end of the database! */
+ return -1;
+ }
+
+ if (tdb->map_ptr) {
+ memcpy(offset + (char *)tdb->map_ptr, buf, len);
+ } else {
+ if (lseek(tdb->fd, offset, SEEK_SET) != offset ||
+ write(tdb->fd, buf, len) != (ssize_t)len) {
+ tdb->ecode = TDB_ERR_IO;
+ return -1;
+ }
+ }
+ return 0;
+}
+
+/* read a lump of data at a specified offset */
+static int tdb_read(TDB_CONTEXT *tdb, tdb_off offset, char *buf, tdb_len len)
+{
+ if (tdb_oob(tdb, offset + len) != 0) {
+ /* oops - trying to read beyond the end of the database! */
+ return -1;
+ }
+
+ if (tdb->map_ptr) {
+ memcpy(buf, offset + (char *)tdb->map_ptr, len);
+ } else {
+ if (lseek(tdb->fd, offset, SEEK_SET) != offset ||
+ read(tdb->fd, buf, len) != (ssize_t)len) {
+ tdb->ecode = TDB_ERR_IO;
+ return -1;
+ }
+ }
+ return 0;
+}
+
+
+/* read a lump of data, allocating the space for it */
+static char *tdb_alloc_read(TDB_CONTEXT *tdb, tdb_off offset, tdb_len len)
+{
+ char *buf;
+
+ buf = (char *)malloc(len);
+
+ if (!buf) {
+ tdb->ecode = TDB_ERR_OOM;
+ return NULL;
+ }
+
+ if (tdb_read(tdb, offset, buf, len) == -1) {
+ free(buf);
+ return NULL;
+ }
+
+ return buf;
+}
+
+/* convenience routine for writing a record */
+static int rec_write(TDB_CONTEXT *tdb, tdb_off offset, struct list_struct *rec)
+{
+ return tdb_write(tdb, offset, (char *)rec, sizeof(*rec));
+}
+
+/* convenience routine for writing a tdb_off */
+static int ofs_write(TDB_CONTEXT *tdb, tdb_off offset, tdb_off *d)
+{
+ return tdb_write(tdb, offset, (char *)d, sizeof(*d));
+}
+
+/* read a tdb_off from the store */
+static int ofs_read(TDB_CONTEXT *tdb, tdb_off offset, tdb_off *d)
+{
+ return tdb_read(tdb, offset, (char *)d, sizeof(*d));
+}
+
+/* read a record and check for simple errors */
+static int rec_read(TDB_CONTEXT *tdb, tdb_off offset, struct list_struct *rec)
+{
+ if (tdb_read(tdb, offset, (char *)rec, sizeof(*rec)) == -1) return -1;
+ if (rec->magic != TDB_MAGIC) {
+#if TDB_DEBUG
+ printf("bad magic 0x%08x at offset %d\n",
+ rec->magic, offset);
+#endif
+ tdb->ecode = TDB_ERR_CORRUPT;
+ return -1;
+ }
+ if (tdb_oob(tdb, rec->next) != 0) {
+ return -1;
+ }
+ return 0;
+}
+
+/* expand the database at least length bytes by expanding the
+ underlying file and doing the mmap again if necessary */
+static int tdb_expand(TDB_CONTEXT *tdb, tdb_off length)
+{
+ struct list_struct rec;
+ tdb_off offset, ptr;
+ char b = 0;
+
+ tdb_lock(tdb,-1);
+
+ /* make sure we know about any previous expansions by another
+ process */
+ tdb_oob(tdb,tdb->map_size + 1);
+
+ /* always make room for at least 10 more records */
+ length *= TDB_LEN_MULTIPLIER;
+
+ /* and round the database up to a multiple of TDB_PAGE_SIZE */
+ length = ((tdb->map_size + length + TDB_PAGE_SIZE) & ~(TDB_PAGE_SIZE - 1)) - tdb->map_size;
+
+ /* expand the file itself */
+ if (tdb->fd != -1) {
+ lseek(tdb->fd, tdb->map_size + length - 1, SEEK_SET);
+ if (write(tdb->fd, &b, 1) != 1) goto fail;
+ }
+
+ /* form a new freelist record */
+ offset = FREELIST_TOP;
+ rec.rec_len = length - sizeof(rec);
+ rec.magic = TDB_FREE_MAGIC;
+ if (ofs_read(tdb, offset, &rec.next) == -1) {
+ goto fail;
+ }
+
+#if HAVE_MMAP
+ if (tdb->fd != -1 && tdb->map_ptr) {
+ munmap(tdb->map_ptr, tdb->map_size);
+ tdb->map_ptr = NULL;
+ }
+#endif
+
+ tdb->map_size += length;
+
+ if (tdb->fd == -1) {
+ tdb->map_ptr = realloc(tdb->map_ptr, tdb->map_size);
+ }
+
+ /* write it out */
+ if (rec_write(tdb, tdb->map_size - length, &rec) == -1) {
+ goto fail;
+ }
+
+ /* link it into the free list */
+ ptr = tdb->map_size - length;
+ if (ofs_write(tdb, offset, &ptr) == -1) goto fail;
+
+#if HAVE_MMAP
+ if (tdb->fd != -1) {
+ tdb->map_ptr = (void *)mmap(NULL, tdb->map_size,
+ PROT_READ|PROT_WRITE,
+ MAP_SHARED | MAP_FILE, tdb->fd, 0);
+ }
+#endif
+
+ tdb_unlock(tdb, -1);
+ return 0;
+
+ fail:
+ tdb_unlock(tdb,-1);
+ return -1;
+}
+
+/* allocate some space from the free list. The offset returned points
+ to a unconnected list_struct within the database with room for at
+ least length bytes of total data
+
+ 0 is returned if the space could not be allocated
+ */
+static tdb_off tdb_allocate(TDB_CONTEXT *tdb, tdb_len length)
+{
+ tdb_off offset, rec_ptr, last_ptr;
+ struct list_struct rec, lastrec, newrec;
+
+ tdb_lock(tdb, -1);
+
+ again:
+ last_ptr = 0;
+ offset = FREELIST_TOP;
+
+ /* read in the freelist top */
+ if (ofs_read(tdb, offset, &rec_ptr) == -1) {
+ goto fail;
+ }
+
+ /* keep looking until we find a freelist record that is big
+ enough */
+ while (rec_ptr) {
+ if (tdb_read(tdb, rec_ptr, (char *)&rec, sizeof(rec)) == -1) {
+ goto fail;
+ }
+
+ if (rec.magic != TDB_FREE_MAGIC) {
+#if TDB_DEBUG
+ printf("bad magic 0x%08x in free list\n", rec.magic);
+#endif
+ goto fail;
+ }
+
+ if (rec.rec_len >= length) {
+ /* found it - now possibly split it up */
+ if (rec.rec_len > length + MIN_REC_SIZE) {
+ length = (length + TDB_ALIGN) & ~(TDB_ALIGN-1);
+
+ newrec.rec_len = rec.rec_len - (sizeof(rec) + length);
+ newrec.next = rec.next;
+ newrec.magic = TDB_FREE_MAGIC;
+
+ rec.rec_len = length;
+ rec.next = rec_ptr + sizeof(rec) + rec.rec_len;
+
+ if (rec_write(tdb, rec.next, &newrec) == -1) {
+ goto fail;
+ }
+
+ if (rec_write(tdb, rec_ptr, &rec) == -1) {
+ goto fail;
+ }
+ }
+
+ /* remove it from the list */
+ if (last_ptr == 0) {
+ offset = FREELIST_TOP;
+
+ if (ofs_write(tdb, offset, &rec.next) == -1) {
+ goto fail;
+ }
+ } else {
+ lastrec.next = rec.next;
+ if (rec_write(tdb, last_ptr, &lastrec) == -1) {
+ goto fail;
+ }
+ }
+
+ /* all done - return the new record offset */
+ tdb_unlock(tdb, -1);
+ return rec_ptr;
+ }
+
+ /* move to the next record */
+ lastrec = rec;
+ last_ptr = rec_ptr;
+ rec_ptr = rec.next;
+ }
+
+ /* we didn't find enough space. See if we can expand the
+ database and if we can then try again */
+ if (tdb_expand(tdb, length + sizeof(rec)) == 0) goto again;
+
+ fail:
+#if TDB_DEBUG
+ printf("tdb_allocate failed for size %u\n", length);
+#endif
+ tdb_unlock(tdb, -1);
+ return 0;
+}
+
+/* initialise a new database with a specified hash size */
+static int tdb_new_database(TDB_CONTEXT *tdb, int hash_size)
+{
+ struct tdb_header header;
+ tdb_off offset;
+ int i, size = 0;
+ tdb_off buf[16];
+
+ /* create the header */
+ memset(&header, 0, sizeof(header));
+ memcpy(header.magic_food, TDB_MAGIC_FOOD, strlen(TDB_MAGIC_FOOD)+1);
+ header.version = TDB_VERSION;
+ header.hash_size = hash_size;
+ lseek(tdb->fd, 0, SEEK_SET);
+ ftruncate(tdb->fd, 0);
+
+ if (tdb->fd != -1 && write(tdb->fd, &header, sizeof(header)) !=
+ sizeof(header)) {
+ tdb->ecode = TDB_ERR_IO;
+ return -1;
+ } else size += sizeof(header);
+
+ /* the freelist and hash pointers */
+ offset = 0;
+ memset(buf, 0, sizeof(buf));
+
+ for (i=0;(hash_size+1)-i >= 16; i += 16) {
+ if (tdb->fd != -1 && write(tdb->fd, buf, sizeof(buf)) !=
+ sizeof(buf)) {
+ tdb->ecode = TDB_ERR_IO;
+ return -1;
+ } else size += sizeof(buf);
+ }
+
+ for (;i<hash_size+1; i++) {
+ if (tdb->fd != -1 && write(tdb->fd, buf, sizeof(tdb_off)) !=
+ sizeof(tdb_off)) {
+ tdb->ecode = TDB_ERR_IO;
+ return -1;
+ } else size += sizeof(tdb_off);
+ }
+
+ if (tdb->fd == -1) {
+ tdb->map_ptr = calloc(size, 1);
+ tdb->map_size = size;
+ if (tdb->map_ptr == NULL) {
+ tdb->ecode = TDB_ERR_IO;
+ return -1;
+ }
+ memcpy(&tdb->header, &header, sizeof(header));
+ }
+
+#if TDB_DEBUG
+ printf("initialised database of hash_size %u\n",
+ hash_size);
+#endif
+ return 0;
+}
+
+/* Returns 0 on fail. On success, return offset of record, and fills
+ in rec */
+static tdb_off tdb_find(TDB_CONTEXT *tdb, TDB_DATA key, unsigned int hash,
+ struct list_struct *rec)
+{
+ tdb_off offset, rec_ptr;
+
+ /* find the top of the hash chain */
+ offset = tdb_hash_top(tdb, hash);
+
+ /* read in the hash top */
+ if (ofs_read(tdb, offset, &rec_ptr) == -1)
+ return 0;
+
+ /* keep looking until we find the right record */
+ while (rec_ptr) {
+ if (rec_read(tdb, rec_ptr, rec) == -1)
+ return 0;
+
+ if (hash == rec->full_hash && key.dsize == rec->key_len) {
+ char *k;
+ /* a very likely hit - read the key */
+ k = tdb_alloc_read(tdb, rec_ptr + sizeof(*rec),
+ rec->key_len);
+
+ if (!k)
+ return 0;
+
+ if (memcmp(key.dptr, k, key.dsize) == 0) {
+ free(k);
+ return rec_ptr;
+ }
+ free(k);
+ }
+
+ /* move to the next record */
+ rec_ptr = rec->next;
+ }
+ return 0;
+}
+
+/*
+ return an error string for the last tdb error
+*/
+char *tdb_error(TDB_CONTEXT *tdb)
+{
+ int i;
+ static struct {
+ enum TDB_ERROR ecode;
+ char *estring;
+ } emap[] = {
+ {TDB_SUCCESS, "Success"},
+ {TDB_ERR_CORRUPT, "Corrupt database"},
+ {TDB_ERR_IO, "IO Error"},
+ {TDB_ERR_LOCK, "Locking error"},
+ {TDB_ERR_OOM, "Out of memory"},
+ {TDB_ERR_EXISTS, "Record exists"},
+ {-1, NULL}};
+ if (tdb != NULL) {
+ for (i=0;emap[i].estring;i++) {
+ if (tdb->ecode == emap[i].ecode) return emap[i].estring;
+ }
+ } else {
+ return "Invalid tdb context";
+ }
+ return "Invalid error code";
+}
+
+
+/* update an entry in place - this only works if the new data size
+ is <= the old data size and the key exists.
+ on failure return -1
+*/
+int tdb_update(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf)
+{
+ unsigned hash;
+ struct list_struct rec;
+ tdb_off rec_ptr;
+ int ret = -1;
+
+ if (tdb == NULL) {
+#ifdef TDB_DEBUG
+ printf("tdb_update() called with null context\n");
+#endif
+ return -1;
+ }
+
+ /* find which hash bucket it is in */
+ hash = tdb_hash(&key);
+
+ tdb_lock(tdb, BUCKET(hash));
+ rec_ptr = tdb_find(tdb, key, hash, &rec);
+
+ if (!rec_ptr)
+ goto out;
+
+ /* must be long enough */
+ if (rec.rec_len < key.dsize + dbuf.dsize)
+ goto out;
+
+ if (tdb_write(tdb, rec_ptr + sizeof(rec) + rec.key_len,
+ dbuf.dptr, dbuf.dsize) == -1)
+ goto out;
+
+ if (dbuf.dsize != rec.data_len) {
+ /* update size */
+ rec.data_len = dbuf.dsize;
+ ret = rec_write(tdb, rec_ptr, &rec);
+ } else
+ ret = 0;
+
+ out:
+ tdb_unlock(tdb, BUCKET(hash));
+ return ret;
+}
+
+/* find an entry in the database given a key */
+TDB_DATA tdb_fetch(TDB_CONTEXT *tdb, TDB_DATA key)
+{
+ unsigned hash;
+ tdb_off rec_ptr;
+ struct list_struct rec;
+ TDB_DATA ret = null_data;
+
+ if (tdb == NULL) {
+#ifdef TDB_DEBUG
+ printf("tdb_fetch() called with null context\n");
+#endif
+ return null_data;
+ }
+
+ /* find which hash bucket it is in */
+ hash = tdb_hash(&key);
+
+ tdb_lock(tdb, BUCKET(hash));
+ rec_ptr = tdb_find(tdb, key, hash, &rec);
+
+ if (rec_ptr) {
+ ret.dptr = tdb_alloc_read(tdb,
+ rec_ptr + sizeof(rec) + rec.key_len,
+ rec.data_len);
+ ret.dsize = rec.data_len;
+ }
+
+ tdb_unlock(tdb, BUCKET(hash));
+ return ret;
+}
+
+/* check if an entry in the database exists
+
+ note that 1 is returned if the key is found and 0 is returned if not found
+ this doesn't match the conventions in the rest of this module, but is
+ compatible with gdbm
+*/
+int tdb_exists(TDB_CONTEXT *tdb, TDB_DATA key)
+{
+ unsigned hash;
+ tdb_off rec_ptr;
+ struct list_struct rec;
+
+ if (tdb == NULL) {
+#ifdef TDB_DEBUG
+ printf("tdb_exists() called with null context\n");
+#endif
+ return 0;
+ }
+
+ /* find which hash bucket it is in */
+ hash = tdb_hash(&key);
+
+ tdb_lock(tdb, BUCKET(hash));
+ rec_ptr = tdb_find(tdb, key, hash, &rec);
+ tdb_unlock(tdb, BUCKET(hash));
+
+ return rec_ptr != 0;
+}
+
+/* traverse the entire database - calling fn(tdb, key, data) on each element.
+ return -1 on error or the record count traversed
+ if fn is NULL then it is not called
+ a non-zero return value from fn() indicates that the traversal should stop
+ */
+int tdb_traverse(TDB_CONTEXT *tdb, int (*fn)(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf, void* state), void* state)
+{
+ int count = 0;
+ unsigned h;
+ tdb_off offset, rec_ptr;
+ struct list_struct rec;
+ char *data;
+ TDB_DATA key, dbuf;
+
+ if (tdb == NULL) {
+#ifdef TDB_DEBUG
+ printf("tdb_traverse() called with null context\n");
+#endif
+ return -1;
+ }
+
+ /* loop over all hash chains */
+ for (h = 0; h < tdb->header.hash_size; h++) {
+ tdb_lock(tdb, BUCKET(h));
+
+ /* read in the hash top */
+ offset = tdb_hash_top(tdb, h);
+ if (ofs_read(tdb, offset, &rec_ptr) == -1) {
+ goto fail;
+ }
+
+ /* traverse all records for this hash */
+ while (rec_ptr) {
+ if (rec_read(tdb, rec_ptr, &rec) == -1) {
+ goto fail;
+ }
+
+ /* now read the full record */
+ data = tdb_alloc_read(tdb, rec_ptr + sizeof(rec),
+ rec.key_len + rec.data_len);
+ if (!data) {
+ goto fail;
+ }
+
+ key.dptr = data;
+ key.dsize = rec.key_len;
+ dbuf.dptr = data + rec.key_len;
+ dbuf.dsize = rec.data_len;
+ count++;
+
+ if (fn && fn(tdb, key, dbuf, state) != 0) {
+ /* they want us to stop traversing */
+ free(data);
+ tdb_unlock(tdb, BUCKET(h));
+ return count;
+ }
+
+ /* a miss - drat */
+ free(data);
+
+ /* move to the next record */
+ rec_ptr = rec.next;
+ }
+ tdb_unlock(tdb, BUCKET(h));
+ }
+
+ /* return the number traversed */
+ return count;
+
+ fail:
+ tdb_unlock(tdb, BUCKET(h));
+ return -1;
+}
+
+
+/* find the first entry in the database and return its key */
+TDB_DATA tdb_firstkey(TDB_CONTEXT *tdb)
+{
+ tdb_off offset, rec_ptr;
+ struct list_struct rec;
+ unsigned hash;
+ TDB_DATA ret;
+
+ if (tdb == NULL) {
+#ifdef TDB_DEBUG
+ printf("tdb_firstkey() called with null context\n");
+#endif
+ return null_data;
+ }
+
+ /* look for a non-empty hash chain */
+ for (hash = 0, rec_ptr = 0;
+ hash < tdb->header.hash_size;
+ hash++) {
+ /* find the top of the hash chain */
+ offset = tdb_hash_top(tdb, hash);
+
+ tdb_lock(tdb, BUCKET(hash));
+
+ /* read in the hash top */
+ if (ofs_read(tdb, offset, &rec_ptr) == -1) {
+ goto fail;
+ }
+
+ if (rec_ptr) break;
+
+ tdb_unlock(tdb, BUCKET(hash));
+ }
+
+ if (rec_ptr == 0) return null_data;
+
+ /* we've found a non-empty chain, now read the record */
+ if (rec_read(tdb, rec_ptr, &rec) == -1) {
+ goto fail;
+ }
+
+ /* allocate and read the key space */
+ ret.dptr = tdb_alloc_read(tdb, rec_ptr + sizeof(rec), rec.key_len);
+ ret.dsize = rec.key_len;
+ tdb_unlock(tdb, BUCKET(hash));
+ return ret;
+
+ fail:
+ tdb_unlock(tdb, BUCKET(hash));
+ return null_data;
+}
+
+/* find the next entry in the database, returning its key */
+TDB_DATA tdb_nextkey(TDB_CONTEXT *tdb, TDB_DATA key)
+{
+ unsigned hash, hbucket;
+ tdb_off rec_ptr, offset;
+ struct list_struct rec;
+ TDB_DATA ret;
+
+ if (tdb == NULL) {
+#ifdef TDB_DEBUG
+ printf("tdb_nextkey() called with null context\n");
+#endif
+ return null_data;
+ }
+
+ /* find which hash bucket it is in */
+ hash = tdb_hash(&key);
+ hbucket = BUCKET(hash);
+
+ tdb_lock(tdb, hbucket);
+ rec_ptr = tdb_find(tdb, key, hash, &rec);
+ if (rec_ptr) {
+ /* we want the next record after this one */
+ rec_ptr = rec.next;
+ }
+
+ /* not found or last in hash: look for next non-empty hash chain */
+ while (rec_ptr == 0) {
+ tdb_unlock(tdb, hbucket);
+
+ if (++hbucket >= tdb->header.hash_size - 1)
+ return null_data;
+
+ offset = tdb_hash_top(tdb, hbucket);
+ tdb_lock(tdb, hbucket);
+ /* read in the hash top */
+ if (ofs_read(tdb, offset, &rec_ptr) == -1) {
+ tdb_unlock(tdb, hbucket);
+ return null_data;
+ }
+ }
+
+ /* Read the record. */
+ if (rec_read(tdb, rec_ptr, &rec) == -1) {
+ tdb_unlock(tdb, hbucket);
+ return null_data;
+ }
+ /* allocate and read the key */
+ ret.dptr = tdb_alloc_read(tdb, rec_ptr + sizeof(rec), rec.key_len);
+ ret.dsize = rec.key_len;
+ tdb_unlock(tdb, hbucket);
+
+ return ret;
+}
+
+/* delete an entry in the database given a key */
+int tdb_delete(TDB_CONTEXT *tdb, TDB_DATA key)
+{
+ unsigned hash;
+ tdb_off offset, rec_ptr, last_ptr;
+ struct list_struct rec, lastrec;
+ char *data = NULL;
+
+ if (tdb == NULL) {
+#ifdef TDB_DEBUG
+ printf("tdb_delete() called with null context\n");
+#endif
+ return -1;
+ }
+
+ /* find which hash bucket it is in */
+ hash = tdb_hash(&key);
+
+ tdb_lock(tdb, BUCKET(hash));
+
+ /* find the top of the hash chain */
+ offset = tdb_hash_top(tdb, hash);
+
+ /* read in the hash top */
+ if (ofs_read(tdb, offset, &rec_ptr) == -1) {
+ goto fail;
+ }
+
+ last_ptr = 0;
+
+ /* keep looking until we find the right record */
+ while (rec_ptr) {
+ if (rec_read(tdb, rec_ptr, &rec) == -1) {
+ goto fail;
+ }
+
+ if (hash == rec.full_hash && key.dsize == rec.key_len) {
+ /* a very likely hit - read the record and full key */
+ data = tdb_alloc_read(tdb, rec_ptr + sizeof(rec),
+ rec.key_len);
+ if (!data) {
+ goto fail;
+ }
+
+ if (memcmp(key.dptr, data, key.dsize) == 0) {
+ /* a definite match - delete it */
+ if (last_ptr == 0) {
+ offset = tdb_hash_top(tdb, hash);
+ if (ofs_write(tdb, offset, &rec.next) == -1) {
+ goto fail;
+ }
+ } else {
+ lastrec.next = rec.next;
+ if (rec_write(tdb, last_ptr, &lastrec) == -1) {
+ goto fail;
+ }
+ }
+ tdb_unlock(tdb, BUCKET(hash));
+ tdb_lock(tdb, -1);
+ /* and recover the space */
+ offset = FREELIST_TOP;
+ if (ofs_read(tdb, offset, &rec.next) == -1) {
+ goto fail2;
+ }
+ rec.magic = TDB_FREE_MAGIC;
+ if (rec_write(tdb, rec_ptr, &rec) == -1) {
+ goto fail2;
+ }
+ if (ofs_write(tdb, offset, &rec_ptr) == -1) {
+ goto fail2;
+ }
+
+ /* yipee - all done */
+ free(data);
+ tdb_unlock(tdb, -1);
+ return 0;
+ }
+
+ /* a miss - drat */
+ free(data);
+ data = NULL;
+ }
+
+ /* move to the next record */
+ last_ptr = rec_ptr;
+ lastrec = rec;
+ rec_ptr = rec.next;
+ }
+
+ fail:
+ if (data) free(data);
+ tdb_unlock(tdb, BUCKET(hash));
+ return -1;
+
+ fail2:
+ if (data) free(data);
+ tdb_unlock(tdb, -1);
+ return -1;
+}
+
+
+/* store an element in the database, replacing any existing element
+ with the same key
+
+ return 0 on success, -1 on failure
+*/
+int tdb_store(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf, int flag)
+{
+ struct list_struct rec;
+ unsigned hash;
+ tdb_off rec_ptr, offset;
+ char *p = NULL;
+
+ if (tdb == NULL) {
+#ifdef TDB_DEBUG
+ printf("tdb_store() called with null context\n");
+#endif
+ return -1;
+ }
+
+ /* find which hash bucket it is in */
+ hash = tdb_hash(&key);
+
+ /* check for it existing */
+ if (flag == TDB_INSERT && tdb_exists(tdb, key)) {
+ tdb->ecode = TDB_ERR_EXISTS;
+ return -1;
+ }
+
+ /* first try in-place update */
+ if (flag != TDB_INSERT && tdb_update(tdb, key, dbuf) == 0) {
+ return 0;
+ }
+
+ rec_ptr = tdb_allocate(tdb, key.dsize + dbuf.dsize);
+ if (rec_ptr == 0) {
+ return -1;
+ }
+
+ tdb_lock(tdb, BUCKET(hash));
+
+ /* delete any existing record - if it doesn't exist we don't care */
+ if (flag != TDB_INSERT) {
+ tdb_delete(tdb, key);
+ }
+
+ /* read the newly created record */
+ if (tdb_read(tdb, rec_ptr, (char *)&rec, sizeof(rec)) == -1) {
+ goto fail;
+ }
+
+ if (rec.magic != TDB_FREE_MAGIC) goto fail;
+
+ /* find the top of the hash chain */
+ offset = tdb_hash_top(tdb, hash);
+
+ /* read in the hash top diretcly into our next pointer */
+ if (ofs_read(tdb, offset, &rec.next) == -1) {
+ goto fail;
+ }
+
+ rec.key_len = key.dsize;
+ rec.data_len = dbuf.dsize;
+ rec.full_hash = hash;
+ rec.magic = TDB_MAGIC;
+
+ p = (char *)malloc(sizeof(rec) + key.dsize + dbuf.dsize);
+ if (!p) {
+ tdb->ecode = TDB_ERR_OOM;
+ goto fail;
+ }
+
+ memcpy(p, &rec, sizeof(rec));
+ memcpy(p+sizeof(rec), key.dptr, key.dsize);
+ memcpy(p+sizeof(rec)+key.dsize, dbuf.dptr, dbuf.dsize);
+
+ if (tdb_write(tdb, rec_ptr, p, sizeof(rec)+key.dsize+dbuf.dsize) == -1)
+ goto fail;
+
+ free(p);
+ p = NULL;
+
+ /* and point the top of the hash chain at it */
+ if (ofs_write(tdb, offset, &rec_ptr) == -1) goto fail;
+
+ tdb_unlock(tdb, BUCKET(hash));
+ return 0;
+
+ fail:
+#if TDB_DEBUG
+ printf("store failed for hash 0x%08x in bucket %u\n", hash, BUCKET(hash));
+#endif
+ if (p) free(p);
+ tdb_unlock(tdb, BUCKET(hash));
+ return -1;
+}
+
+
+/* open the database, creating it if necessary
+
+ The open_flags and mode are passed straight to the open call on the database
+ file. A flags value of O_WRONLY is invalid
+
+ The hash size is advisory, use zero for a default value.
+
+ return is NULL on error
+*/
+TDB_CONTEXT *tdb_open(char *name, int hash_size, int tdb_flags,
+ int open_flags, mode_t mode)
+{
+ TDB_CONTEXT tdb, *ret;
+ struct stat st;
+
+ memset(&tdb, 0, sizeof(tdb));
+
+ tdb.fd = -1;
+ tdb.name = NULL;
+ tdb.map_ptr = NULL;
+
+ if ((open_flags & O_ACCMODE) == O_WRONLY) {
+ goto fail;
+ }
+
+ if (hash_size == 0) hash_size = DEFAULT_HASH_SIZE;
+
+ tdb.read_only = ((open_flags & O_ACCMODE) == O_RDONLY);
+
+ if (name != NULL) {
+ tdb.fd = open(name, open_flags, mode);
+ if (tdb.fd == -1) {
+ goto fail;
+ }
+ }
+
+ /* ensure there is only one process initialising at once */
+ tdb_brlock(&tdb, GLOBAL_LOCK, LOCK_SET, F_WRLCK, F_SETLKW);
+
+ if (tdb_flags & TDB_CLEAR_IF_FIRST) {
+ /* we need to zero the database if we are the only
+ one with it open */
+ if (tdb_brlock(&tdb, ACTIVE_LOCK, LOCK_SET, F_WRLCK, F_SETLK) == 0) {
+ ftruncate(tdb.fd, 0);
+ tdb_brlock(&tdb, ACTIVE_LOCK, LOCK_CLEAR, F_WRLCK, F_SETLK);
+ }
+ }
+
+ /* leave this lock in place */
+ tdb_brlock(&tdb, ACTIVE_LOCK, LOCK_SET, F_RDLCK, F_SETLKW);
+
+ if (read(tdb.fd, &tdb.header, sizeof(tdb.header)) != sizeof(tdb.header) ||
+ strcmp(tdb.header.magic_food, TDB_MAGIC_FOOD) != 0 ||
+ tdb.header.version != TDB_VERSION) {
+ /* its not a valid database - possibly initialise it */
+ if (!(open_flags & O_CREAT)) {
+ goto fail;
+ }
+ if (tdb_new_database(&tdb, hash_size) == -1) goto fail;
+
+ lseek(tdb.fd, 0, SEEK_SET);
+ if (tdb.fd != -1 && read(tdb.fd, &tdb.header,
+ sizeof(tdb.header)) !=
+ sizeof(tdb.header))
+ goto fail;
+ }
+
+ if (tdb.fd != -1) {
+ fstat(tdb.fd, &st);
+
+ /* map the database and fill in the return structure */
+ tdb.name = (char *)strdup(name);
+ tdb.map_size = st.st_size;
+ }
+
+ tdb.locked = (int *)calloc(tdb.header.hash_size+1,
+ sizeof(tdb.locked[0]));
+ if (!tdb.locked) {
+ goto fail;
+ }
+
+#if HAVE_MMAP
+ if (tdb.fd != -1) {
+ tdb.map_ptr = (void *)mmap(NULL, st.st_size,
+ tdb.read_only? PROT_READ : PROT_READ|PROT_WRITE,
+ MAP_SHARED | MAP_FILE, tdb.fd, 0);
+ }
+#endif
+
+ ret = (TDB_CONTEXT *)malloc(sizeof(tdb));
+ if (!ret) goto fail;
+
+ *ret = tdb;
+
+#if TDB_DEBUG
+ printf("mapped database of hash_size %u map_size=%u\n",
+ hash_size, tdb.map_size);
+#endif
+
+ tdb_brlock(&tdb, GLOBAL_LOCK, LOCK_CLEAR, F_WRLCK, F_SETLKW);
+ return ret;
+
+ fail:
+ if (tdb.name) free(tdb.name);
+ if (tdb.fd != -1) close(tdb.fd);
+ if (tdb.map_ptr) munmap(tdb.map_ptr, tdb.map_size);
+
+ return NULL;
+}
+
+/* close a database */
+int tdb_close(TDB_CONTEXT *tdb)
+{
+ if (!tdb) return -1;
+
+ if (tdb->name) free(tdb->name);
+ if (tdb->fd != -1) close(tdb->fd);
+ if (tdb->locked) free(tdb->locked);
+
+ if (tdb->map_ptr) {
+ if (tdb->fd != -1) {
+ munmap(tdb->map_ptr, tdb->map_size);
+ } else {
+ free(tdb->map_ptr);
+ }
+ }
+
+ memset(tdb, 0, sizeof(*tdb));
+ free(tdb);
+
+ return 0;
+}
+
+/* lock the database. If we already have it locked then don't do anything */
+int tdb_writelock(TDB_CONTEXT *tdb)
+{
+ if (tdb == NULL) {
+#ifdef TDB_DEBUG
+ printf("tdb_writelock() called with null context\n");
+#endif
+ return -1;
+ }
+
+ return tdb_lock(tdb, -1);
+}
+
+/* unlock the database. */
+int tdb_writeunlock(TDB_CONTEXT *tdb)
+{
+ if (tdb == NULL) {
+#ifdef TDB_DEBUG
+ printf("tdb_writeunlock() called with null context\n");
+#endif
+ return -1;
+ }
+
+ return tdb_unlock(tdb, -1);
+}
+
+/* lock one hash chain. This is meant to be used to reduce locking
+ contention - it cannot guarantee how many records will be locked */
+int tdb_lockchain(TDB_CONTEXT *tdb, TDB_DATA key)
+{
+ if (tdb == NULL) {
+#ifdef TDB_DEBUG
+ printf("tdb_lockchain() called with null context\n");
+#endif
+ return -1;
+ }
+
+ return tdb_lock(tdb, BUCKET(tdb_hash(&key)));
+}
+
+
+/* unlock one hash chain */
+int tdb_unlockchain(TDB_CONTEXT *tdb, TDB_DATA key)
+{
+ if (tdb == NULL) {
+#ifdef TDB_DEBUG
+ printf("tdb_unlockchain() called with null context\n");
+#endif
+ return -1;
+ }
+
+ return tdb_unlock(tdb, BUCKET(tdb_hash(&key)));
+}
diff --git a/mdk-stage1/ppp/pppd/tdb.h b/mdk-stage1/ppp/pppd/tdb.h
new file mode 100644
index 000000000..56ae0ac2a
--- /dev/null
+++ b/mdk-stage1/ppp/pppd/tdb.h
@@ -0,0 +1,77 @@
+#define STANDALONE 1
+/*
+ * Database functions
+ * Copyright (C) Andrew Tridgell 1999
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms AND provided that this software or
+ * any derived work is only used as part of the PPP daemon (pppd)
+ * and related utilities.
+ * The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Note: this software is also available under the Gnu Public License
+ * version 2 or later.
+ */
+
+typedef unsigned tdb_len;
+typedef unsigned tdb_off;
+
+#define TDB_MAGIC_FOOD "TDB file\n"
+
+/* this is stored at the front of every database */
+struct tdb_header {
+ char magic_food[32]; /* for /etc/magic */
+ unsigned version; /* version of the code */
+ unsigned hash_size; /* number of hash entries */
+};
+
+typedef struct {
+ char *dptr;
+ size_t dsize;
+} TDB_DATA;
+
+/* this is the context structure that is returned from a db open */
+typedef struct {
+ char *name; /* the name of the database */
+ void *map_ptr; /* where it is currently mapped */
+ int fd; /* open file descriptor for the database */
+ tdb_len map_size; /* how much space has been mapped */
+ int read_only; /* opened read-only */
+ int *locked; /* set if we have a chain locked */
+ int ecode; /* error code for last tdb error */
+ struct tdb_header header; /* a cached copy of the header */
+} TDB_CONTEXT;
+
+/* flags to tdb_store() */
+#define TDB_REPLACE 1
+#define TDB_INSERT 2
+
+/* flags for tdb_open() */
+#define TDB_CLEAR_IF_FIRST 1
+
+/* error codes */
+enum TDB_ERROR {TDB_SUCCESS=0, TDB_ERR_CORRUPT, TDB_ERR_IO, TDB_ERR_LOCK,
+ TDB_ERR_OOM, TDB_ERR_EXISTS};
+
+#if STANDALONE
+TDB_CONTEXT *tdb_open(char *name, int hash_size, int tdb_flags,
+ int open_flags, mode_t mode);
+char *tdb_error(TDB_CONTEXT *tdb);
+int tdb_writelock(TDB_CONTEXT *tdb);
+int tdb_writeunlock(TDB_CONTEXT *tdb);
+TDB_DATA tdb_fetch(TDB_CONTEXT *tdb, TDB_DATA key);
+int tdb_delete(TDB_CONTEXT *tdb, TDB_DATA key);
+int tdb_store(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf, int flag);
+int tdb_close(TDB_CONTEXT *tdb);
+TDB_DATA tdb_firstkey(TDB_CONTEXT *tdb);
+TDB_DATA tdb_nextkey(TDB_CONTEXT *tdb, TDB_DATA key);
+int tdb_traverse(TDB_CONTEXT *tdb,
+ int (*fn)(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf, void *state),
+ void *state);
+int tdb_exists(TDB_CONTEXT *tdb, TDB_DATA key);
+#endif
diff --git a/mdk-stage1/ppp/pppd/tty.c b/mdk-stage1/ppp/pppd/tty.c
new file mode 100644
index 000000000..cd724e935
--- /dev/null
+++ b/mdk-stage1/ppp/pppd/tty.c
@@ -0,0 +1,1164 @@
+/*
+ * tty.c - code for handling serial ports in pppd.
+ *
+ * Copyright (C) 2000 Paul Mackerras.
+ * All rights reserved.
+ *
+ * Portions Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#define RCSID "$Id: tty.c 195720 2001-06-11 11:44:34Z gc $"
+
+#include <stdio.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <signal.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <syslog.h>
+#include <netdb.h>
+#include <utmp.h>
+#include <pwd.h>
+#include <setjmp.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include "pppd.h"
+#include "fsm.h"
+#include "lcp.h"
+
+void tty_process_extra_options __P((void));
+void tty_check_options __P((void));
+int connect_tty __P((void));
+void disconnect_tty __P((void));
+void tty_close_fds __P((void));
+void cleanup_tty __P((void));
+void tty_do_send_config __P((int, u_int32_t, int, int));
+
+static int setdevname __P((char *, char **, int));
+static int setspeed __P((char *, char **, int));
+static int setxonxoff __P((char **));
+static int setescape __P((char **));
+static void printescape __P((option_t *, void (*)(void *, char *,...),void *));
+static void finish_tty __P((void));
+static int start_charshunt __P((int, int));
+static void stop_charshunt __P((void *, int));
+static void charshunt_done __P((void *));
+static void charshunt __P((int, int, char *));
+static int record_write __P((FILE *, int code, u_char *buf, int nb,
+ struct timeval *));
+static int open_socket __P((char *));
+static void maybe_relock __P((void *, int));
+
+static int pty_master; /* fd for master side of pty */
+static int pty_slave; /* fd for slave side of pty */
+static int real_ttyfd; /* fd for actual serial port (not pty) */
+static int ttyfd; /* Serial port file descriptor */
+static char speed_str[16]; /* Serial port speed as string */
+
+mode_t tty_mode = (mode_t)-1; /* Original access permissions to tty */
+int baud_rate; /* Actual bits/second for serial device */
+char *callback_script; /* script for doing callback */
+int charshunt_pid; /* Process ID for charshunt */
+int locked; /* lock() has succeeded */
+struct stat devstat; /* result of stat() on devnam */
+
+/* option variables */
+int crtscts = 0; /* Use hardware flow control */
+bool modem = 1; /* Use modem control lines */
+int inspeed = 0; /* Input/Output speed requested */
+bool lockflag = 0; /* Create lock file to lock the serial dev */
+char *initializer = NULL; /* Script to initialize physical link */
+char *connect_script = NULL; /* Script to establish physical link */
+char *disconnect_script = NULL; /* Script to disestablish physical link */
+char *welcomer = NULL; /* Script to run after phys link estab. */
+char *ptycommand = NULL; /* Command to run on other side of pty */
+bool notty = 0; /* Stdin/out is not a tty */
+char *record_file = NULL; /* File to record chars sent/received */
+int max_data_rate; /* max bytes/sec through charshunt */
+bool sync_serial = 0; /* Device is synchronous serial device */
+char *pty_socket = NULL; /* Socket to connect to pty */
+int using_pty = 0; /* we're allocating a pty as the device */
+
+extern uid_t uid;
+extern int kill_link;
+
+/* XXX */
+extern int privopen; /* don't lock, open device as root */
+
+u_int32_t xmit_accm[8]; /* extended transmit ACCM */
+
+/* option descriptors */
+option_t tty_options[] = {
+ /* device name must be first, or change connect_tty() below! */
+ { "device name", o_wild, (void *) &setdevname,
+ "Serial port device name",
+ OPT_DEVNAM | OPT_PRIVFIX | OPT_NOARG | OPT_A2STRVAL | OPT_STATIC,
+ devnam},
+
+ { "tty speed", o_wild, (void *) &setspeed,
+ "Baud rate for serial port",
+ OPT_PRIO | OPT_NOARG | OPT_A2STRVAL | OPT_STATIC, speed_str },
+
+ { "lock", o_bool, &lockflag,
+ "Lock serial device with UUCP-style lock file", OPT_PRIO | 1 },
+ { "nolock", o_bool, &lockflag,
+ "Don't lock serial device", OPT_PRIOSUB | OPT_PRIV },
+
+ { "init", o_string, &initializer,
+ "A program to initialize the device", OPT_PRIO | OPT_PRIVFIX },
+
+ { "connect", o_string, &connect_script,
+ "A program to set up a connection", OPT_PRIO | OPT_PRIVFIX },
+
+ { "disconnect", o_string, &disconnect_script,
+ "Program to disconnect serial device", OPT_PRIO | OPT_PRIVFIX },
+
+ { "welcome", o_string, &welcomer,
+ "Script to welcome client", OPT_PRIO | OPT_PRIVFIX },
+
+ { "pty", o_string, &ptycommand,
+ "Script to run on pseudo-tty master side",
+ OPT_PRIO | OPT_PRIVFIX | OPT_DEVNAM },
+
+ { "notty", o_bool, &notty,
+ "Input/output is not a tty", OPT_DEVNAM | 1 },
+
+ { "socket", o_string, &pty_socket,
+ "Send and receive over socket, arg is host:port",
+ OPT_PRIO | OPT_DEVNAM },
+
+ { "record", o_string, &record_file,
+ "Record characters sent/received to file", OPT_PRIO },
+
+ { "crtscts", o_int, &crtscts,
+ "Set hardware (RTS/CTS) flow control",
+ OPT_PRIO | OPT_NOARG | OPT_VAL(1) },
+ { "cdtrcts", o_int, &crtscts,
+ "Set alternate hardware (DTR/CTS) flow control",
+ OPT_PRIOSUB | OPT_NOARG | OPT_VAL(2) },
+ { "nocrtscts", o_int, &crtscts,
+ "Disable hardware flow control",
+ OPT_PRIOSUB | OPT_NOARG | OPT_VAL(-1) },
+ { "-crtscts", o_int, &crtscts,
+ "Disable hardware flow control",
+ OPT_PRIOSUB | OPT_ALIAS | OPT_NOARG | OPT_VAL(-1) },
+ { "nocdtrcts", o_int, &crtscts,
+ "Disable hardware flow control",
+ OPT_PRIOSUB | OPT_ALIAS | OPT_NOARG | OPT_VAL(-1) },
+ { "xonxoff", o_special_noarg, (void *)setxonxoff,
+ "Set software (XON/XOFF) flow control", OPT_PRIOSUB },
+
+ { "modem", o_bool, &modem,
+ "Use modem control lines", OPT_PRIO | 1 },
+ { "local", o_bool, &modem,
+ "Don't use modem control lines", OPT_PRIOSUB | 0 },
+
+ { "sync", o_bool, &sync_serial,
+ "Use synchronous HDLC serial encoding", 1 },
+
+ { "datarate", o_int, &max_data_rate,
+ "Maximum data rate in bytes/sec (with pty, notty or record option)",
+ OPT_PRIO },
+
+ { "escape", o_special, (void *)setescape,
+ "List of character codes to escape on transmission",
+ OPT_A2PRINTER, (void *)printescape },
+
+ { NULL }
+};
+
+
+struct channel tty_channel = {
+ tty_options,
+ &tty_process_extra_options,
+ &tty_check_options,
+ &connect_tty,
+ &disconnect_tty,
+ &tty_establish_ppp,
+ &tty_disestablish_ppp,
+ &tty_do_send_config,
+ &tty_recv_config,
+ &cleanup_tty,
+ &tty_close_fds
+};
+
+/*
+ * setspeed - Set the serial port baud rate.
+ * If doit is 0, the call is to check whether this option is
+ * potentially a speed value.
+ */
+static int
+setspeed(arg, argv, doit)
+ char *arg;
+ char **argv;
+ int doit;
+{
+ char *ptr;
+ int spd;
+
+ spd = strtol(arg, &ptr, 0);
+ if (ptr == arg || *ptr != 0 || spd == 0)
+ return 0;
+ if (doit) {
+ inspeed = spd;
+ slprintf(speed_str, sizeof(speed_str), "%d", spd);
+ }
+ return 1;
+}
+
+
+/*
+ * setdevname - Set the device name.
+ * If doit is 0, the call is to check whether this option is
+ * potentially a device name.
+ */
+static int
+setdevname(cp, argv, doit)
+ char *cp;
+ char **argv;
+ int doit;
+{
+ struct stat statbuf;
+ char dev[MAXPATHLEN];
+
+ if (*cp == 0)
+ return 0;
+
+ if (strncmp("/dev/", cp, 5) != 0) {
+ strlcpy(dev, "/dev/", sizeof(dev));
+ strlcat(dev, cp, sizeof(dev));
+ cp = dev;
+ }
+
+ /*
+ * Check if there is a character device by this name.
+ */
+ if (stat(cp, &statbuf) < 0) {
+ if (!doit)
+ return errno != ENOENT;
+ option_error("Couldn't stat %s: %m", cp);
+ return 0;
+ }
+ if (!S_ISCHR(statbuf.st_mode)) {
+ if (doit)
+ option_error("%s is not a character device", cp);
+ return 0;
+ }
+
+ if (doit) {
+ strlcpy(devnam, cp, sizeof(devnam));
+ devstat = statbuf;
+ default_device = 0;
+ }
+
+ return 1;
+}
+
+static int
+setxonxoff(argv)
+ char **argv;
+{
+ lcp_wantoptions[0].asyncmap |= 0x000A0000; /* escape ^S and ^Q */
+ lcp_wantoptions[0].neg_asyncmap = 1;
+
+ crtscts = -2;
+ return 1;
+}
+
+/*
+ * setescape - add chars to the set we escape on transmission.
+ */
+static int
+setescape(argv)
+ char **argv;
+{
+ int n, ret;
+ char *p, *endp;
+
+ p = *argv;
+ ret = 1;
+ while (*p) {
+ n = strtol(p, &endp, 16);
+ if (p == endp) {
+ option_error("escape parameter contains invalid hex number '%s'",
+ p);
+ return 0;
+ }
+ p = endp;
+ if (n < 0 || n == 0x5E || n > 0xFF) {
+ option_error("can't escape character 0x%x", n);
+ ret = 0;
+ } else
+ xmit_accm[n >> 5] |= 1 << (n & 0x1F);
+ while (*p == ',' || *p == ' ')
+ ++p;
+ }
+ lcp_allowoptions[0].asyncmap = xmit_accm[0];
+ return ret;
+}
+
+static void
+printescape(opt, printer, arg)
+ option_t *opt;
+ void (*printer) __P((void *, char *, ...));
+ void *arg;
+{
+ int n;
+ int first = 1;
+
+ for (n = 0; n < 256; ++n) {
+ if (n == 0x7d)
+ n += 2; /* skip 7d, 7e */
+ if (xmit_accm[n >> 5] & (1 << (n & 0x1f))) {
+ if (!first)
+ printer(arg, ",");
+ else
+ first = 0;
+ printer(arg, "%x", n);
+ }
+ }
+ if (first)
+ printer(arg, "oops # nothing escaped");
+}
+
+/*
+ * tty_init - do various tty-related initializations.
+ */
+void tty_init()
+{
+ add_notifier(&pidchange, maybe_relock, 0);
+ the_channel = &tty_channel;
+ xmit_accm[3] = 0x60000000;
+}
+
+/*
+ * tty_process_extra_options - work out which tty device we are using
+ * and read its options file.
+ */
+void tty_process_extra_options()
+{
+ using_pty = notty || ptycommand != NULL || pty_socket != NULL;
+ if (using_pty)
+ return;
+ if (default_device) {
+ char *p;
+ if (!isatty(0) || (p = ttyname(0)) == NULL) {
+ option_error("no device specified and stdin is not a tty");
+ exit(EXIT_OPTION_ERROR);
+ }
+ strlcpy(devnam, p, sizeof(devnam));
+ if (stat(devnam, &devstat) < 0)
+ fatal("Couldn't stat default device %s: %m", devnam);
+ }
+
+
+ /*
+ * Parse the tty options file.
+ * The per-tty options file should not change
+ * ptycommand, pty_socket, notty or devnam.
+ * options_for_tty doesn't override options set on the command line,
+ * except for some privileged options.
+ */
+ if (!options_for_tty())
+ exit(EXIT_OPTION_ERROR);
+}
+
+/*
+ * tty_check_options - do consistency checks on the options we were given.
+ */
+void
+tty_check_options()
+{
+ struct stat statbuf;
+ int fdflags;
+
+ if (demand && connect_script == 0) {
+ option_error("connect script is required for demand-dialling\n");
+ exit(EXIT_OPTION_ERROR);
+ }
+ /* default holdoff to 0 if no connect script has been given */
+ if (connect_script == 0 && !holdoff_specified)
+ holdoff = 0;
+
+ if (using_pty) {
+ if (!default_device) {
+ option_error("%s option precludes specifying device name",
+ notty? "notty": "pty");
+ exit(EXIT_OPTION_ERROR);
+ }
+ if (ptycommand != NULL && notty) {
+ option_error("pty option is incompatible with notty option");
+ exit(EXIT_OPTION_ERROR);
+ }
+ if (pty_socket != NULL && (ptycommand != NULL || notty)) {
+ option_error("socket option is incompatible with pty and notty");
+ exit(EXIT_OPTION_ERROR);
+ }
+ default_device = notty;
+ lockflag = 0;
+ modem = 0;
+ if (notty && log_to_fd <= 1)
+ log_to_fd = -1;
+ } else {
+ /*
+ * If the user has specified a device which is the same as
+ * the one on stdin, pretend they didn't specify any.
+ * If the device is already open read/write on stdin,
+ * we assume we don't need to lock it, and we can open it
+ * as root.
+ */
+ if (fstat(0, &statbuf) >= 0 && S_ISCHR(statbuf.st_mode)
+ && statbuf.st_rdev == devstat.st_rdev) {
+ default_device = 1;
+ fdflags = fcntl(0, F_GETFL);
+ if (fdflags != -1 && (fdflags & O_ACCMODE) == O_RDWR)
+ privopen = 1;
+ }
+ }
+ if (default_device)
+ nodetach = 1;
+
+ /*
+ * Don't send log messages to the serial port, it tends to
+ * confuse the peer. :-)
+ */
+ if (log_to_fd >= 0 && fstat(log_to_fd, &statbuf) >= 0
+ && S_ISCHR(statbuf.st_mode) && statbuf.st_rdev == devstat.st_rdev)
+ log_to_fd = -1;
+}
+
+/*
+ * connect_tty - get the serial port ready to start doing PPP.
+ * That is, open the serial port, set its speed and mode, and run
+ * the connector and/or welcomer.
+ */
+int connect_tty()
+{
+ char *connector;
+ int fdflags;
+ struct stat statbuf;
+ char numbuf[16];
+
+ /*
+ * Get a pty master/slave pair if the pty, notty, socket,
+ * or record options were specified.
+ */
+ strlcpy(ppp_devnam, devnam, sizeof(ppp_devnam));
+ pty_master = -1;
+ pty_slave = -1;
+ real_ttyfd = -1;
+ if (using_pty || record_file != NULL) {
+ if (!get_pty(&pty_master, &pty_slave, ppp_devnam, uid)) {
+ error("Couldn't allocate pseudo-tty");
+ status = EXIT_FATAL_ERROR;
+ return -1;
+ }
+ set_up_tty(pty_slave, 1);
+ }
+
+ /*
+ * Lock the device if we've been asked to.
+ */
+ status = EXIT_LOCK_FAILED;
+ if (lockflag && !privopen) {
+ if (lock(devnam) < 0)
+ return -1;
+ locked = 1;
+ }
+
+ /*
+ * Open the serial device and set it up to be the ppp interface.
+ * First we open it in non-blocking mode so we can set the
+ * various termios flags appropriately. If we aren't dialling
+ * out and we want to use the modem lines, we reopen it later
+ * in order to wait for the carrier detect signal from the modem.
+ */
+ hungup = 0;
+ kill_link = 0;
+ connector = doing_callback? callback_script: connect_script;
+ if (devnam[0] != 0) {
+ for (;;) {
+ /* If the user specified the device name, become the
+ user before opening it. */
+ int err, prio;
+
+ prio = privopen? OPRIO_ROOT: tty_options[0].priority;
+ if (prio < OPRIO_ROOT)
+ seteuid(uid);
+ ttyfd = open(devnam, O_NONBLOCK | O_RDWR, 0);
+ err = errno;
+ if (prio < OPRIO_ROOT)
+ seteuid(0);
+ if (ttyfd >= 0)
+ break;
+ errno = err;
+ if (err != EINTR) {
+ error("Failed to open %s: %m", devnam);
+ status = EXIT_OPEN_FAILED;
+ }
+ if (!persist || err != EINTR)
+ return -1;
+ }
+ real_ttyfd = ttyfd;
+ if ((fdflags = fcntl(ttyfd, F_GETFL)) == -1
+ || fcntl(ttyfd, F_SETFL, fdflags & ~O_NONBLOCK) < 0)
+ warn("Couldn't reset non-blocking mode on device: %m");
+
+ /*
+ * Do the equivalent of `mesg n' to stop broadcast messages.
+ */
+ if (fstat(ttyfd, &statbuf) < 0
+ || fchmod(ttyfd, statbuf.st_mode & ~(S_IWGRP | S_IWOTH)) < 0) {
+ warn("Couldn't restrict write permissions to %s: %m", devnam);
+ } else
+ tty_mode = statbuf.st_mode;
+
+ /*
+ * Set line speed, flow control, etc.
+ * If we have a non-null connection or initializer script,
+ * on most systems we set CLOCAL for now so that we can talk
+ * to the modem before carrier comes up. But this has the
+ * side effect that we might miss it if CD drops before we
+ * get to clear CLOCAL below. On systems where we can talk
+ * successfully to the modem with CLOCAL clear and CD down,
+ * we could clear CLOCAL at this point.
+ */
+ set_up_tty(ttyfd, ((connector != NULL && connector[0] != 0)
+ || initializer != NULL));
+ }
+
+ /*
+ * If the pty, socket, notty and/or record option was specified,
+ * start up the character shunt now.
+ */
+ status = EXIT_PTYCMD_FAILED;
+ if (ptycommand != NULL) {
+ if (record_file != NULL) {
+ int ipipe[2], opipe[2], ok;
+
+ if (pipe(ipipe) < 0 || pipe(opipe) < 0)
+ fatal("Couldn't create pipes for record option: %m");
+ ok = device_script(ptycommand, opipe[0], ipipe[1], 1) == 0
+ && start_charshunt(ipipe[0], opipe[1]);
+ close(ipipe[0]);
+ close(ipipe[1]);
+ close(opipe[0]);
+ close(opipe[1]);
+ if (!ok)
+ return -1;
+ } else {
+ if (device_script(ptycommand, pty_master, pty_master, 1) < 0)
+ return -1;
+ ttyfd = pty_slave;
+ close(pty_master);
+ pty_master = -1;
+ }
+ } else if (pty_socket != NULL) {
+ int fd = open_socket(pty_socket);
+ if (fd < 0)
+ return -1;
+ if (!start_charshunt(fd, fd))
+ return -1;
+ } else if (notty) {
+ if (!start_charshunt(0, 1))
+ return -1;
+ } else if (record_file != NULL) {
+ if (!start_charshunt(ttyfd, ttyfd))
+ return -1;
+ }
+
+ /* run connection script */
+ if ((connector && connector[0]) || initializer) {
+ if (real_ttyfd != -1) {
+ /* XXX do this if doing_callback == CALLBACK_DIALIN? */
+ if (!default_device && modem) {
+ setdtr(real_ttyfd, 0); /* in case modem is off hook */
+ sleep(1);
+ setdtr(real_ttyfd, 1);
+ }
+ }
+
+ if (initializer && initializer[0]) {
+ if (device_script(initializer, ttyfd, ttyfd, 0) < 0) {
+ error("Initializer script failed");
+ status = EXIT_INIT_FAILED;
+ return -1;
+ }
+ if (kill_link) {
+ disconnect_tty();
+ return -1;
+ }
+ info("Serial port initialized.");
+ }
+
+ if (connector && connector[0]) {
+ if (device_script(connector, ttyfd, ttyfd, 0) < 0) {
+ error("Connect script failed");
+ status = EXIT_CONNECT_FAILED;
+ return -1;
+ }
+ if (kill_link) {
+ disconnect_tty();
+ return -1;
+ }
+ info("Serial connection established.");
+ }
+
+ /* set line speed, flow control, etc.;
+ clear CLOCAL if modem option */
+ if (real_ttyfd != -1)
+ set_up_tty(real_ttyfd, 0);
+
+ if (doing_callback == CALLBACK_DIALIN)
+ connector = NULL;
+ }
+
+ /* reopen tty if necessary to wait for carrier */
+ if (connector == NULL && modem && devnam[0] != 0) {
+ int i;
+ for (;;) {
+ if ((i = open(devnam, O_RDWR)) >= 0)
+ break;
+ if (errno != EINTR) {
+ error("Failed to reopen %s: %m", devnam);
+ status = EXIT_OPEN_FAILED;
+ }
+ if (!persist || errno != EINTR || hungup || kill_link)
+ return -1;
+ }
+ close(i);
+ }
+
+ slprintf(numbuf, sizeof(numbuf), "%d", baud_rate);
+ script_setenv("SPEED", numbuf, 0);
+
+ /* run welcome script, if any */
+ if (welcomer && welcomer[0]) {
+ if (device_script(welcomer, ttyfd, ttyfd, 0) < 0)
+ warn("Welcome script failed");
+ }
+
+ /*
+ * If we are initiating this connection, wait for a short
+ * time for something from the peer. This can avoid bouncing
+ * our packets off his tty before he has it set up.
+ */
+ if (connector != NULL || ptycommand != NULL)
+ listen_time = connect_delay;
+
+ return ttyfd;
+}
+
+
+void disconnect_tty()
+{
+ if (disconnect_script == NULL || hungup)
+ return;
+ if (real_ttyfd >= 0)
+ set_up_tty(real_ttyfd, 1);
+ if (device_script(disconnect_script, ttyfd, ttyfd, 0) < 0) {
+ warn("disconnect script failed");
+ } else {
+ info("Serial link disconnected.");
+ }
+}
+
+void tty_close_fds()
+{
+ if (pty_master >= 0)
+ close(pty_master);
+ if (pty_slave >= 0)
+ close(pty_slave);
+ if (real_ttyfd >= 0) {
+ close(real_ttyfd);
+ real_ttyfd = -1;
+ }
+ /* N.B. ttyfd will == either pty_slave or real_ttyfd */
+}
+
+void cleanup_tty()
+{
+ if (real_ttyfd >= 0)
+ finish_tty();
+ tty_close_fds();
+ if (locked) {
+ unlock();
+ locked = 0;
+ }
+}
+
+/*
+ * tty_do_send_config - set transmit-side PPP configuration.
+ * We set the extended transmit ACCM here as well.
+ */
+void
+tty_do_send_config(mtu, accm, pcomp, accomp)
+ int mtu;
+ u_int32_t accm;
+ int pcomp, accomp;
+{
+ tty_set_xaccm(xmit_accm);
+ tty_send_config(mtu, accm, pcomp, accomp);
+}
+
+/*
+ * finish_tty - restore the terminal device to its original settings
+ */
+static void
+finish_tty()
+{
+ /* drop dtr to hang up */
+ if (!default_device && modem) {
+ setdtr(real_ttyfd, 0);
+ /*
+ * This sleep is in case the serial port has CLOCAL set by default,
+ * and consequently will reassert DTR when we close the device.
+ */
+ sleep(1);
+ }
+
+ restore_tty(real_ttyfd);
+
+ if (tty_mode != (mode_t) -1) {
+ if (fchmod(real_ttyfd, tty_mode) != 0) {
+ /* XXX if devnam is a symlink, this will change the link */
+ chmod(devnam, tty_mode);
+ }
+ }
+
+ close(real_ttyfd);
+ real_ttyfd = -1;
+}
+
+/*
+ * maybe_relock - our PID has changed, maybe update the lock file.
+ */
+static void
+maybe_relock(arg, pid)
+ void *arg;
+ int pid;
+{
+ if (locked)
+ relock(pid);
+}
+
+/*
+ * open_socket - establish a stream socket connection to the nominated
+ * host and port.
+ */
+static int
+open_socket(dest)
+ char *dest;
+{
+ char *sep, *endp = NULL;
+ int sock, port = -1;
+ u_int32_t host;
+ struct hostent *hent;
+ struct sockaddr_in sad;
+
+ /* parse host:port and resolve host to an IP address */
+ sep = strchr(dest, ':');
+ if (sep != NULL)
+ port = strtol(sep+1, &endp, 10);
+ if (port < 0 || endp == sep+1 || sep == dest) {
+ error("Can't parse host:port for socket destination");
+ return -1;
+ }
+ *sep = 0;
+ host = inet_addr(dest);
+ if (host == (u_int32_t) -1) {
+ hent = gethostbyname(dest);
+ if (hent == NULL) {
+ error("%s: unknown host in socket option", dest);
+ *sep = ':';
+ return -1;
+ }
+ host = *(u_int32_t *)(hent->h_addr_list[0]);
+ }
+ *sep = ':';
+
+ /* get a socket and connect it to the other end */
+ sock = socket(PF_INET, SOCK_STREAM, 0);
+ if (sock < 0) {
+ error("Can't create socket: %m");
+ return -1;
+ }
+ memset(&sad, 0, sizeof(sad));
+ sad.sin_family = AF_INET;
+ sad.sin_port = htons(port);
+ sad.sin_addr.s_addr = host;
+ if (connect(sock, (struct sockaddr *)&sad, sizeof(sad)) < 0) {
+ error("Can't connect to %s: %m", dest);
+ close(sock);
+ return -1;
+ }
+
+ return sock;
+}
+
+
+/*
+ * start_charshunt - create a child process to run the character shunt.
+ */
+static int
+start_charshunt(ifd, ofd)
+ int ifd, ofd;
+{
+ int cpid;
+
+ cpid = fork();
+ if (cpid == -1) {
+ error("Can't fork process for character shunt: %m");
+ return 0;
+ }
+ if (cpid == 0) {
+ /* child */
+ close(pty_slave);
+ setuid(uid);
+ if (getuid() != uid)
+ fatal("setuid failed");
+ setgid(getgid());
+ if (!nodetach)
+ log_to_fd = -1;
+ charshunt(ifd, ofd, record_file);
+ exit(0);
+ }
+ charshunt_pid = cpid;
+ add_notifier(&sigreceived, stop_charshunt, 0);
+ close(pty_master);
+ pty_master = -1;
+ ttyfd = pty_slave;
+ record_child(cpid, "pppd (charshunt)", charshunt_done, NULL);
+ return 1;
+}
+
+static void
+charshunt_done(arg)
+ void *arg;
+{
+ charshunt_pid = 0;
+}
+
+static void
+stop_charshunt(arg, sig)
+ void *arg;
+ int sig;
+{
+ if (charshunt_pid)
+ kill(charshunt_pid, (sig == SIGINT? sig: SIGTERM));
+}
+
+/*
+ * charshunt - the character shunt, which passes characters between
+ * the pty master side and the serial port (or stdin/stdout).
+ * This runs as the user (not as root).
+ * (We assume ofd >= ifd which is true the way this gets called. :-).
+ */
+static void
+charshunt(ifd, ofd, record_file)
+ int ifd, ofd;
+ char *record_file;
+{
+ int n, nfds;
+ fd_set ready, writey;
+ u_char *ibufp, *obufp;
+ int nibuf, nobuf;
+ int flags;
+ int pty_readable, stdin_readable;
+ struct timeval lasttime;
+ FILE *recordf = NULL;
+ int ilevel, olevel, max_level;
+ struct timeval levelt, tout, *top;
+ extern u_char inpacket_buf[];
+
+ /*
+ * Reset signal handlers.
+ */
+ signal(SIGHUP, SIG_IGN); /* Hangup */
+ signal(SIGINT, SIG_DFL); /* Interrupt */
+ signal(SIGTERM, SIG_DFL); /* Terminate */
+ signal(SIGCHLD, SIG_DFL);
+ signal(SIGUSR1, SIG_DFL);
+ signal(SIGUSR2, SIG_DFL);
+ signal(SIGABRT, SIG_DFL);
+ signal(SIGALRM, SIG_DFL);
+ signal(SIGFPE, SIG_DFL);
+ signal(SIGILL, SIG_DFL);
+ signal(SIGPIPE, SIG_DFL);
+ signal(SIGQUIT, SIG_DFL);
+ signal(SIGSEGV, SIG_DFL);
+#ifdef SIGBUS
+ signal(SIGBUS, SIG_DFL);
+#endif
+#ifdef SIGEMT
+ signal(SIGEMT, SIG_DFL);
+#endif
+#ifdef SIGPOLL
+ signal(SIGPOLL, SIG_DFL);
+#endif
+#ifdef SIGPROF
+ signal(SIGPROF, SIG_DFL);
+#endif
+#ifdef SIGSYS
+ signal(SIGSYS, SIG_DFL);
+#endif
+#ifdef SIGTRAP
+ signal(SIGTRAP, SIG_DFL);
+#endif
+#ifdef SIGVTALRM
+ signal(SIGVTALRM, SIG_DFL);
+#endif
+#ifdef SIGXCPU
+ signal(SIGXCPU, SIG_DFL);
+#endif
+#ifdef SIGXFSZ
+ signal(SIGXFSZ, SIG_DFL);
+#endif
+
+ /*
+ * Open the record file if required.
+ */
+ if (record_file != NULL) {
+ recordf = fopen(record_file, "a");
+ if (recordf == NULL)
+ error("Couldn't create record file %s: %m", record_file);
+ }
+
+ /* set all the fds to non-blocking mode */
+ flags = fcntl(pty_master, F_GETFL);
+ if (flags == -1
+ || fcntl(pty_master, F_SETFL, flags | O_NONBLOCK) == -1)
+ warn("couldn't set pty master to nonblock: %m");
+ flags = fcntl(ifd, F_GETFL);
+ if (flags == -1
+ || fcntl(ifd, F_SETFL, flags | O_NONBLOCK) == -1)
+ warn("couldn't set %s to nonblock: %m", (ifd==0? "stdin": "tty"));
+ if (ofd != ifd) {
+ flags = fcntl(ofd, F_GETFL);
+ if (flags == -1
+ || fcntl(ofd, F_SETFL, flags | O_NONBLOCK) == -1)
+ warn("couldn't set stdout to nonblock: %m");
+ }
+
+ nibuf = nobuf = 0;
+ ibufp = obufp = NULL;
+ pty_readable = stdin_readable = 1;
+
+ ilevel = olevel = 0;
+ gettimeofday(&levelt, NULL);
+ if (max_data_rate) {
+ max_level = max_data_rate / 10;
+ if (max_level < 100)
+ max_level = 100;
+ } else
+ max_level = PPP_MRU + PPP_HDRLEN + 1;
+
+ nfds = (ofd > pty_master? ofd: pty_master) + 1;
+ if (recordf != NULL) {
+ gettimeofday(&lasttime, NULL);
+ putc(7, recordf); /* put start marker */
+ putc(lasttime.tv_sec >> 24, recordf);
+ putc(lasttime.tv_sec >> 16, recordf);
+ putc(lasttime.tv_sec >> 8, recordf);
+ putc(lasttime.tv_sec, recordf);
+ lasttime.tv_usec = 0;
+ }
+
+ while (nibuf != 0 || nobuf != 0 || pty_readable || stdin_readable) {
+ top = 0;
+ tout.tv_sec = 0;
+ tout.tv_usec = 10000;
+ FD_ZERO(&ready);
+ FD_ZERO(&writey);
+ if (nibuf != 0) {
+ if (ilevel >= max_level)
+ top = &tout;
+ else
+ FD_SET(pty_master, &writey);
+ } else if (stdin_readable)
+ FD_SET(ifd, &ready);
+ if (nobuf != 0) {
+ if (olevel >= max_level)
+ top = &tout;
+ else
+ FD_SET(ofd, &writey);
+ } else if (pty_readable)
+ FD_SET(pty_master, &ready);
+ if (select(nfds, &ready, &writey, NULL, top) < 0) {
+ if (errno != EINTR)
+ fatal("select");
+ continue;
+ }
+ if (max_data_rate) {
+ double dt;
+ int nbt;
+ struct timeval now;
+
+ gettimeofday(&now, NULL);
+ dt = (now.tv_sec - levelt.tv_sec
+ + (now.tv_usec - levelt.tv_usec) / 1e6);
+ nbt = (int)(dt * max_data_rate);
+ ilevel = (nbt < 0 || nbt > ilevel)? 0: ilevel - nbt;
+ olevel = (nbt < 0 || nbt > olevel)? 0: olevel - nbt;
+ levelt = now;
+ } else
+ ilevel = olevel = 0;
+ if (FD_ISSET(ifd, &ready)) {
+ ibufp = inpacket_buf;
+ nibuf = read(ifd, ibufp, PPP_MRU + PPP_HDRLEN);
+ if (nibuf < 0 && errno == EIO)
+ nibuf = 0;
+ if (nibuf < 0) {
+ if (!(errno == EINTR || errno == EAGAIN)) {
+ error("Error reading standard input: %m");
+ break;
+ }
+ nibuf = 0;
+ } else if (nibuf == 0) {
+ /* end of file from stdin */
+ stdin_readable = 0;
+ /* do a 0-length write, hopefully this will generate
+ an EOF (hangup) on the slave side. */
+ write(pty_master, inpacket_buf, 0);
+ if (recordf)
+ if (!record_write(recordf, 4, NULL, 0, &lasttime))
+ recordf = NULL;
+ } else {
+ FD_SET(pty_master, &writey);
+ if (recordf)
+ if (!record_write(recordf, 2, ibufp, nibuf, &lasttime))
+ recordf = NULL;
+ }
+ }
+ if (FD_ISSET(pty_master, &ready)) {
+ obufp = outpacket_buf;
+ nobuf = read(pty_master, obufp, PPP_MRU + PPP_HDRLEN);
+ if (nobuf < 0 && errno == EIO)
+ nobuf = 0;
+ if (nobuf < 0) {
+ if (!(errno == EINTR || errno == EAGAIN)) {
+ error("Error reading pseudo-tty master: %m");
+ break;
+ }
+ nobuf = 0;
+ } else if (nobuf == 0) {
+ /* end of file from the pty - slave side has closed */
+ pty_readable = 0;
+ stdin_readable = 0; /* pty is not writable now */
+ nibuf = 0;
+ close(ofd);
+ if (recordf)
+ if (!record_write(recordf, 3, NULL, 0, &lasttime))
+ recordf = NULL;
+ } else {
+ FD_SET(ofd, &writey);
+ if (recordf)
+ if (!record_write(recordf, 1, obufp, nobuf, &lasttime))
+ recordf = NULL;
+ }
+ }
+ if (FD_ISSET(ofd, &writey)) {
+ n = nobuf;
+ if (olevel + n > max_level)
+ n = max_level - olevel;
+ n = write(ofd, obufp, n);
+ if (n < 0) {
+ if (errno == EIO) {
+ pty_readable = 0;
+ nobuf = 0;
+ } else if (errno != EAGAIN && errno != EINTR) {
+ error("Error writing standard output: %m");
+ break;
+ }
+ } else {
+ obufp += n;
+ nobuf -= n;
+ olevel += n;
+ }
+ }
+ if (FD_ISSET(pty_master, &writey)) {
+ n = nibuf;
+ if (ilevel + n > max_level)
+ n = max_level - ilevel;
+ n = write(pty_master, ibufp, n);
+ if (n < 0) {
+ if (errno == EIO) {
+ stdin_readable = 0;
+ nibuf = 0;
+ } else if (errno != EAGAIN && errno != EINTR) {
+ error("Error writing pseudo-tty master: %m");
+ break;
+ }
+ } else {
+ ibufp += n;
+ nibuf -= n;
+ ilevel += n;
+ }
+ }
+ }
+ exit(0);
+}
+
+static int
+record_write(f, code, buf, nb, tp)
+ FILE *f;
+ int code;
+ u_char *buf;
+ int nb;
+ struct timeval *tp;
+{
+ struct timeval now;
+ int diff;
+
+ gettimeofday(&now, NULL);
+ now.tv_usec /= 100000; /* actually 1/10 s, not usec now */
+ diff = (now.tv_sec - tp->tv_sec) * 10 + (now.tv_usec - tp->tv_usec);
+ if (diff > 0) {
+ if (diff > 255) {
+ putc(5, f);
+ putc(diff >> 24, f);
+ putc(diff >> 16, f);
+ putc(diff >> 8, f);
+ putc(diff, f);
+ } else {
+ putc(6, f);
+ putc(diff, f);
+ }
+ *tp = now;
+ }
+ putc(code, f);
+ if (buf != NULL) {
+ putc(nb >> 8, f);
+ putc(nb, f);
+ fwrite(buf, nb, 1, f);
+ }
+ fflush(f);
+ if (ferror(f)) {
+ error("Error writing record file: %m");
+ return 0;
+ }
+ return 1;
+}
diff --git a/mdk-stage1/ppp/pppd/upap.c b/mdk-stage1/ppp/pppd/upap.c
new file mode 100644
index 000000000..83bf8f7e6
--- /dev/null
+++ b/mdk-stage1/ppp/pppd/upap.c
@@ -0,0 +1,640 @@
+/*
+ * upap.c - User/Password Authentication Protocol.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#define RCSID "$Id: upap.c 195720 2001-06-11 11:44:34Z gc $"
+
+/*
+ * TODO:
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "pppd.h"
+#include "upap.h"
+
+static const char rcsid[] = RCSID;
+
+static bool hide_password = 1;
+
+/*
+ * Command-line options.
+ */
+static option_t pap_option_list[] = {
+ { "hide-password", o_bool, &hide_password,
+ "Don't output passwords to log", OPT_PRIO | 1 },
+ { "show-password", o_bool, &hide_password,
+ "Show password string in debug log messages", OPT_PRIOSUB | 0 },
+
+ { "pap-restart", o_int, &upap[0].us_timeouttime,
+ "Set retransmit timeout for PAP", OPT_PRIO },
+ { "pap-max-authreq", o_int, &upap[0].us_maxtransmits,
+ "Set max number of transmissions for auth-reqs", OPT_PRIO },
+ { "pap-timeout", o_int, &upap[0].us_reqtimeout,
+ "Set time limit for peer PAP authentication", OPT_PRIO },
+
+ { NULL }
+};
+
+/*
+ * Protocol entry points.
+ */
+static void upap_init __P((int));
+static void upap_lowerup __P((int));
+static void upap_lowerdown __P((int));
+static void upap_input __P((int, u_char *, int));
+static void upap_protrej __P((int));
+static int upap_printpkt __P((u_char *, int,
+ void (*) __P((void *, char *, ...)), void *));
+
+struct protent pap_protent = {
+ PPP_PAP,
+ upap_init,
+ upap_input,
+ upap_protrej,
+ upap_lowerup,
+ upap_lowerdown,
+ NULL,
+ NULL,
+ upap_printpkt,
+ NULL,
+ 1,
+ "PAP",
+ NULL,
+ pap_option_list,
+ NULL,
+ NULL,
+ NULL
+};
+
+upap_state upap[NUM_PPP]; /* UPAP state; one for each unit */
+
+static void upap_timeout __P((void *));
+static void upap_reqtimeout __P((void *));
+static void upap_rauthreq __P((upap_state *, u_char *, int, int));
+static void upap_rauthack __P((upap_state *, u_char *, int, int));
+static void upap_rauthnak __P((upap_state *, u_char *, int, int));
+static void upap_sauthreq __P((upap_state *));
+static void upap_sresp __P((upap_state *, int, int, char *, int));
+
+
+/*
+ * upap_init - Initialize a UPAP unit.
+ */
+static void
+upap_init(unit)
+ int unit;
+{
+ upap_state *u = &upap[unit];
+
+ u->us_unit = unit;
+ u->us_user = NULL;
+ u->us_userlen = 0;
+ u->us_passwd = NULL;
+ u->us_passwdlen = 0;
+ u->us_clientstate = UPAPCS_INITIAL;
+ u->us_serverstate = UPAPSS_INITIAL;
+ u->us_id = 0;
+ u->us_timeouttime = UPAP_DEFTIMEOUT;
+ u->us_maxtransmits = 10;
+ u->us_reqtimeout = UPAP_DEFREQTIME;
+}
+
+
+/*
+ * upap_authwithpeer - Authenticate us with our peer (start client).
+ *
+ * Set new state and send authenticate's.
+ */
+void
+upap_authwithpeer(unit, user, password)
+ int unit;
+ char *user, *password;
+{
+ upap_state *u = &upap[unit];
+
+ /* Save the username and password we're given */
+ u->us_user = user;
+ u->us_userlen = strlen(user);
+ u->us_passwd = password;
+ u->us_passwdlen = strlen(password);
+ u->us_transmits = 0;
+
+ /* Lower layer up yet? */
+ if (u->us_clientstate == UPAPCS_INITIAL ||
+ u->us_clientstate == UPAPCS_PENDING) {
+ u->us_clientstate = UPAPCS_PENDING;
+ return;
+ }
+
+ upap_sauthreq(u); /* Start protocol */
+}
+
+
+/*
+ * upap_authpeer - Authenticate our peer (start server).
+ *
+ * Set new state.
+ */
+void
+upap_authpeer(unit)
+ int unit;
+{
+ upap_state *u = &upap[unit];
+
+ /* Lower layer up yet? */
+ if (u->us_serverstate == UPAPSS_INITIAL ||
+ u->us_serverstate == UPAPSS_PENDING) {
+ u->us_serverstate = UPAPSS_PENDING;
+ return;
+ }
+
+ u->us_serverstate = UPAPSS_LISTEN;
+ if (u->us_reqtimeout > 0)
+ TIMEOUT(upap_reqtimeout, u, u->us_reqtimeout);
+}
+
+
+/*
+ * upap_timeout - Retransmission timer for sending auth-reqs expired.
+ */
+static void
+upap_timeout(arg)
+ void *arg;
+{
+ upap_state *u = (upap_state *) arg;
+
+ if (u->us_clientstate != UPAPCS_AUTHREQ)
+ return;
+
+ if (u->us_transmits >= u->us_maxtransmits) {
+ /* give up in disgust */
+ error("No response to PAP authenticate-requests");
+ u->us_clientstate = UPAPCS_BADAUTH;
+ auth_withpeer_fail(u->us_unit, PPP_PAP);
+ return;
+ }
+
+ upap_sauthreq(u); /* Send Authenticate-Request */
+}
+
+
+/*
+ * upap_reqtimeout - Give up waiting for the peer to send an auth-req.
+ */
+static void
+upap_reqtimeout(arg)
+ void *arg;
+{
+ upap_state *u = (upap_state *) arg;
+
+ if (u->us_serverstate != UPAPSS_LISTEN)
+ return; /* huh?? */
+
+ auth_peer_fail(u->us_unit, PPP_PAP);
+ u->us_serverstate = UPAPSS_BADAUTH;
+}
+
+
+/*
+ * upap_lowerup - The lower layer is up.
+ *
+ * Start authenticating if pending.
+ */
+static void
+upap_lowerup(unit)
+ int unit;
+{
+ upap_state *u = &upap[unit];
+
+ if (u->us_clientstate == UPAPCS_INITIAL)
+ u->us_clientstate = UPAPCS_CLOSED;
+ else if (u->us_clientstate == UPAPCS_PENDING) {
+ upap_sauthreq(u); /* send an auth-request */
+ }
+
+ if (u->us_serverstate == UPAPSS_INITIAL)
+ u->us_serverstate = UPAPSS_CLOSED;
+ else if (u->us_serverstate == UPAPSS_PENDING) {
+ u->us_serverstate = UPAPSS_LISTEN;
+ if (u->us_reqtimeout > 0)
+ TIMEOUT(upap_reqtimeout, u, u->us_reqtimeout);
+ }
+}
+
+
+/*
+ * upap_lowerdown - The lower layer is down.
+ *
+ * Cancel all timeouts.
+ */
+static void
+upap_lowerdown(unit)
+ int unit;
+{
+ upap_state *u = &upap[unit];
+
+ if (u->us_clientstate == UPAPCS_AUTHREQ) /* Timeout pending? */
+ UNTIMEOUT(upap_timeout, u); /* Cancel timeout */
+ if (u->us_serverstate == UPAPSS_LISTEN && u->us_reqtimeout > 0)
+ UNTIMEOUT(upap_reqtimeout, u);
+
+ u->us_clientstate = UPAPCS_INITIAL;
+ u->us_serverstate = UPAPSS_INITIAL;
+}
+
+
+/*
+ * upap_protrej - Peer doesn't speak this protocol.
+ *
+ * This shouldn't happen. In any case, pretend lower layer went down.
+ */
+static void
+upap_protrej(unit)
+ int unit;
+{
+ upap_state *u = &upap[unit];
+
+ if (u->us_clientstate == UPAPCS_AUTHREQ) {
+ error("PAP authentication failed due to protocol-reject");
+ auth_withpeer_fail(unit, PPP_PAP);
+ }
+ if (u->us_serverstate == UPAPSS_LISTEN) {
+ error("PAP authentication of peer failed (protocol-reject)");
+ auth_peer_fail(unit, PPP_PAP);
+ }
+ upap_lowerdown(unit);
+}
+
+
+/*
+ * upap_input - Input UPAP packet.
+ */
+static void
+upap_input(unit, inpacket, l)
+ int unit;
+ u_char *inpacket;
+ int l;
+{
+ upap_state *u = &upap[unit];
+ u_char *inp;
+ u_char code, id;
+ int len;
+
+ /*
+ * Parse header (code, id and length).
+ * If packet too short, drop it.
+ */
+ inp = inpacket;
+ if (l < UPAP_HEADERLEN) {
+ UPAPDEBUG(("pap_input: rcvd short header."));
+ return;
+ }
+ GETCHAR(code, inp);
+ GETCHAR(id, inp);
+ GETSHORT(len, inp);
+ if (len < UPAP_HEADERLEN) {
+ UPAPDEBUG(("pap_input: rcvd illegal length."));
+ return;
+ }
+ if (len > l) {
+ UPAPDEBUG(("pap_input: rcvd short packet."));
+ return;
+ }
+ len -= UPAP_HEADERLEN;
+
+ /*
+ * Action depends on code.
+ */
+ switch (code) {
+ case UPAP_AUTHREQ:
+ upap_rauthreq(u, inp, id, len);
+ break;
+
+ case UPAP_AUTHACK:
+ upap_rauthack(u, inp, id, len);
+ break;
+
+ case UPAP_AUTHNAK:
+ upap_rauthnak(u, inp, id, len);
+ break;
+
+ default: /* XXX Need code reject */
+ break;
+ }
+}
+
+
+/*
+ * upap_rauth - Receive Authenticate.
+ */
+static void
+upap_rauthreq(u, inp, id, len)
+ upap_state *u;
+ u_char *inp;
+ int id;
+ int len;
+{
+ u_char ruserlen, rpasswdlen;
+ char *ruser, *rpasswd;
+ int retcode;
+ char *msg;
+ int msglen;
+
+ if (u->us_serverstate < UPAPSS_LISTEN)
+ return;
+
+ /*
+ * If we receive a duplicate authenticate-request, we are
+ * supposed to return the same status as for the first request.
+ */
+ if (u->us_serverstate == UPAPSS_OPEN) {
+ upap_sresp(u, UPAP_AUTHACK, id, "", 0); /* return auth-ack */
+ return;
+ }
+ if (u->us_serverstate == UPAPSS_BADAUTH) {
+ upap_sresp(u, UPAP_AUTHNAK, id, "", 0); /* return auth-nak */
+ return;
+ }
+
+ /*
+ * Parse user/passwd.
+ */
+ if (len < 1) {
+ UPAPDEBUG(("pap_rauth: rcvd short packet."));
+ return;
+ }
+ GETCHAR(ruserlen, inp);
+ len -= sizeof (u_char) + ruserlen + sizeof (u_char);
+ if (len < 0) {
+ UPAPDEBUG(("pap_rauth: rcvd short packet."));
+ return;
+ }
+ ruser = (char *) inp;
+ INCPTR(ruserlen, inp);
+ GETCHAR(rpasswdlen, inp);
+ if (len < rpasswdlen) {
+ UPAPDEBUG(("pap_rauth: rcvd short packet."));
+ return;
+ }
+ rpasswd = (char *) inp;
+
+ /*
+ * Check the username and password given.
+ */
+ retcode = check_passwd(u->us_unit, ruser, ruserlen, rpasswd,
+ rpasswdlen, &msg);
+ BZERO(rpasswd, rpasswdlen);
+ msglen = strlen(msg);
+ if (msglen > 255)
+ msglen = 255;
+
+ upap_sresp(u, retcode, id, msg, msglen);
+
+ if (retcode == UPAP_AUTHACK) {
+ u->us_serverstate = UPAPSS_OPEN;
+ auth_peer_success(u->us_unit, PPP_PAP, ruser, ruserlen);
+ } else {
+ u->us_serverstate = UPAPSS_BADAUTH;
+ auth_peer_fail(u->us_unit, PPP_PAP);
+ }
+
+ if (u->us_reqtimeout > 0)
+ UNTIMEOUT(upap_reqtimeout, u);
+}
+
+
+/*
+ * upap_rauthack - Receive Authenticate-Ack.
+ */
+static void
+upap_rauthack(u, inp, id, len)
+ upap_state *u;
+ u_char *inp;
+ int id;
+ int len;
+{
+ u_char msglen;
+ char *msg;
+
+ if (u->us_clientstate != UPAPCS_AUTHREQ) /* XXX */
+ return;
+
+ /*
+ * Parse message.
+ */
+ if (len < 1) {
+ UPAPDEBUG(("pap_rauthack: ignoring missing msg-length."));
+ } else {
+ GETCHAR(msglen, inp);
+ if (msglen > 0) {
+ len -= sizeof (u_char);
+ if (len < msglen) {
+ UPAPDEBUG(("pap_rauthack: rcvd short packet."));
+ return;
+ }
+ msg = (char *) inp;
+ PRINTMSG(msg, msglen);
+ }
+ }
+
+ u->us_clientstate = UPAPCS_OPEN;
+
+ auth_withpeer_success(u->us_unit, PPP_PAP);
+}
+
+
+/*
+ * upap_rauthnak - Receive Authenticate-Nakk.
+ */
+static void
+upap_rauthnak(u, inp, id, len)
+ upap_state *u;
+ u_char *inp;
+ int id;
+ int len;
+{
+ u_char msglen;
+ char *msg;
+
+ if (u->us_clientstate != UPAPCS_AUTHREQ) /* XXX */
+ return;
+
+ /*
+ * Parse message.
+ */
+ if (len < 1) {
+ UPAPDEBUG(("pap_rauthnak: ignoring missing msg-length."));
+ } else {
+ GETCHAR(msglen, inp);
+ if (msglen > 0) {
+ len -= sizeof (u_char);
+ if (len < msglen) {
+ UPAPDEBUG(("pap_rauthnak: rcvd short packet."));
+ return;
+ }
+ msg = (char *) inp;
+ PRINTMSG(msg, msglen);
+ }
+ }
+
+ u->us_clientstate = UPAPCS_BADAUTH;
+
+ error("PAP authentication failed");
+ auth_withpeer_fail(u->us_unit, PPP_PAP);
+}
+
+
+/*
+ * upap_sauthreq - Send an Authenticate-Request.
+ */
+static void
+upap_sauthreq(u)
+ upap_state *u;
+{
+ u_char *outp;
+ int outlen;
+
+ outlen = UPAP_HEADERLEN + 2 * sizeof (u_char) +
+ u->us_userlen + u->us_passwdlen;
+ outp = outpacket_buf;
+
+ MAKEHEADER(outp, PPP_PAP);
+
+ PUTCHAR(UPAP_AUTHREQ, outp);
+ PUTCHAR(++u->us_id, outp);
+ PUTSHORT(outlen, outp);
+ PUTCHAR(u->us_userlen, outp);
+ BCOPY(u->us_user, outp, u->us_userlen);
+ INCPTR(u->us_userlen, outp);
+ PUTCHAR(u->us_passwdlen, outp);
+ BCOPY(u->us_passwd, outp, u->us_passwdlen);
+
+ output(u->us_unit, outpacket_buf, outlen + PPP_HDRLEN);
+
+ TIMEOUT(upap_timeout, u, u->us_timeouttime);
+ ++u->us_transmits;
+ u->us_clientstate = UPAPCS_AUTHREQ;
+}
+
+
+/*
+ * upap_sresp - Send a response (ack or nak).
+ */
+static void
+upap_sresp(u, code, id, msg, msglen)
+ upap_state *u;
+ u_char code, id;
+ char *msg;
+ int msglen;
+{
+ u_char *outp;
+ int outlen;
+
+ outlen = UPAP_HEADERLEN + sizeof (u_char) + msglen;
+ outp = outpacket_buf;
+ MAKEHEADER(outp, PPP_PAP);
+
+ PUTCHAR(code, outp);
+ PUTCHAR(id, outp);
+ PUTSHORT(outlen, outp);
+ PUTCHAR(msglen, outp);
+ BCOPY(msg, outp, msglen);
+ output(u->us_unit, outpacket_buf, outlen + PPP_HDRLEN);
+}
+
+/*
+ * upap_printpkt - print the contents of a PAP packet.
+ */
+static char *upap_codenames[] = {
+ "AuthReq", "AuthAck", "AuthNak"
+};
+
+static int
+upap_printpkt(p, plen, printer, arg)
+ u_char *p;
+ int plen;
+ void (*printer) __P((void *, char *, ...));
+ void *arg;
+{
+ int code, id, len;
+ int mlen, ulen, wlen;
+ char *user, *pwd, *msg;
+ u_char *pstart;
+
+ if (plen < UPAP_HEADERLEN)
+ return 0;
+ pstart = p;
+ GETCHAR(code, p);
+ GETCHAR(id, p);
+ GETSHORT(len, p);
+ if (len < UPAP_HEADERLEN || len > plen)
+ return 0;
+
+ if (code >= 1 && code <= sizeof(upap_codenames) / sizeof(char *))
+ printer(arg, " %s", upap_codenames[code-1]);
+ else
+ printer(arg, " code=0x%x", code);
+ printer(arg, " id=0x%x", id);
+ len -= UPAP_HEADERLEN;
+ switch (code) {
+ case UPAP_AUTHREQ:
+ if (len < 1)
+ break;
+ ulen = p[0];
+ if (len < ulen + 2)
+ break;
+ wlen = p[ulen + 1];
+ if (len < ulen + wlen + 2)
+ break;
+ user = (char *) (p + 1);
+ pwd = (char *) (p + ulen + 2);
+ p += ulen + wlen + 2;
+ len -= ulen + wlen + 2;
+ printer(arg, " user=");
+ print_string(user, ulen, printer, arg);
+ printer(arg, " password=");
+ if (!hide_password)
+ print_string(pwd, wlen, printer, arg);
+ else
+ printer(arg, "<hidden>");
+ break;
+ case UPAP_AUTHACK:
+ case UPAP_AUTHNAK:
+ if (len < 1)
+ break;
+ mlen = p[0];
+ if (len < mlen + 1)
+ break;
+ msg = (char *) (p + 1);
+ p += mlen + 1;
+ len -= mlen + 1;
+ printer(arg, " ");
+ print_string(msg, mlen, printer, arg);
+ break;
+ }
+
+ /* print the rest of the bytes in the packet */
+ for (; len > 0; --len) {
+ GETCHAR(code, p);
+ printer(arg, " %.2x", code);
+ }
+
+ return p - pstart;
+}
diff --git a/mdk-stage1/ppp/pppd/upap.h b/mdk-stage1/ppp/pppd/upap.h
new file mode 100644
index 000000000..a1ee587d1
--- /dev/null
+++ b/mdk-stage1/ppp/pppd/upap.h
@@ -0,0 +1,87 @@
+/*
+ * upap.h - User/Password Authentication Protocol definitions.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id: upap.h 195720 2001-06-11 11:44:34Z gc $
+ */
+
+/*
+ * Packet header = Code, id, length.
+ */
+#define UPAP_HEADERLEN 4
+
+
+/*
+ * UPAP codes.
+ */
+#define UPAP_AUTHREQ 1 /* Authenticate-Request */
+#define UPAP_AUTHACK 2 /* Authenticate-Ack */
+#define UPAP_AUTHNAK 3 /* Authenticate-Nak */
+
+
+/*
+ * Each interface is described by upap structure.
+ */
+typedef struct upap_state {
+ int us_unit; /* Interface unit number */
+ char *us_user; /* User */
+ int us_userlen; /* User length */
+ char *us_passwd; /* Password */
+ int us_passwdlen; /* Password length */
+ int us_clientstate; /* Client state */
+ int us_serverstate; /* Server state */
+ u_char us_id; /* Current id */
+ int us_timeouttime; /* Timeout (seconds) for auth-req retrans. */
+ int us_transmits; /* Number of auth-reqs sent */
+ int us_maxtransmits; /* Maximum number of auth-reqs to send */
+ int us_reqtimeout; /* Time to wait for auth-req from peer */
+} upap_state;
+
+
+/*
+ * Client states.
+ */
+#define UPAPCS_INITIAL 0 /* Connection down */
+#define UPAPCS_CLOSED 1 /* Connection up, haven't requested auth */
+#define UPAPCS_PENDING 2 /* Connection down, have requested auth */
+#define UPAPCS_AUTHREQ 3 /* We've sent an Authenticate-Request */
+#define UPAPCS_OPEN 4 /* We've received an Ack */
+#define UPAPCS_BADAUTH 5 /* We've received a Nak */
+
+/*
+ * Server states.
+ */
+#define UPAPSS_INITIAL 0 /* Connection down */
+#define UPAPSS_CLOSED 1 /* Connection up, haven't requested auth */
+#define UPAPSS_PENDING 2 /* Connection down, have requested auth */
+#define UPAPSS_LISTEN 3 /* Listening for an Authenticate */
+#define UPAPSS_OPEN 4 /* We've sent an Ack */
+#define UPAPSS_BADAUTH 5 /* We've sent a Nak */
+
+
+/*
+ * Timeouts.
+ */
+#define UPAP_DEFTIMEOUT 3 /* Timeout (seconds) for retransmitting req */
+#define UPAP_DEFREQTIME 30 /* Time to wait for auth-req from peer */
+
+extern upap_state upap[];
+
+void upap_authwithpeer __P((int, char *, char *));
+void upap_authpeer __P((int));
+
+extern struct protent pap_protent;
diff --git a/mdk-stage1/ppp/pppd/utils.c b/mdk-stage1/ppp/pppd/utils.c
new file mode 100644
index 000000000..64b960a63
--- /dev/null
+++ b/mdk-stage1/ppp/pppd/utils.c
@@ -0,0 +1,949 @@
+/*
+ * utils.c - various utility functions used in pppd.
+ *
+ * Copyright (c) 1999 The Australian National University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the Australian National University. The name of the University
+ * may not be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#define RCSID "$Id: utils.c 203596 2003-08-19 08:57:26Z gbeauchesne $"
+
+#include <stdio.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <signal.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <syslog.h>
+#include <netdb.h>
+#include <utmp.h>
+#include <pwd.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#ifdef SVR4
+#include <sys/mkdev.h>
+#endif
+
+#include "pppd.h"
+#include <time.h>
+
+static const char rcsid[] = RCSID;
+
+#if defined(SUNOS4)
+extern char *strerror();
+#endif
+
+static void logit __P((int, char *, va_list));
+static void log_write __P((int, char *));
+static void vslp_printer __P((void *, char *, ...));
+static void format_packet __P((u_char *, int, void (*) (void *, char *, ...),
+ void *));
+
+struct buffer_info {
+ char *ptr;
+ int len;
+};
+
+/*
+ * strlcpy - like strcpy/strncpy, doesn't overflow destination buffer,
+ * always leaves destination null-terminated (for len > 0).
+ */
+size_t
+strlcpy(dest, src, len)
+ char *dest;
+ const char *src;
+ size_t len;
+{
+ size_t ret = strlen(src);
+
+ if (len != 0) {
+ if (ret < len)
+ strcpy(dest, src);
+ else {
+ strncpy(dest, src, len - 1);
+ dest[len-1] = 0;
+ }
+ }
+ return ret;
+}
+
+/*
+ * strlcat - like strcat/strncat, doesn't overflow destination buffer,
+ * always leaves destination null-terminated (for len > 0).
+ */
+size_t
+strlcat(dest, src, len)
+ char *dest;
+ const char *src;
+ size_t len;
+{
+ size_t dlen = strlen(dest);
+
+ return dlen + strlcpy(dest + dlen, src, (len > dlen? len - dlen: 0));
+}
+
+
+/*
+ * slprintf - format a message into a buffer. Like sprintf except we
+ * also specify the length of the output buffer, and we handle
+ * %r (recursive format), %m (error message), %v (visible string),
+ * %q (quoted string), %t (current time) and %I (IP address) formats.
+ * Doesn't do floating-point formats.
+ * Returns the number of chars put into buf.
+ */
+int
+slprintf __V((char *buf, int buflen, char *fmt, ...))
+{
+ va_list args;
+ int n;
+
+#if defined(__STDC__)
+ va_start(args, fmt);
+#else
+ char *buf;
+ int buflen;
+ char *fmt;
+ va_start(args);
+ buf = va_arg(args, char *);
+ buflen = va_arg(args, int);
+ fmt = va_arg(args, char *);
+#endif
+ n = vslprintf(buf, buflen, fmt, args);
+ va_end(args);
+ return n;
+}
+
+/*
+ * vslprintf - like slprintf, takes a va_list instead of a list of args.
+ */
+#define OUTCHAR(c) (buflen > 0? (--buflen, *buf++ = (c)): 0)
+
+int
+vslprintf(buf, buflen, fmt, args)
+ char *buf;
+ int buflen;
+ char *fmt;
+ va_list args;
+{
+ int c, i, n;
+ int width, prec, fillch;
+ int base, len, neg, quoted;
+ unsigned long val = 0;
+ char *str, *f, *buf0;
+ unsigned char *p;
+ char num[32];
+ time_t t;
+ u_int32_t ip;
+ static char hexchars[] = "0123456789abcdef";
+ struct buffer_info bufinfo;
+
+ buf0 = buf;
+ --buflen;
+ while (buflen > 0) {
+ for (f = fmt; *f != '%' && *f != 0; ++f)
+ ;
+ if (f > fmt) {
+ len = f - fmt;
+ if (len > buflen)
+ len = buflen;
+ memcpy(buf, fmt, len);
+ buf += len;
+ buflen -= len;
+ fmt = f;
+ }
+ if (*fmt == 0)
+ break;
+ c = *++fmt;
+ width = 0;
+ prec = -1;
+ fillch = ' ';
+ if (c == '0') {
+ fillch = '0';
+ c = *++fmt;
+ }
+ if (c == '*') {
+ width = va_arg(args, int);
+ c = *++fmt;
+ } else {
+ while (isdigit(c)) {
+ width = width * 10 + c - '0';
+ c = *++fmt;
+ }
+ }
+ if (c == '.') {
+ c = *++fmt;
+ if (c == '*') {
+ prec = va_arg(args, int);
+ c = *++fmt;
+ } else {
+ prec = 0;
+ while (isdigit(c)) {
+ prec = prec * 10 + c - '0';
+ c = *++fmt;
+ }
+ }
+ }
+ str = 0;
+ base = 0;
+ neg = 0;
+ ++fmt;
+ switch (c) {
+ case 'd':
+ i = va_arg(args, int);
+ if (i < 0) {
+ neg = 1;
+ val = -i;
+ } else
+ val = i;
+ base = 10;
+ break;
+ case 'u':
+ val = va_arg(args, unsigned int);
+ base = 10;
+ break;
+ case 'o':
+ val = va_arg(args, unsigned int);
+ base = 8;
+ break;
+ case 'x':
+ case 'X':
+ val = va_arg(args, unsigned int);
+ base = 16;
+ break;
+ case 'p':
+ val = (unsigned long) va_arg(args, void *);
+ base = 16;
+ neg = 2;
+ break;
+ case 's':
+ str = va_arg(args, char *);
+ break;
+ case 'c':
+ num[0] = va_arg(args, int);
+ num[1] = 0;
+ str = num;
+ break;
+ case 'm':
+ str = strerror(errno);
+ break;
+ case 'I':
+ ip = va_arg(args, u_int32_t);
+ ip = ntohl(ip);
+ slprintf(num, sizeof(num), "%d.%d.%d.%d", (ip >> 24) & 0xff,
+ (ip >> 16) & 0xff, (ip >> 8) & 0xff, ip & 0xff);
+ str = num;
+ break;
+ case 'r':
+ f = va_arg(args, char *);
+#if !defined(__powerpc__) && !defined(__x86_64__)
+ n = vslprintf(buf, buflen + 1, f, va_arg(args, va_list));
+#else
+ /* On the powerpc, a va_list is an array of 1 structure */
+ n = vslprintf(buf, buflen + 1, f, va_arg(args, void *));
+#endif
+ buf += n;
+ buflen -= n;
+ continue;
+ case 't':
+ time(&t);
+ str = ctime(&t);
+ str += 4; /* chop off the day name */
+ str[15] = 0; /* chop off year and newline */
+ break;
+ case 'v': /* "visible" string */
+ case 'q': /* quoted string */
+ quoted = c == 'q';
+ p = va_arg(args, unsigned char *);
+ if (fillch == '0' && prec >= 0) {
+ n = prec;
+ } else {
+ n = strlen((char *)p);
+ if (prec >= 0 && n > prec)
+ n = prec;
+ }
+ while (n > 0 && buflen > 0) {
+ c = *p++;
+ --n;
+ if (!quoted && c >= 0x80) {
+ OUTCHAR('M');
+ OUTCHAR('-');
+ c -= 0x80;
+ }
+ if (quoted && (c == '"' || c == '\\'))
+ OUTCHAR('\\');
+ if (c < 0x20 || (0x7f <= c && c < 0xa0)) {
+ if (quoted) {
+ OUTCHAR('\\');
+ switch (c) {
+ case '\t': OUTCHAR('t'); break;
+ case '\n': OUTCHAR('n'); break;
+ case '\b': OUTCHAR('b'); break;
+ case '\f': OUTCHAR('f'); break;
+ default:
+ OUTCHAR('x');
+ OUTCHAR(hexchars[c >> 4]);
+ OUTCHAR(hexchars[c & 0xf]);
+ }
+ } else {
+ if (c == '\t')
+ OUTCHAR(c);
+ else {
+ OUTCHAR('^');
+ OUTCHAR(c ^ 0x40);
+ }
+ }
+ } else
+ OUTCHAR(c);
+ }
+ continue;
+ case 'P': /* print PPP packet */
+ bufinfo.ptr = buf;
+ bufinfo.len = buflen + 1;
+ p = va_arg(args, unsigned char *);
+ n = va_arg(args, int);
+ format_packet(p, n, vslp_printer, &bufinfo);
+ buf = bufinfo.ptr;
+ buflen = bufinfo.len - 1;
+ continue;
+ case 'B':
+ p = va_arg(args, unsigned char *);
+ for (n = prec; n > 0; --n) {
+ c = *p++;
+ if (fillch == ' ')
+ OUTCHAR(' ');
+ OUTCHAR(hexchars[(c >> 4) & 0xf]);
+ OUTCHAR(hexchars[c & 0xf]);
+ }
+ continue;
+ default:
+ *buf++ = '%';
+ if (c != '%')
+ --fmt; /* so %z outputs %z etc. */
+ --buflen;
+ continue;
+ }
+ if (base != 0) {
+ str = num + sizeof(num);
+ *--str = 0;
+ while (str > num + neg) {
+ *--str = hexchars[val % base];
+ val = val / base;
+ if (--prec <= 0 && val == 0)
+ break;
+ }
+ switch (neg) {
+ case 1:
+ *--str = '-';
+ break;
+ case 2:
+ *--str = 'x';
+ *--str = '0';
+ break;
+ }
+ len = num + sizeof(num) - 1 - str;
+ } else {
+ len = strlen(str);
+ if (prec >= 0 && len > prec)
+ len = prec;
+ }
+ if (width > 0) {
+ if (width > buflen)
+ width = buflen;
+ if ((n = width - len) > 0) {
+ buflen -= n;
+ for (; n > 0; --n)
+ *buf++ = fillch;
+ }
+ }
+ if (len > buflen)
+ len = buflen;
+ memcpy(buf, str, len);
+ buf += len;
+ buflen -= len;
+ }
+ *buf = 0;
+ return buf - buf0;
+}
+
+/*
+ * vslp_printer - used in processing a %P format
+ */
+static void
+vslp_printer __V((void *arg, char *fmt, ...))
+{
+ int n;
+ va_list pvar;
+ struct buffer_info *bi;
+
+#if defined(__STDC__)
+ va_start(pvar, fmt);
+#else
+ void *arg;
+ char *fmt;
+ va_start(pvar);
+ arg = va_arg(pvar, void *);
+ fmt = va_arg(pvar, char *);
+#endif
+
+ bi = (struct buffer_info *) arg;
+ n = vslprintf(bi->ptr, bi->len, fmt, pvar);
+ va_end(pvar);
+
+ bi->ptr += n;
+ bi->len -= n;
+}
+
+#ifdef unused
+/*
+ * log_packet - format a packet and log it.
+ */
+
+void
+log_packet(p, len, prefix, level)
+ u_char *p;
+ int len;
+ char *prefix;
+ int level;
+{
+ init_pr_log(prefix, level);
+ format_packet(p, len, pr_log, &level);
+ end_pr_log();
+}
+#endif /* unused */
+
+/*
+ * format_packet - make a readable representation of a packet,
+ * calling `printer(arg, format, ...)' to output it.
+ */
+static void
+format_packet(p, len, printer, arg)
+ u_char *p;
+ int len;
+ void (*printer) __P((void *, char *, ...));
+ void *arg;
+{
+ int i, n;
+ u_short proto;
+ struct protent *protp;
+
+ if (len >= PPP_HDRLEN && p[0] == PPP_ALLSTATIONS && p[1] == PPP_UI) {
+ p += 2;
+ GETSHORT(proto, p);
+ len -= PPP_HDRLEN;
+ for (i = 0; (protp = protocols[i]) != NULL; ++i)
+ if (proto == protp->protocol)
+ break;
+ if (protp != NULL) {
+ printer(arg, "[%s", protp->name);
+ n = (*protp->printpkt)(p, len, printer, arg);
+ printer(arg, "]");
+ p += n;
+ len -= n;
+ } else {
+ for (i = 0; (protp = protocols[i]) != NULL; ++i)
+ if (proto == (protp->protocol & ~0x8000))
+ break;
+ if (protp != 0 && protp->data_name != 0) {
+ printer(arg, "[%s data]", protp->data_name);
+ if (len > 8)
+ printer(arg, "%.8B ...", p);
+ else
+ printer(arg, "%.*B", len, p);
+ len = 0;
+ } else
+ printer(arg, "[proto=0x%x]", proto);
+ }
+ }
+
+ if (len > 32)
+ printer(arg, "%.32B ...", p);
+ else
+ printer(arg, "%.*B", len, p);
+}
+
+/*
+ * init_pr_log, end_pr_log - initialize and finish use of pr_log.
+ */
+
+static char line[256]; /* line to be logged accumulated here */
+static char *linep; /* current pointer within line */
+static int llevel; /* level for logging */
+
+void
+init_pr_log(prefix, level)
+ char *prefix;
+ int level;
+{
+ linep = line;
+ if (prefix != NULL) {
+ strlcpy(line, prefix, sizeof(line));
+ linep = line + strlen(line);
+ }
+ llevel = level;
+}
+
+void
+end_pr_log()
+{
+ if (linep != line) {
+ *linep = 0;
+ log_write(llevel, line);
+ }
+}
+
+/*
+ * pr_log - printer routine for outputting to syslog
+ */
+void
+pr_log __V((void *arg, char *fmt, ...))
+{
+ int l, n;
+ va_list pvar;
+ char *p, *eol;
+ char buf[256];
+
+#if defined(__STDC__)
+ va_start(pvar, fmt);
+#else
+ void *arg;
+ char *fmt;
+ va_start(pvar);
+ arg = va_arg(pvar, void *);
+ fmt = va_arg(pvar, char *);
+#endif
+
+ n = vslprintf(buf, sizeof(buf), fmt, pvar);
+ va_end(pvar);
+
+ p = buf;
+ eol = strchr(buf, '\n');
+ if (linep != line) {
+ l = (eol == NULL)? n: eol - buf;
+ if (linep + l < line + sizeof(line)) {
+ if (l > 0) {
+ memcpy(linep, buf, l);
+ linep += l;
+ }
+ if (eol == NULL)
+ return;
+ p = eol + 1;
+ eol = strchr(p, '\n');
+ }
+ *linep = 0;
+ log_write(llevel, line);
+ linep = line;
+ }
+
+ while (eol != NULL) {
+ *eol = 0;
+ log_write(llevel, p);
+ p = eol + 1;
+ eol = strchr(p, '\n');
+ }
+
+ /* assumes sizeof(buf) <= sizeof(line) */
+ l = buf + n - p;
+ if (l > 0) {
+ memcpy(line, p, n);
+ linep = line + l;
+ }
+}
+
+/*
+ * print_string - print a readable representation of a string using
+ * printer.
+ */
+void
+print_string(p, len, printer, arg)
+ char *p;
+ int len;
+ void (*printer) __P((void *, char *, ...));
+ void *arg;
+{
+ int c;
+
+ printer(arg, "\"");
+ for (; len > 0; --len) {
+ c = *p++;
+ if (' ' <= c && c <= '~') {
+ if (c == '\\' || c == '"')
+ printer(arg, "\\");
+ printer(arg, "%c", c);
+ } else {
+ switch (c) {
+ case '\n':
+ printer(arg, "\\n");
+ break;
+ case '\r':
+ printer(arg, "\\r");
+ break;
+ case '\t':
+ printer(arg, "\\t");
+ break;
+ default:
+ printer(arg, "\\%.3o", c);
+ }
+ }
+ }
+ printer(arg, "\"");
+}
+
+/*
+ * logit - does the hard work for fatal et al.
+ */
+static void
+logit(level, fmt, args)
+ int level;
+ char *fmt;
+ va_list args;
+{
+ int n;
+ char buf[1024];
+
+ n = vslprintf(buf, sizeof(buf), fmt, args);
+ log_write(level, buf);
+}
+
+static void
+log_write(level, buf)
+ int level;
+ char *buf;
+{
+ syslog(level, "%s", buf);
+ if (log_to_fd >= 0 && (level != LOG_DEBUG || debug)) {
+ int n = strlen(buf);
+
+ if (n > 0 && buf[n-1] == '\n')
+ --n;
+ if (write(log_to_fd, buf, n) != n
+ || write(log_to_fd, "\n", 1) != 1)
+ log_to_fd = -1;
+ }
+}
+
+/*
+ * fatal - log an error message and die horribly.
+ */
+void
+fatal __V((char *fmt, ...))
+{
+ va_list pvar;
+
+#if defined(__STDC__)
+ va_start(pvar, fmt);
+#else
+ char *fmt;
+ va_start(pvar);
+ fmt = va_arg(pvar, char *);
+#endif
+
+ logit(LOG_ERR, fmt, pvar);
+ va_end(pvar);
+
+ die(1); /* as promised */
+}
+
+/*
+ * error - log an error message.
+ */
+void
+error __V((char *fmt, ...))
+{
+ va_list pvar;
+
+#if defined(__STDC__)
+ va_start(pvar, fmt);
+#else
+ char *fmt;
+ va_start(pvar);
+ fmt = va_arg(pvar, char *);
+#endif
+
+ logit(LOG_ERR, fmt, pvar);
+ va_end(pvar);
+}
+
+/*
+ * warn - log a warning message.
+ */
+void
+warn __V((char *fmt, ...))
+{
+ va_list pvar;
+
+#if defined(__STDC__)
+ va_start(pvar, fmt);
+#else
+ char *fmt;
+ va_start(pvar);
+ fmt = va_arg(pvar, char *);
+#endif
+
+ logit(LOG_WARNING, fmt, pvar);
+ va_end(pvar);
+}
+
+/*
+ * notice - log a notice-level message.
+ */
+void
+notice __V((char *fmt, ...))
+{
+ va_list pvar;
+
+#if defined(__STDC__)
+ va_start(pvar, fmt);
+#else
+ char *fmt;
+ va_start(pvar);
+ fmt = va_arg(pvar, char *);
+#endif
+
+ logit(LOG_NOTICE, fmt, pvar);
+ va_end(pvar);
+}
+
+/*
+ * info - log an informational message.
+ */
+void
+info __V((char *fmt, ...))
+{
+ va_list pvar;
+
+#if defined(__STDC__)
+ va_start(pvar, fmt);
+#else
+ char *fmt;
+ va_start(pvar);
+ fmt = va_arg(pvar, char *);
+#endif
+
+ logit(LOG_INFO, fmt, pvar);
+ va_end(pvar);
+}
+
+/*
+ * dbglog - log a debug message.
+ */
+void
+dbglog __V((char *fmt, ...))
+{
+ va_list pvar;
+
+#if defined(__STDC__)
+ va_start(pvar, fmt);
+#else
+ char *fmt;
+ va_start(pvar);
+ fmt = va_arg(pvar, char *);
+#endif
+
+ logit(LOG_DEBUG, fmt, pvar);
+ va_end(pvar);
+}
+
+/* Procedures for locking the serial device using a lock file. */
+#ifndef LOCK_DIR
+#ifdef _linux_
+#define LOCK_DIR "/var/lock"
+#else
+#ifdef SVR4
+#define LOCK_DIR "/var/spool/locks"
+#else
+#define LOCK_DIR "/var/spool/lock"
+#endif
+#endif
+#endif /* LOCK_DIR */
+
+static char lock_file[MAXPATHLEN];
+
+/*
+ * lock - create a lock file for the named device
+ */
+int
+lock(dev)
+ char *dev;
+{
+#ifdef LOCKLIB
+ int result;
+
+ result = mklock (dev, (void *) 0);
+ if (result == 0) {
+ strlcpy(lock_file, sizeof(lock_file), dev);
+ return 0;
+ }
+
+ if (result > 0)
+ notice("Device %s is locked by pid %d", dev, result);
+ else
+ error("Can't create lock file %s", lock_file);
+ return -1;
+
+#else /* LOCKLIB */
+
+ char lock_buffer[12];
+ int fd, pid, n;
+
+#ifdef SVR4
+ struct stat sbuf;
+
+ if (stat(dev, &sbuf) < 0) {
+ error("Can't get device number for %s: %m", dev);
+ return -1;
+ }
+ if ((sbuf.st_mode & S_IFMT) != S_IFCHR) {
+ error("Can't lock %s: not a character device", dev);
+ return -1;
+ }
+ slprintf(lock_file, sizeof(lock_file), "%s/LK.%03d.%03d.%03d",
+ LOCK_DIR, major(sbuf.st_dev),
+ major(sbuf.st_rdev), minor(sbuf.st_rdev));
+#else
+ char *p;
+
+ if ((p = strrchr(dev, '/')) != NULL)
+ dev = p + 1;
+ slprintf(lock_file, sizeof(lock_file), "%s/LCK..%s", LOCK_DIR, dev);
+#endif
+
+ while ((fd = open(lock_file, O_EXCL | O_CREAT | O_RDWR, 0644)) < 0) {
+ if (errno != EEXIST) {
+ error("Can't create lock file %s: %m", lock_file);
+ break;
+ }
+
+ /* Read the lock file to find out who has the device locked. */
+ fd = open(lock_file, O_RDONLY, 0);
+ if (fd < 0) {
+ if (errno == ENOENT) /* This is just a timing problem. */
+ continue;
+ error("Can't open existing lock file %s: %m", lock_file);
+ break;
+ }
+#ifndef LOCK_BINARY
+ n = read(fd, lock_buffer, 11);
+#else
+ n = read(fd, &pid, sizeof(pid));
+#endif /* LOCK_BINARY */
+ close(fd);
+ fd = -1;
+ if (n <= 0) {
+ error("Can't read pid from lock file %s", lock_file);
+ break;
+ }
+
+ /* See if the process still exists. */
+#ifndef LOCK_BINARY
+ lock_buffer[n] = 0;
+ pid = atoi(lock_buffer);
+#endif /* LOCK_BINARY */
+ if (pid == getpid())
+ return 1; /* somebody else locked it for us */
+ if (pid == 0
+ || (kill(pid, 0) == -1 && errno == ESRCH)) {
+ if (unlink (lock_file) == 0) {
+ notice("Removed stale lock on %s (pid %d)", dev, pid);
+ continue;
+ }
+ warn("Couldn't remove stale lock on %s", dev);
+ } else
+ notice("Device %s is locked by pid %d", dev, pid);
+ break;
+ }
+
+ if (fd < 0) {
+ lock_file[0] = 0;
+ return -1;
+ }
+
+ pid = getpid();
+#ifndef LOCK_BINARY
+ slprintf(lock_buffer, sizeof(lock_buffer), "%10d\n", pid);
+ write (fd, lock_buffer, 11);
+#else
+ write(fd, &pid, sizeof (pid));
+#endif
+ close(fd);
+ return 0;
+
+#endif
+}
+
+/*
+ * relock - called to update our lockfile when we are about to detach,
+ * thus changing our pid (we fork, the child carries on, and the parent dies).
+ * Note that this is called by the parent, with pid equal to the pid
+ * of the child. This avoids a potential race which would exist if
+ * we had the child rewrite the lockfile (the parent might die first,
+ * and another process could think the lock was stale if it checked
+ * between when the parent died and the child rewrote the lockfile).
+ */
+int
+relock(pid)
+ int pid;
+{
+#ifdef LOCKLIB
+ /* XXX is there a way to do this? */
+ return -1;
+#else /* LOCKLIB */
+
+ int fd;
+ char lock_buffer[12];
+
+ if (lock_file[0] == 0)
+ return -1;
+ fd = open(lock_file, O_WRONLY, 0);
+ if (fd < 0) {
+ error("Couldn't reopen lock file %s: %m", lock_file);
+ lock_file[0] = 0;
+ return -1;
+ }
+
+#ifndef LOCK_BINARY
+ slprintf(lock_buffer, sizeof(lock_buffer), "%10d\n", pid);
+ write (fd, lock_buffer, 11);
+#else
+ write(fd, &pid, sizeof(pid));
+#endif /* LOCK_BINARY */
+ close(fd);
+ return 0;
+
+#endif /* LOCKLIB */
+}
+
+/*
+ * unlock - remove our lockfile
+ */
+void
+unlock()
+{
+ if (lock_file[0]) {
+#ifdef LOCKLIB
+ (void) rmlock(lock_file, (void *) 0);
+#else
+ unlink(lock_file);
+#endif
+ lock_file[0] = 0;
+ }
+}
+
diff --git a/mdk-stage1/ppp/pppdump/Makefile.linux b/mdk-stage1/ppp/pppdump/Makefile.linux
new file mode 100644
index 000000000..1d8d78ff7
--- /dev/null
+++ b/mdk-stage1/ppp/pppdump/Makefile.linux
@@ -0,0 +1,17 @@
+CFLAGS= -I../include/net $(RPM_OPT_FLAGS)
+OBJS = pppdump.o bsd-comp.o deflate.o zlib.o
+
+INSTALL= install
+
+all: pppdump
+
+pppdump: $(OBJS)
+ $(CC) $(RPM_OPT_FLAGS) -o pppdump $(OBJS)
+
+clean:
+ rm -f pppdump $(OBJS) *~
+
+install:
+ mkdir -p $(BINDIR) $(MANDIR)/man8
+ $(INSTALL) -s -c pppdump $(BINDIR)
+ $(INSTALL) -c pppdump.8 $(MANDIR)/man8
diff --git a/mdk-stage1/ppp/pppdump/Makefile.linux.makeopt b/mdk-stage1/ppp/pppdump/Makefile.linux.makeopt
new file mode 100644
index 000000000..d02fecde8
--- /dev/null
+++ b/mdk-stage1/ppp/pppdump/Makefile.linux.makeopt
@@ -0,0 +1,17 @@
+CFLAGS= -O -I../include/net
+OBJS = pppdump.o bsd-comp.o deflate.o zlib.o
+
+INSTALL= install
+
+all: pppdump
+
+pppdump: $(OBJS)
+ $(CC) -o pppdump $(OBJS)
+
+clean:
+ rm -f pppdump $(OBJS) *~
+
+install:
+ mkdir -p $(BINDIR) $(MANDIR)/man8
+ $(INSTALL) -s -c pppdump $(BINDIR)
+ $(INSTALL) -c -m 444 pppdump.8 $(MANDIR)/man8
diff --git a/mdk-stage1/ppp/pppdump/Makefile.linux.pppdump-Makefile b/mdk-stage1/ppp/pppdump/Makefile.linux.pppdump-Makefile
new file mode 100644
index 000000000..4c98b6c6d
--- /dev/null
+++ b/mdk-stage1/ppp/pppdump/Makefile.linux.pppdump-Makefile
@@ -0,0 +1,17 @@
+CFLAGS= -O -I../include/net
+OBJS = pppdump.o bsd-comp.o deflate.o zlib.o
+
+INSTALL= install
+
+all: pppdump
+
+pppdump: $(OBJS)
+ $(CC) $(RPM_OPT_FLAGS) -o pppdump $(OBJS)
+
+clean:
+ rm -f pppdump $(OBJS) *~
+
+install:
+ mkdir -p $(BINDIR) $(MANDIR)/man8
+ $(INSTALL) -s -c pppdump $(BINDIR)
+ $(INSTALL) -c -m 444 pppdump.8 $(MANDIR)/man8
diff --git a/mdk-stage1/ppp/pppdump/Makefile.sol2 b/mdk-stage1/ppp/pppdump/Makefile.sol2
new file mode 100644
index 000000000..bbd07ebff
--- /dev/null
+++ b/mdk-stage1/ppp/pppdump/Makefile.sol2
@@ -0,0 +1,21 @@
+#
+# pppdump Makefile for SVR4 systems
+# $Id: Makefile.sol2 195720 2001-06-11 11:44:34Z gc $
+#
+
+include ../solaris/Makedefs
+
+CFLAGS= $(COPTS) -I../include/net
+OBJS = pppdump.o bsd-comp.o deflate.o zlib.o
+
+all: pppdump
+
+pppdump: $(OBJS)
+ $(CC) -o pppdump $(OBJS)
+
+clean:
+ rm -f $(OBJS) pppdump *~
+
+install:
+ $(INSTALL) -f $(BINDIR) pppdump
+ $(INSTALL) -m 444 -f $(MANDIR)/man8 pppdump.8
diff --git a/mdk-stage1/ppp/pppdump/Makefile.sunos4 b/mdk-stage1/ppp/pppdump/Makefile.sunos4
new file mode 100644
index 000000000..5f60f747c
--- /dev/null
+++ b/mdk-stage1/ppp/pppdump/Makefile.sunos4
@@ -0,0 +1,21 @@
+#
+# pppstats makefile
+# $Id: Makefile.sunos4 195720 2001-06-11 11:44:34Z gc $
+#
+
+include ../sunos4/Makedefs
+
+OBJS = pppdump.o bsd-comp.o deflate.o zlib.o
+CFLAGS = $(COPTS) -I../include/net
+
+all: pppdump
+
+pppdump: $(OBJS)
+ $(CC) -o pppdump $(OBJS)
+
+clean:
+ rm -f pppdump $(OBJS) *~
+
+install: pppdump
+ $(INSTALL) -c pppdump $(BINDIR)/pppdump
+ $(INSTALL) -c -m 444 pppdump.8 $(MANDIR)/man8/pppdump.8
diff --git a/mdk-stage1/ppp/pppdump/bsd-comp.c b/mdk-stage1/ppp/pppdump/bsd-comp.c
new file mode 100644
index 000000000..cf3c18d35
--- /dev/null
+++ b/mdk-stage1/ppp/pppdump/bsd-comp.c
@@ -0,0 +1,750 @@
+/* Because this code is derived from the 4.3BSD compress source:
+ *
+ *
+ * Copyright (c) 1985, 1986 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * James A. Woods, derived from original work by Spencer Thomas
+ * and Joseph Orost.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * $Id: bsd-comp.c 195720 2001-06-11 11:44:34Z gc $
+ */
+
+#include <sys/types.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include "ppp_defs.h"
+#include "ppp-comp.h"
+
+#if DO_BSD_COMPRESS
+
+/*
+ * PPP "BSD compress" compression
+ * The differences between this compression and the classic BSD LZW
+ * source are obvious from the requirement that the classic code worked
+ * with files while this handles arbitrarily long streams that
+ * are broken into packets. They are:
+ *
+ * When the code size expands, a block of junk is not emitted by
+ * the compressor and not expected by the decompressor.
+ *
+ * New codes are not necessarily assigned every time an old
+ * code is output by the compressor. This is because a packet
+ * end forces a code to be emitted, but does not imply that a
+ * new sequence has been seen.
+ *
+ * The compression ratio is checked at the first end of a packet
+ * after the appropriate gap. Besides simplifying and speeding
+ * things up, this makes it more likely that the transmitter
+ * and receiver will agree when the dictionary is cleared when
+ * compression is not going well.
+ */
+
+/*
+ * A dictionary for doing BSD compress.
+ */
+struct bsd_db {
+ int totlen; /* length of this structure */
+ u_int hsize; /* size of the hash table */
+ u_char hshift; /* used in hash function */
+ u_char n_bits; /* current bits/code */
+ u_char maxbits;
+ u_char debug;
+ u_char unit;
+ u_short seqno; /* sequence number of next packet */
+ u_int hdrlen; /* header length to preallocate */
+ u_int mru;
+ u_int maxmaxcode; /* largest valid code */
+ u_int max_ent; /* largest code in use */
+ u_int in_count; /* uncompressed bytes, aged */
+ u_int bytes_out; /* compressed bytes, aged */
+ u_int ratio; /* recent compression ratio */
+ u_int checkpoint; /* when to next check the ratio */
+ u_int clear_count; /* times dictionary cleared */
+ u_int incomp_count; /* incompressible packets */
+ u_int incomp_bytes; /* incompressible bytes */
+ u_int uncomp_count; /* uncompressed packets */
+ u_int uncomp_bytes; /* uncompressed bytes */
+ u_int comp_count; /* compressed packets */
+ u_int comp_bytes; /* compressed bytes */
+ u_short *lens; /* array of lengths of codes */
+ struct bsd_dict {
+ union { /* hash value */
+ u_int32_t fcode;
+ struct {
+#ifdef BSD_LITTLE_ENDIAN
+ u_short prefix; /* preceding code */
+ u_char suffix; /* last character of new code */
+ u_char pad;
+#else
+ u_char pad;
+ u_char suffix; /* last character of new code */
+ u_short prefix; /* preceding code */
+#endif
+ } hs;
+ } f;
+ u_short codem1; /* output of hash table -1 */
+ u_short cptr; /* map code to hash table entry */
+ } dict[1];
+};
+
+#define BSD_OVHD 2 /* BSD compress overhead/packet */
+#define BSD_INIT_BITS BSD_MIN_BITS
+
+static void *bsd_decomp_alloc __P((u_char *options, int opt_len));
+static void bsd_free __P((void *state));
+static int bsd_decomp_init __P((void *state, u_char *options, int opt_len,
+ int unit, int hdrlen, int mru, int debug));
+static void bsd_incomp __P((void *state, u_char *dmsg, int len));
+static int bsd_decompress __P((void *state, u_char *cmp, int inlen,
+ u_char *dmp, int *outlen));
+static void bsd_reset __P((void *state));
+static void bsd_comp_stats __P((void *state, struct compstat *stats));
+
+/*
+ * Exported procedures.
+ */
+struct compressor ppp_bsd_compress = {
+ CI_BSD_COMPRESS, /* compress_proto */
+ bsd_decomp_alloc, /* decomp_alloc */
+ bsd_free, /* decomp_free */
+ bsd_decomp_init, /* decomp_init */
+ bsd_reset, /* decomp_reset */
+ bsd_decompress, /* decompress */
+ bsd_incomp, /* incomp */
+ bsd_comp_stats, /* decomp_stat */
+};
+
+/*
+ * the next two codes should not be changed lightly, as they must not
+ * lie within the contiguous general code space.
+ */
+#define CLEAR 256 /* table clear output code */
+#define FIRST 257 /* first free entry */
+#define LAST 255
+
+#define MAXCODE(b) ((1 << (b)) - 1)
+#define BADCODEM1 MAXCODE(BSD_MAX_BITS)
+
+#define BSD_HASH(prefix,suffix,hshift) ((((u_int32_t)(suffix)) << (hshift)) \
+ ^ (u_int32_t)(prefix))
+#define BSD_KEY(prefix,suffix) ((((u_int32_t)(suffix)) << 16) \
+ + (u_int32_t)(prefix))
+
+#define CHECK_GAP 10000 /* Ratio check interval */
+
+#define RATIO_SCALE_LOG 8
+#define RATIO_SCALE (1<<RATIO_SCALE_LOG)
+#define RATIO_MAX (0x7fffffff>>RATIO_SCALE_LOG)
+
+/*
+ * clear the dictionary
+ */
+static void
+bsd_clear(db)
+ struct bsd_db *db;
+{
+ db->clear_count++;
+ db->max_ent = FIRST-1;
+ db->n_bits = BSD_INIT_BITS;
+ db->ratio = 0;
+ db->bytes_out = 0;
+ db->in_count = 0;
+ db->checkpoint = CHECK_GAP;
+}
+
+/*
+ * If the dictionary is full, then see if it is time to reset it.
+ *
+ * Compute the compression ratio using fixed-point arithmetic
+ * with 8 fractional bits.
+ *
+ * Since we have an infinite stream instead of a single file,
+ * watch only the local compression ratio.
+ *
+ * Since both peers must reset the dictionary at the same time even in
+ * the absence of CLEAR codes (while packets are incompressible), they
+ * must compute the same ratio.
+ */
+static int /* 1=output CLEAR */
+bsd_check(db)
+ struct bsd_db *db;
+{
+ u_int new_ratio;
+
+ if (db->in_count >= db->checkpoint) {
+ /* age the ratio by limiting the size of the counts */
+ if (db->in_count >= RATIO_MAX
+ || db->bytes_out >= RATIO_MAX) {
+ db->in_count -= db->in_count/4;
+ db->bytes_out -= db->bytes_out/4;
+ }
+
+ db->checkpoint = db->in_count + CHECK_GAP;
+
+ if (db->max_ent >= db->maxmaxcode) {
+ /* Reset the dictionary only if the ratio is worse,
+ * or if it looks as if it has been poisoned
+ * by incompressible data.
+ *
+ * This does not overflow, because
+ * db->in_count <= RATIO_MAX.
+ */
+ new_ratio = db->in_count << RATIO_SCALE_LOG;
+ if (db->bytes_out != 0)
+ new_ratio /= db->bytes_out;
+
+ if (new_ratio < db->ratio || new_ratio < 1 * RATIO_SCALE) {
+ bsd_clear(db);
+ return 1;
+ }
+ db->ratio = new_ratio;
+ }
+ }
+ return 0;
+}
+
+/*
+ * Return statistics.
+ */
+static void
+bsd_comp_stats(state, stats)
+ void *state;
+ struct compstat *stats;
+{
+ struct bsd_db *db = (struct bsd_db *) state;
+ u_int out;
+
+ stats->unc_bytes = db->uncomp_bytes;
+ stats->unc_packets = db->uncomp_count;
+ stats->comp_bytes = db->comp_bytes;
+ stats->comp_packets = db->comp_count;
+ stats->inc_bytes = db->incomp_bytes;
+ stats->inc_packets = db->incomp_count;
+ stats->ratio = db->in_count;
+ out = db->bytes_out;
+ if (stats->ratio <= 0x7fffff)
+ stats->ratio <<= 8;
+ else
+ out >>= 8;
+ if (out != 0)
+ stats->ratio /= out;
+}
+
+/*
+ * Reset state, as on a CCP ResetReq.
+ */
+static void
+bsd_reset(state)
+ void *state;
+{
+ struct bsd_db *db = (struct bsd_db *) state;
+
+ db->seqno = 0;
+ bsd_clear(db);
+ db->clear_count = 0;
+}
+
+/*
+ * Allocate space for a (de) compressor.
+ */
+static void *
+bsd_alloc(options, opt_len, decomp)
+ u_char *options;
+ int opt_len, decomp;
+{
+ int bits;
+ u_int newlen, hsize, hshift, maxmaxcode;
+ struct bsd_db *db;
+
+ if (opt_len != 3 || options[0] != CI_BSD_COMPRESS || options[1] != 3
+ || BSD_VERSION(options[2]) != BSD_CURRENT_VERSION)
+ return NULL;
+
+ bits = BSD_NBITS(options[2]);
+ switch (bits) {
+ case 9: /* needs 82152 for both directions */
+ case 10: /* needs 84144 */
+ case 11: /* needs 88240 */
+ case 12: /* needs 96432 */
+ hsize = 5003;
+ hshift = 4;
+ break;
+ case 13: /* needs 176784 */
+ hsize = 9001;
+ hshift = 5;
+ break;
+ case 14: /* needs 353744 */
+ hsize = 18013;
+ hshift = 6;
+ break;
+ case 15: /* needs 691440 */
+ hsize = 35023;
+ hshift = 7;
+ break;
+ case 16: /* needs 1366160--far too much, */
+ /* hsize = 69001; */ /* and 69001 is too big for cptr */
+ /* hshift = 8; */ /* in struct bsd_db */
+ /* break; */
+ default:
+ return NULL;
+ }
+
+ maxmaxcode = MAXCODE(bits);
+ newlen = sizeof(*db) + (hsize-1) * (sizeof(db->dict[0]));
+ db = (struct bsd_db *) malloc(newlen);
+ if (!db)
+ return NULL;
+ memset(db, 0, sizeof(*db) - sizeof(db->dict));
+
+ if (!decomp) {
+ db->lens = NULL;
+ } else {
+ db->lens = (u_short *) malloc((maxmaxcode+1) * sizeof(db->lens[0]));
+ if (!db->lens) {
+ free(db);
+ return NULL;
+ }
+ }
+
+ db->totlen = newlen;
+ db->hsize = hsize;
+ db->hshift = hshift;
+ db->maxmaxcode = maxmaxcode;
+ db->maxbits = bits;
+
+ return (void *) db;
+}
+
+static void
+bsd_free(state)
+ void *state;
+{
+ struct bsd_db *db = (struct bsd_db *) state;
+
+ if (db->lens)
+ free(db->lens);
+ free(db);
+}
+
+static void *
+bsd_decomp_alloc(options, opt_len)
+ u_char *options;
+ int opt_len;
+{
+ return bsd_alloc(options, opt_len, 1);
+}
+
+/*
+ * Initialize the database.
+ */
+static int
+bsd_init(db, options, opt_len, unit, hdrlen, mru, debug, decomp)
+ struct bsd_db *db;
+ u_char *options;
+ int opt_len, unit, hdrlen, mru, debug, decomp;
+{
+ int i;
+
+ if (opt_len < CILEN_BSD_COMPRESS
+ || options[0] != CI_BSD_COMPRESS || options[1] != CILEN_BSD_COMPRESS
+ || BSD_VERSION(options[2]) != BSD_CURRENT_VERSION
+ || BSD_NBITS(options[2]) != db->maxbits
+ || decomp && db->lens == NULL)
+ return 0;
+
+ if (decomp) {
+ i = LAST+1;
+ while (i != 0)
+ db->lens[--i] = 1;
+ }
+ i = db->hsize;
+ while (i != 0) {
+ db->dict[--i].codem1 = BADCODEM1;
+ db->dict[i].cptr = 0;
+ }
+
+ db->unit = unit;
+ db->hdrlen = hdrlen;
+ db->mru = mru;
+ if (debug)
+ db->debug = 1;
+
+ bsd_reset(db);
+
+ return 1;
+}
+
+static int
+bsd_decomp_init(state, options, opt_len, unit, hdrlen, mru, debug)
+ void *state;
+ u_char *options;
+ int opt_len, unit, hdrlen, mru, debug;
+{
+ return bsd_init((struct bsd_db *) state, options, opt_len,
+ unit, hdrlen, mru, debug, 1);
+}
+
+
+/*
+ * Update the "BSD Compress" dictionary on the receiver for
+ * incompressible data by pretending to compress the incoming data.
+ */
+static void
+bsd_incomp(state, dmsg, mlen)
+ void *state;
+ u_char *dmsg;
+ int mlen;
+{
+ struct bsd_db *db = (struct bsd_db *) state;
+ u_int hshift = db->hshift;
+ u_int max_ent = db->max_ent;
+ u_int n_bits = db->n_bits;
+ struct bsd_dict *dictp;
+ u_int32_t fcode;
+ u_char c;
+ long hval, disp;
+ int slen, ilen;
+ u_int bitno = 7;
+ u_char *rptr;
+ u_int ent;
+
+ rptr = dmsg;
+ ent = rptr[0]; /* get the protocol */
+ if (ent == 0) {
+ ++rptr;
+ --mlen;
+ ent = rptr[0];
+ }
+ if ((ent & 1) == 0 || ent < 0x21 || ent > 0xf9)
+ return;
+
+ db->seqno++;
+ ilen = 1; /* count the protocol as 1 byte */
+ ++rptr;
+ slen = dmsg + mlen - rptr;
+ ilen += slen;
+ for (; slen > 0; --slen) {
+ c = *rptr++;
+ fcode = BSD_KEY(ent, c);
+ hval = BSD_HASH(ent, c, hshift);
+ dictp = &db->dict[hval];
+
+ /* validate and then check the entry */
+ if (dictp->codem1 >= max_ent)
+ goto nomatch;
+ if (dictp->f.fcode == fcode) {
+ ent = dictp->codem1+1;
+ continue; /* found (prefix,suffix) */
+ }
+
+ /* continue probing until a match or invalid entry */
+ disp = (hval == 0) ? 1 : hval;
+ do {
+ hval += disp;
+ if (hval >= db->hsize)
+ hval -= db->hsize;
+ dictp = &db->dict[hval];
+ if (dictp->codem1 >= max_ent)
+ goto nomatch;
+ } while (dictp->f.fcode != fcode);
+ ent = dictp->codem1+1;
+ continue; /* finally found (prefix,suffix) */
+
+ nomatch: /* output (count) the prefix */
+ bitno += n_bits;
+
+ /* code -> hashtable */
+ if (max_ent < db->maxmaxcode) {
+ struct bsd_dict *dictp2;
+ /* expand code size if needed */
+ if (max_ent >= MAXCODE(n_bits))
+ db->n_bits = ++n_bits;
+
+ /* Invalidate previous hash table entry
+ * assigned this code, and then take it over.
+ */
+ dictp2 = &db->dict[max_ent+1];
+ if (db->dict[dictp2->cptr].codem1 == max_ent)
+ db->dict[dictp2->cptr].codem1 = BADCODEM1;
+ dictp2->cptr = hval;
+ dictp->codem1 = max_ent;
+ dictp->f.fcode = fcode;
+
+ db->max_ent = ++max_ent;
+ db->lens[max_ent] = db->lens[ent]+1;
+ }
+ ent = c;
+ }
+ bitno += n_bits; /* output (count) the last code */
+ db->bytes_out += bitno/8;
+ db->in_count += ilen;
+ (void)bsd_check(db);
+
+ ++db->incomp_count;
+ db->incomp_bytes += ilen;
+ ++db->uncomp_count;
+ db->uncomp_bytes += ilen;
+
+ /* Increase code size if we would have without the packet
+ * boundary and as the decompressor will.
+ */
+ if (max_ent >= MAXCODE(n_bits) && max_ent < db->maxmaxcode)
+ db->n_bits++;
+}
+
+
+/*
+ * Decompress "BSD Compress"
+ *
+ * Because of patent problems, we return DECOMP_ERROR for errors
+ * found by inspecting the input data and for system problems, but
+ * DECOMP_FATALERROR for any errors which could possibly be said to
+ * be being detected "after" decompression. For DECOMP_ERROR,
+ * we can issue a CCP reset-request; for DECOMP_FATALERROR, we may be
+ * infringing a patent of Motorola's if we do, so we take CCP down
+ * instead.
+ *
+ * Given that the frame has the correct sequence number and a good FCS,
+ * errors such as invalid codes in the input most likely indicate a
+ * bug, so we return DECOMP_FATALERROR for them in order to turn off
+ * compression, even though they are detected by inspecting the input.
+ */
+static int
+bsd_decompress(state, cmsg, inlen, dmp, outlenp)
+ void *state;
+ u_char *cmsg, *dmp;
+ int inlen, *outlenp;
+{
+ struct bsd_db *db = (struct bsd_db *) state;
+ u_int max_ent = db->max_ent;
+ u_int32_t accm = 0;
+ u_int bitno = 32; /* 1st valid bit in accm */
+ u_int n_bits = db->n_bits;
+ u_int tgtbitno = 32-n_bits; /* bitno when we have a code */
+ struct bsd_dict *dictp;
+ int explen, i, seq, len;
+ u_int incode, oldcode, finchar;
+ u_char *p, *rptr, *wptr;
+ int ilen;
+ int dlen, space, codelen, extra;
+
+ rptr = cmsg;
+ if (*rptr == 0)
+ ++rptr;
+ ++rptr; /* skip protocol (assumed 0xfd) */
+ seq = (rptr[0] << 8) + rptr[1];
+ rptr += BSD_OVHD;
+ ilen = len = cmsg + inlen - rptr;
+
+ /*
+ * Check the sequence number and give up if it is not what we expect.
+ */
+ if (seq != db->seqno++) {
+ if (db->debug)
+ printf("bsd_decomp%d: bad sequence # %d, expected %d\n",
+ db->unit, seq, db->seqno - 1);
+ return DECOMP_ERROR;
+ }
+
+ wptr = dmp + db->hdrlen;
+
+ oldcode = CLEAR;
+ explen = 0;
+ while (len > 0) {
+ /*
+ * Accumulate bytes until we have a complete code.
+ * Then get the next code, relying on the 32-bit,
+ * unsigned accm to mask the result.
+ */
+ bitno -= 8;
+ accm |= *rptr++ << bitno;
+ --len;
+ if (tgtbitno < bitno)
+ continue;
+ incode = accm >> tgtbitno;
+ accm <<= n_bits;
+ bitno += n_bits;
+
+ if (incode == CLEAR) {
+ /*
+ * The dictionary must only be cleared at
+ * the end of a packet. But there could be an
+ * empty message block at the end.
+ */
+ if (len > 0) {
+ if (db->debug)
+ printf("bsd_decomp%d: bad CLEAR\n", db->unit);
+ return DECOMP_FATALERROR;
+ }
+ bsd_clear(db);
+ explen = ilen = 0;
+ break;
+ }
+
+ if (incode > max_ent + 2 || incode > db->maxmaxcode
+ || incode > max_ent && oldcode == CLEAR) {
+ if (db->debug) {
+ printf("bsd_decomp%d: bad code 0x%x oldcode=0x%x ",
+ db->unit, incode, oldcode);
+ printf("max_ent=0x%x dlen=%d seqno=%d\n",
+ max_ent, dlen, db->seqno);
+ }
+ return DECOMP_FATALERROR; /* probably a bug */
+ }
+
+ /* Special case for KwKwK string. */
+ if (incode > max_ent) {
+ finchar = oldcode;
+ extra = 1;
+ } else {
+ finchar = incode;
+ extra = 0;
+ }
+
+ codelen = db->lens[finchar];
+ explen += codelen + extra;
+ if (explen > db->mru + 1) {
+ if (db->debug)
+ printf("bsd_decomp%d: ran out of mru\n", db->unit);
+ return DECOMP_FATALERROR;
+ }
+
+ /*
+ * Decode this code and install it in the decompressed buffer.
+ */
+ p = (wptr += codelen);
+ while (finchar > LAST) {
+ dictp = &db->dict[db->dict[finchar].cptr];
+#ifdef DEBUG
+ --codelen;
+ if (codelen <= 0) {
+ printf("bsd_decomp%d: fell off end of chain ", db->unit);
+ printf("0x%x at 0x%x by 0x%x, max_ent=0x%x\n",
+ incode, finchar, db->dict[finchar].cptr, max_ent);
+ return DECOMP_FATALERROR;
+ }
+ if (dictp->codem1 != finchar-1) {
+ printf("bsd_decomp%d: bad code chain 0x%x finchar=0x%x ",
+ db->unit, incode, finchar);
+ printf("oldcode=0x%x cptr=0x%x codem1=0x%x\n", oldcode,
+ db->dict[finchar].cptr, dictp->codem1);
+ return DECOMP_FATALERROR;
+ }
+#endif
+ *--p = dictp->f.hs.suffix;
+ finchar = dictp->f.hs.prefix;
+ }
+ *--p = finchar;
+
+#ifdef DEBUG
+ if (--codelen != 0)
+ printf("bsd_decomp%d: short by %d after code 0x%x, max_ent=0x%x\n",
+ db->unit, codelen, incode, max_ent);
+#endif
+
+ if (extra) /* the KwKwK case again */
+ *wptr++ = finchar;
+
+ /*
+ * If not first code in a packet, and
+ * if not out of code space, then allocate a new code.
+ *
+ * Keep the hash table correct so it can be used
+ * with uncompressed packets.
+ */
+ if (oldcode != CLEAR && max_ent < db->maxmaxcode) {
+ struct bsd_dict *dictp2;
+ u_int32_t fcode;
+ int hval, disp;
+
+ fcode = BSD_KEY(oldcode,finchar);
+ hval = BSD_HASH(oldcode,finchar,db->hshift);
+ dictp = &db->dict[hval];
+
+ /* look for a free hash table entry */
+ if (dictp->codem1 < max_ent) {
+ disp = (hval == 0) ? 1 : hval;
+ do {
+ hval += disp;
+ if (hval >= db->hsize)
+ hval -= db->hsize;
+ dictp = &db->dict[hval];
+ } while (dictp->codem1 < max_ent);
+ }
+
+ /*
+ * Invalidate previous hash table entry
+ * assigned this code, and then take it over
+ */
+ dictp2 = &db->dict[max_ent+1];
+ if (db->dict[dictp2->cptr].codem1 == max_ent) {
+ db->dict[dictp2->cptr].codem1 = BADCODEM1;
+ }
+ dictp2->cptr = hval;
+ dictp->codem1 = max_ent;
+ dictp->f.fcode = fcode;
+
+ db->max_ent = ++max_ent;
+ db->lens[max_ent] = db->lens[oldcode]+1;
+
+ /* Expand code size if needed. */
+ if (max_ent >= MAXCODE(n_bits) && max_ent < db->maxmaxcode) {
+ db->n_bits = ++n_bits;
+ tgtbitno = 32-n_bits;
+ }
+ }
+ oldcode = incode;
+ }
+ *outlenp = wptr - (dmp + db->hdrlen);
+
+ /*
+ * Keep the checkpoint right so that incompressible packets
+ * clear the dictionary at the right times.
+ */
+ db->bytes_out += ilen;
+ db->in_count += explen;
+ if (bsd_check(db) && db->debug) {
+ printf("bsd_decomp%d: peer should have cleared dictionary\n",
+ db->unit);
+ }
+
+ ++db->comp_count;
+ db->comp_bytes += ilen + BSD_OVHD;
+ ++db->uncomp_count;
+ db->uncomp_bytes += explen;
+
+ return DECOMP_OK;
+}
+#endif /* DO_BSD_COMPRESS */
diff --git a/mdk-stage1/ppp/pppdump/deflate.c b/mdk-stage1/ppp/pppdump/deflate.c
new file mode 100644
index 000000000..812905bfe
--- /dev/null
+++ b/mdk-stage1/ppp/pppdump/deflate.c
@@ -0,0 +1,344 @@
+/*
+ * ppp_deflate.c - interface the zlib procedures for Deflate compression
+ * and decompression (as used by gzip) to the PPP code.
+ *
+ * Copyright (c) 1994 The Australian National University.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation is hereby granted, provided that the above copyright
+ * notice appears in all copies. This software is provided without any
+ * warranty, express or implied. The Australian National University
+ * makes no representations about the suitability of this software for
+ * any purpose.
+ *
+ * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
+ * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
+ * THE AUSTRALIAN NATIONAL UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
+ * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
+ * OR MODIFICATIONS.
+ *
+ * $Id: deflate.c 195720 2001-06-11 11:44:34Z gc $
+ */
+
+#include <sys/types.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include "ppp_defs.h"
+#include "ppp-comp.h"
+#include "zlib.h"
+
+#if DO_DEFLATE
+
+#define DEFLATE_DEBUG 1
+
+/*
+ * State for a Deflate (de)compressor.
+ */
+struct deflate_state {
+ int seqno;
+ int w_size;
+ int unit;
+ int hdrlen;
+ int mru;
+ int debug;
+ z_stream strm;
+ struct compstat stats;
+};
+
+#define DEFLATE_OVHD 2 /* Deflate overhead/packet */
+
+static void *z_alloc __P((void *, u_int items, u_int size));
+static void z_free __P((void *, void *ptr, u_int nb));
+static void *z_decomp_alloc __P((u_char *options, int opt_len));
+static void z_decomp_free __P((void *state));
+static int z_decomp_init __P((void *state, u_char *options, int opt_len,
+ int unit, int hdrlen, int mru, int debug));
+static void z_incomp __P((void *state, u_char *dmsg, int len));
+static int z_decompress __P((void *state, u_char *cmp, int inlen,
+ u_char *dmp, int *outlenp));
+static void z_decomp_reset __P((void *state));
+static void z_comp_stats __P((void *state, struct compstat *stats));
+
+/*
+ * Procedures exported to if_ppp.c.
+ */
+struct compressor ppp_deflate = {
+ CI_DEFLATE, /* compress_proto */
+ z_decomp_alloc, /* decomp_alloc */
+ z_decomp_free, /* decomp_free */
+ z_decomp_init, /* decomp_init */
+ z_decomp_reset, /* decomp_reset */
+ z_decompress, /* decompress */
+ z_incomp, /* incomp */
+ z_comp_stats, /* decomp_stat */
+};
+
+/*
+ * Space allocation and freeing routines for use by zlib routines.
+ */
+static void *
+z_alloc(notused, items, size)
+ void *notused;
+ u_int items, size;
+{
+ return malloc(items * size);
+}
+
+static void
+z_free(notused, ptr, nbytes)
+ void *notused;
+ void *ptr;
+ u_int nbytes;
+{
+ free(ptr);
+}
+
+static void
+z_comp_stats(arg, stats)
+ void *arg;
+ struct compstat *stats;
+{
+ struct deflate_state *state = (struct deflate_state *) arg;
+ u_int out;
+
+ *stats = state->stats;
+ stats->ratio = stats->unc_bytes;
+ out = stats->comp_bytes + stats->unc_bytes;
+ if (stats->ratio <= 0x7ffffff)
+ stats->ratio <<= 8;
+ else
+ out >>= 8;
+ if (out != 0)
+ stats->ratio /= out;
+}
+
+/*
+ * Allocate space for a decompressor.
+ */
+static void *
+z_decomp_alloc(options, opt_len)
+ u_char *options;
+ int opt_len;
+{
+ struct deflate_state *state;
+ int w_size;
+
+ if (opt_len != CILEN_DEFLATE || options[0] != CI_DEFLATE
+ || options[1] != CILEN_DEFLATE
+ || DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL
+ || options[3] != DEFLATE_CHK_SEQUENCE)
+ return NULL;
+ w_size = DEFLATE_SIZE(options[2]);
+ if (w_size < DEFLATE_MIN_SIZE || w_size > DEFLATE_MAX_SIZE)
+ return NULL;
+
+ state = (struct deflate_state *) malloc(sizeof(*state));
+ if (state == NULL)
+ return NULL;
+
+ state->strm.next_out = NULL;
+ state->strm.zalloc = (alloc_func) z_alloc;
+ state->strm.zfree = (free_func) z_free;
+ if (inflateInit2(&state->strm, -w_size) != Z_OK) {
+ free(state);
+ return NULL;
+ }
+
+ state->w_size = w_size;
+ memset(&state->stats, 0, sizeof(state->stats));
+ return (void *) state;
+}
+
+static void
+z_decomp_free(arg)
+ void *arg;
+{
+ struct deflate_state *state = (struct deflate_state *) arg;
+
+ inflateEnd(&state->strm);
+ free(state);
+}
+
+static int
+z_decomp_init(arg, options, opt_len, unit, hdrlen, mru, debug)
+ void *arg;
+ u_char *options;
+ int opt_len, unit, hdrlen, mru, debug;
+{
+ struct deflate_state *state = (struct deflate_state *) arg;
+
+ if (opt_len < CILEN_DEFLATE || options[0] != CI_DEFLATE
+ || options[1] != CILEN_DEFLATE
+ || DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL
+ || DEFLATE_SIZE(options[2]) != state->w_size
+ || options[3] != DEFLATE_CHK_SEQUENCE)
+ return 0;
+
+ state->seqno = 0;
+ state->unit = unit;
+ state->hdrlen = hdrlen;
+ state->debug = debug;
+ state->mru = mru;
+
+ inflateReset(&state->strm);
+
+ return 1;
+}
+
+static void
+z_decomp_reset(arg)
+ void *arg;
+{
+ struct deflate_state *state = (struct deflate_state *) arg;
+
+ state->seqno = 0;
+ inflateReset(&state->strm);
+}
+
+/*
+ * Decompress a Deflate-compressed packet.
+ *
+ * Because of patent problems, we return DECOMP_ERROR for errors
+ * found by inspecting the input data and for system problems, but
+ * DECOMP_FATALERROR for any errors which could possibly be said to
+ * be being detected "after" decompression. For DECOMP_ERROR,
+ * we can issue a CCP reset-request; for DECOMP_FATALERROR, we may be
+ * infringing a patent of Motorola's if we do, so we take CCP down
+ * instead.
+ *
+ * Given that the frame has the correct sequence number and a good FCS,
+ * errors such as invalid codes in the input most likely indicate a
+ * bug, so we return DECOMP_FATALERROR for them in order to turn off
+ * compression, even though they are detected by inspecting the input.
+ */
+static int
+z_decompress(arg, mi, inlen, mo, outlenp)
+ void *arg;
+ u_char *mi, *mo;
+ int inlen, *outlenp;
+{
+ struct deflate_state *state = (struct deflate_state *) arg;
+ u_char *rptr, *wptr;
+ int rlen, olen, ospace;
+ int seq, i, flush, r, decode_proto;
+
+ rptr = mi;
+ if (*rptr == 0)
+ ++rptr;
+ ++rptr;
+
+ /* Check the sequence number. */
+ seq = (rptr[0] << 8) + rptr[1];
+ rptr += 2;
+ if (seq != state->seqno) {
+#if !DEFLATE_DEBUG
+ if (state->debug)
+#endif
+ printf("z_decompress%d: bad seq # %d, expected %d\n",
+ state->unit, seq, state->seqno);
+ return DECOMP_ERROR;
+ }
+ ++state->seqno;
+
+ /*
+ * Set up to call inflate.
+ */
+ wptr = mo;
+ state->strm.next_in = rptr;
+ state->strm.avail_in = mi + inlen - rptr;
+ rlen = state->strm.avail_in + PPP_HDRLEN + DEFLATE_OVHD;
+ state->strm.next_out = wptr;
+ state->strm.avail_out = state->mru + 2;
+
+ r = inflate(&state->strm, Z_PACKET_FLUSH);
+ if (r != Z_OK) {
+#if !DEFLATE_DEBUG
+ if (state->debug)
+#endif
+ printf("z_decompress%d: inflate returned %d (%s)\n",
+ state->unit, r, (state->strm.msg? state->strm.msg: ""));
+ return DECOMP_FATALERROR;
+ }
+ olen = state->mru + 2 - state->strm.avail_out;
+ *outlenp = olen;
+
+ if ((wptr[0] & 1) != 0)
+ ++olen; /* for suppressed protocol high byte */
+ olen += 2; /* for address, control */
+
+#if DEFLATE_DEBUG
+ if (olen > state->mru + PPP_HDRLEN)
+ printf("ppp_deflate%d: exceeded mru (%d > %d)\n",
+ state->unit, olen, state->mru + PPP_HDRLEN);
+#endif
+
+ state->stats.unc_bytes += olen;
+ state->stats.unc_packets++;
+ state->stats.comp_bytes += rlen;
+ state->stats.comp_packets++;
+
+ return DECOMP_OK;
+}
+
+/*
+ * Incompressible data has arrived - add it to the history.
+ */
+static void
+z_incomp(arg, mi, mlen)
+ void *arg;
+ u_char *mi;
+ int mlen;
+{
+ struct deflate_state *state = (struct deflate_state *) arg;
+ u_char *rptr;
+ int rlen, proto, r;
+
+ /*
+ * Check that the protocol is one we handle.
+ */
+ rptr = mi;
+ proto = rptr[0];
+ if ((proto & 1) == 0)
+ proto = (proto << 8) + rptr[1];
+ if (proto > 0x3fff || proto == 0xfd || proto == 0xfb)
+ return;
+
+ ++state->seqno;
+
+ if (rptr[0] == 0)
+ ++rptr;
+ rlen = mi + mlen - rptr;
+ state->strm.next_in = rptr;
+ state->strm.avail_in = rlen;
+ r = inflateIncomp(&state->strm);
+ if (r != Z_OK) {
+ /* gak! */
+#if !DEFLATE_DEBUG
+ if (state->debug)
+#endif
+ printf("z_incomp%d: inflateIncomp returned %d (%s)\n",
+ state->unit, r, (state->strm.msg? state->strm.msg: ""));
+ return;
+ }
+
+ /*
+ * Update stats.
+ */
+ if (proto <= 0xff)
+ ++rlen;
+ rlen += 2;
+ state->stats.inc_bytes += rlen;
+ state->stats.inc_packets++;
+ state->stats.unc_bytes += rlen;
+ state->stats.unc_packets++;
+}
+
+#endif /* DO_DEFLATE */
diff --git a/mdk-stage1/ppp/pppdump/ppp-comp.h b/mdk-stage1/ppp/pppdump/ppp-comp.h
new file mode 100644
index 000000000..7608c393d
--- /dev/null
+++ b/mdk-stage1/ppp/pppdump/ppp-comp.h
@@ -0,0 +1,150 @@
+/*
+ * ppp-comp.h - Definitions for doing PPP packet compression.
+ *
+ * Copyright (c) 1994 The Australian National University.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation is hereby granted, provided that the above copyright
+ * notice appears in all copies. This software is provided without any
+ * warranty, express or implied. The Australian National University
+ * makes no representations about the suitability of this software for
+ * any purpose.
+ *
+ * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
+ * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
+ * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
+ * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
+ * OR MODIFICATIONS.
+ *
+ * $Id: ppp-comp.h 195720 2001-06-11 11:44:34Z gc $
+ */
+
+#ifndef _NET_PPP_COMP_H
+#define _NET_PPP_COMP_H
+
+/*
+ * The following symbols control whether we include code for
+ * various compression methods.
+ */
+#ifndef DO_BSD_COMPRESS
+#define DO_BSD_COMPRESS 1 /* by default, include BSD-Compress */
+#endif
+#ifndef DO_DEFLATE
+#define DO_DEFLATE 1 /* by default, include Deflate */
+#endif
+#define DO_PREDICTOR_1 0
+#define DO_PREDICTOR_2 0
+
+/*
+ * Structure giving methods for compression/decompression.
+ */
+struct compressor {
+ int compress_proto; /* CCP compression protocol number */
+
+ /* Allocate space for a decompressor (receive side) */
+ void *(*decomp_alloc) __P((u_char *options, int opt_len));
+ /* Free space used by a decompressor */
+ void (*decomp_free) __P((void *state));
+ /* Initialize a decompressor */
+ int (*decomp_init) __P((void *state, u_char *options, int opt_len,
+ int unit, int hdrlen, int mru, int debug));
+ /* Reset a decompressor */
+ void (*decomp_reset) __P((void *state));
+ /* Decompress a packet. */
+ int (*decompress) __P((void *state, u_char *mp, int inlen,
+ u_char *dmp, int *outlen));
+ /* Update state for an incompressible packet received */
+ void (*incomp) __P((void *state, u_char *mp, int len));
+ /* Return decompression statistics */
+ void (*decomp_stat) __P((void *state, struct compstat *stats));
+};
+
+/*
+ * Return values for decompress routine.
+ * We need to make these distinctions so that we can disable certain
+ * useful functionality, namely sending a CCP reset-request as a result
+ * of an error detected after decompression. This is to avoid infringing
+ * a patent held by Motorola.
+ * Don't you just lurve software patents.
+ */
+#define DECOMP_OK 0 /* everything went OK */
+#define DECOMP_ERROR 1 /* error detected before decomp. */
+#define DECOMP_FATALERROR 2 /* error detected after decomp. */
+
+/*
+ * CCP codes.
+ */
+#define CCP_CONFREQ 1
+#define CCP_CONFACK 2
+#define CCP_CONFNAK 3
+#define CCP_CONFREJ 4
+#define CCP_TERMREQ 5
+#define CCP_TERMACK 6
+#define CCP_RESETREQ 14
+#define CCP_RESETACK 15
+
+/*
+ * Max # bytes for a CCP option
+ */
+#define CCP_MAX_OPTION_LENGTH 32
+
+/*
+ * Parts of a CCP packet.
+ */
+#define CCP_CODE(dp) ((dp)[0])
+#define CCP_ID(dp) ((dp)[1])
+#define CCP_LENGTH(dp) (((dp)[2] << 8) + (dp)[3])
+#define CCP_HDRLEN 4
+
+#define CCP_OPT_CODE(dp) ((dp)[0])
+#define CCP_OPT_LENGTH(dp) ((dp)[1])
+#define CCP_OPT_MINLEN 2
+
+/*
+ * Definitions for BSD-Compress.
+ */
+#define CI_BSD_COMPRESS 21 /* config. option for BSD-Compress */
+#define CILEN_BSD_COMPRESS 3 /* length of config. option */
+
+/* Macros for handling the 3rd byte of the BSD-Compress config option. */
+#define BSD_NBITS(x) ((x) & 0x1F) /* number of bits requested */
+#define BSD_VERSION(x) ((x) >> 5) /* version of option format */
+#define BSD_CURRENT_VERSION 1 /* current version number */
+#define BSD_MAKE_OPT(v, n) (((v) << 5) | (n))
+
+#define BSD_MIN_BITS 9 /* smallest code size supported */
+#define BSD_MAX_BITS 15 /* largest code size supported */
+
+/*
+ * Definitions for Deflate.
+ */
+#define CI_DEFLATE 26 /* config option for Deflate */
+#define CI_DEFLATE_DRAFT 24 /* value used in original draft RFC */
+#define CILEN_DEFLATE 4 /* length of its config option */
+
+#define DEFLATE_MIN_SIZE 8
+#define DEFLATE_MAX_SIZE 15
+#define DEFLATE_METHOD_VAL 8
+#define DEFLATE_SIZE(x) (((x) >> 4) + DEFLATE_MIN_SIZE)
+#define DEFLATE_METHOD(x) ((x) & 0x0F)
+#define DEFLATE_MAKE_OPT(w) ((((w) - DEFLATE_MIN_SIZE) << 4) \
+ + DEFLATE_METHOD_VAL)
+#define DEFLATE_CHK_SEQUENCE 0
+
+/*
+ * Definitions for other, as yet unsupported, compression methods.
+ */
+#define CI_PREDICTOR_1 1 /* config option for Predictor-1 */
+#define CILEN_PREDICTOR_1 2 /* length of its config option */
+#define CI_PREDICTOR_2 2 /* config option for Predictor-2 */
+#define CILEN_PREDICTOR_2 2 /* length of its config option */
+
+#endif /* _NET_PPP_COMP_H */
diff --git a/mdk-stage1/ppp/pppdump/pppdump.8 b/mdk-stage1/ppp/pppdump/pppdump.8
new file mode 100644
index 000000000..b908eeed7
--- /dev/null
+++ b/mdk-stage1/ppp/pppdump/pppdump.8
@@ -0,0 +1,62 @@
+.\" @(#) $Id: pppdump.8 195720 2001-06-11 11:44:34Z gc $
+.TH PPPDUMP 8 "1 April 1999"
+.SH NAME
+pppdump \- convert PPP record file to readable format
+.SH SYNOPSIS
+.B pppdump
+[
+.B -h
+|
+.B -p
+[
+.B -d
+]] [
+.B -r
+] [
+.B -m \fImru
+] [
+.I file \fR...
+]
+.ti 12
+.SH DESCRIPTION
+The
+.B pppdump
+utility converts the files written using the \fIrecord\fR option of
+.B pppd
+into a human-readable format. If one or more filenames are specified,
+.B pppdump
+will read each in turn; otherwise it will read its standard input. In
+each case the result is written to standard output.
+.PP
+The options are as follows:
+.TP
+.B -h
+Prints the bytes sent and received in hexadecimal. If neither this
+option nor the \fB-p\fR option is specified, the bytes are printed as
+the characters themselves, with non-printing and non-ASCII characters
+printed as escape sequences.
+.TP
+.B -p
+Collects the bytes sent and received into PPP packets, interpreting
+the async HDLC framing and escape characters and checking the FCS
+(frame check sequence) of each packet. The packets are printed as hex
+values and as characters (non-printable characters are printed as
+`.').
+.TP
+.B -d
+With the \fB-p\fR option, this option causes
+.B pppdump
+to decompress packets which have been compressed with the BSD-Compress
+or Deflate methods.
+.TP
+.B -r
+Reverses the direction indicators, so that `sent' is printed for
+bytes or packets received, and `rcvd' is printed for bytes or packets
+sent.
+.TP
+.B -m \fImru
+Use \fImru\fR as the MRU (maximum receive unit) for both directions of
+the link when checking for over-length PPP packets (with the \fB-p\fR
+option).
+.SH SEE ALSO
+pppd(8)
diff --git a/mdk-stage1/ppp/pppdump/pppdump.c b/mdk-stage1/ppp/pppdump/pppdump.c
new file mode 100644
index 000000000..a8e69d4bf
--- /dev/null
+++ b/mdk-stage1/ppp/pppdump/pppdump.c
@@ -0,0 +1,502 @@
+/*
+ * pppdump - print out the contents of a record file generated by
+ * pppd in readable form.
+ *
+ * Copyright (C) 1999 Paul Mackerras. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms. The name of the author
+ * may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+#include <stdio.h>
+#include <unistd.h>
+#include <time.h>
+#include <sys/types.h>
+#include "ppp_defs.h"
+#include "ppp-comp.h"
+
+int hexmode;
+int pppmode;
+int reverse;
+int decompress;
+int mru = 1500;
+int abs_times;
+time_t start_time;
+int start_time_tenths;
+int tot_sent, tot_rcvd;
+
+extern int optind;
+extern char *optarg;
+
+main(ac, av)
+ int ac;
+ char **av;
+{
+ int i;
+ char *p;
+ FILE *f;
+
+ while ((i = getopt(ac, av, "hprdm:a")) != -1) {
+ switch (i) {
+ case 'h':
+ hexmode = 1;
+ break;
+ case 'p':
+ pppmode = 1;
+ break;
+ case 'r':
+ reverse = 1;
+ break;
+ case 'd':
+ decompress = 1;
+ break;
+ case 'm':
+ mru = atoi(optarg);
+ break;
+ case 'a':
+ abs_times = 1;
+ break;
+ default:
+ fprintf(stderr, "Usage: %s [-h | -p[d]] [-r] [-m mru] [-a] [file ...]\n", av[0]);
+ exit(1);
+ }
+ }
+ if (optind >= ac)
+ dumplog(stdin);
+ else {
+ for (i = optind; i < ac; ++i) {
+ p = av[i];
+ if ((f = fopen(p, "r")) == NULL) {
+ perror(p);
+ exit(1);
+ }
+ if (pppmode)
+ dumpppp(f);
+ else
+ dumplog(f);
+ fclose(f);
+ }
+ }
+ exit(0);
+}
+
+dumplog(f)
+ FILE *f;
+{
+ int c, n, k, col;
+ int nb, c2;
+ unsigned char buf[16];
+
+ while ((c = getc(f)) != EOF) {
+ switch (c) {
+ case 1:
+ case 2:
+ if (reverse)
+ c = 3 - c;
+ printf("%s %c", c==1? "sent": "rcvd", hexmode? ' ': '"');
+ col = 6;
+ n = getc(f);
+ n = (n << 8) + getc(f);
+ *(c==1? &tot_sent: &tot_rcvd) += n;
+ nb = 0;
+ for (; n > 0; --n) {
+ c = getc(f);
+ if (c == EOF) {
+ printf("\nEOF\n");
+ exit(0);
+ }
+ if (hexmode) {
+ if (nb >= 16) {
+ printf(" ");
+ for (k = 0; k < nb; ++k) {
+ c2 = buf[k];
+ putchar((' ' <= c2 && c2 <= '~')? c2: '.');
+ }
+ printf("\n ");
+ nb = 0;
+ }
+ buf[nb++] = c;
+ printf(" %.2x", c);
+ } else {
+ k = (' ' <= c && c <= '~')? (c != '\\' && c != '"')? 1: 2: 3;
+ if ((col += k) >= 78) {
+ printf("\n ");
+ col = 6 + k;
+ }
+ switch (k) {
+ case 1:
+ putchar(c);
+ break;
+ case 2:
+ printf("\\%c", c);
+ break;
+ case 3:
+ printf("\\%.2x", c);
+ break;
+ }
+ }
+ }
+ if (hexmode) {
+ for (k = nb; k < 16; ++k)
+ printf(" ");
+ printf(" ");
+ for (k = 0; k < nb; ++k) {
+ c2 = buf[k];
+ putchar((' ' <= c2 && c2 <= '~')? c2: '.');
+ }
+ } else
+ putchar('"');
+ printf("\n");
+ break;
+ case 3:
+ case 4:
+ printf("end %s\n", c==3? "send": "recv");
+ break;
+ case 5:
+ case 6:
+ case 7:
+ show_time(f, c);
+ break;
+ default:
+ printf("?%.2x\n");
+ }
+ }
+}
+
+/*
+ * FCS lookup table as calculated by genfcstab.
+ */
+static u_short fcstab[256] = {
+ 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
+ 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
+ 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
+ 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
+ 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
+ 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
+ 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
+ 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
+ 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
+ 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
+ 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
+ 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
+ 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
+ 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
+ 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
+ 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
+ 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
+ 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
+ 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
+ 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
+ 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
+ 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
+ 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
+ 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
+ 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
+ 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
+ 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
+ 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
+ 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
+ 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
+ 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
+ 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
+};
+
+struct pkt {
+ int cnt;
+ int esc;
+ int flags;
+ struct compressor *comp;
+ void *state;
+ unsigned char buf[8192];
+} spkt, rpkt;
+
+/* Values for flags */
+#define CCP_ISUP 1
+#define CCP_ERROR 2
+#define CCP_FATALERROR 4
+#define CCP_ERR (CCP_ERROR | CCP_FATALERROR)
+#define CCP_DECOMP_RUN 8
+
+unsigned char dbuf[8192];
+
+dumpppp(f)
+ FILE *f;
+{
+ int c, n, k;
+ int nb, nl, dn, proto, rv;
+ char *dir, *q;
+ unsigned char *p, *r, *endp;
+ unsigned char *d;
+ unsigned short fcs;
+ struct pkt *pkt;
+
+ spkt.cnt = rpkt.cnt = 0;
+ spkt.esc = rpkt.esc = 0;
+ while ((c = getc(f)) != EOF) {
+ switch (c) {
+ case 1:
+ case 2:
+ if (reverse)
+ c = 3 - c;
+ dir = c==1? "sent": "rcvd";
+ pkt = c==1? &spkt: &rpkt;
+ n = getc(f);
+ n = (n << 8) + getc(f);
+ *(c==1? &tot_sent: &tot_rcvd) += n;
+ for (; n > 0; --n) {
+ c = getc(f);
+ switch (c) {
+ case EOF:
+ printf("\nEOF\n");
+ if (spkt.cnt > 0)
+ printf("[%d bytes in incomplete send packet]\n",
+ spkt.cnt);
+ if (rpkt.cnt > 0)
+ printf("[%d bytes in incomplete recv packet]\n",
+ rpkt.cnt);
+ exit(0);
+ case '~':
+ if (pkt->cnt > 0) {
+ q = dir;
+ if (pkt->esc) {
+ printf("%s aborted packet:\n ", dir);
+ q = " ";
+ }
+ nb = pkt->cnt;
+ p = pkt->buf;
+ pkt->cnt = 0;
+ pkt->esc = 0;
+ if (nb <= 2) {
+ printf("%s short packet [%d bytes]:", q, nb);
+ for (k = 0; k < nb; ++k)
+ printf(" %.2x", p[k]);
+ printf("\n");
+ break;
+ }
+ fcs = PPP_INITFCS;
+ for (k = 0; k < nb; ++k)
+ fcs = PPP_FCS(fcs, p[k]);
+ fcs &= 0xFFFF;
+ nb -= 2;
+ endp = p + nb;
+ r = p;
+ if (r[0] == 0xff && r[1] == 3)
+ r += 2;
+ if ((r[0] & 1) == 0)
+ ++r;
+ ++r;
+ if (endp - r > mru)
+ printf(" ERROR: length (%d) > MRU (%d)\n",
+ endp - r, mru);
+ if (decompress && fcs == PPP_GOODFCS) {
+ /* See if this is a CCP or compressed packet */
+ d = dbuf;
+ r = p;
+ if (r[0] == 0xff && r[1] == 3) {
+ *d++ = *r++;
+ *d++ = *r++;
+ }
+ proto = r[0];
+ if ((proto & 1) == 0)
+ proto = (proto << 8) + r[1];
+ if (proto == PPP_CCP) {
+ handle_ccp(pkt, r + 2, endp - r - 2);
+ } else if (proto == PPP_COMP) {
+ if ((pkt->flags & CCP_ISUP)
+ && (pkt->flags & CCP_DECOMP_RUN)
+ && pkt->state
+ && (pkt->flags & CCP_ERR) == 0) {
+ rv = pkt->comp->decompress(pkt->state, r,
+ endp - r, d, &dn);
+ switch (rv) {
+ case DECOMP_OK:
+ p = dbuf;
+ nb = d + dn - p;
+ if ((d[0] & 1) == 0)
+ --dn;
+ --dn;
+ if (dn > mru)
+ printf(" ERROR: decompressed length (%d) > MRU (%d)\n", dn, mru);
+ break;
+ case DECOMP_ERROR:
+ printf(" DECOMPRESSION ERROR\n");
+ pkt->flags |= CCP_ERROR;
+ break;
+ case DECOMP_FATALERROR:
+ printf(" FATAL DECOMPRESSION ERROR\n");
+ pkt->flags |= CCP_FATALERROR;
+ break;
+ }
+ }
+ } else if (pkt->state
+ && (pkt->flags & CCP_DECOMP_RUN)) {
+ pkt->comp->incomp(pkt->state, r, endp - r);
+ }
+ }
+ do {
+ nl = nb < 16? nb: 16;
+ printf("%s ", q);
+ for (k = 0; k < nl; ++k)
+ printf(" %.2x", p[k]);
+ for (; k < 16; ++k)
+ printf(" ");
+ printf(" ");
+ for (k = 0; k < nl; ++k) {
+ c = p[k];
+ putchar((' ' <= c && c <= '~')? c: '.');
+ }
+ printf("\n");
+ q = " ";
+ p += nl;
+ nb -= nl;
+ } while (nb > 0);
+ if (fcs != PPP_GOODFCS)
+ printf(" BAD FCS: (residue = %x)\n", fcs);
+ }
+ break;
+ case '}':
+ if (!pkt->esc) {
+ pkt->esc = 1;
+ break;
+ }
+ /* else fall through */
+ default:
+ if (pkt->esc) {
+ c ^= 0x20;
+ pkt->esc = 0;
+ }
+ pkt->buf[pkt->cnt++] = c;
+ break;
+ }
+ }
+ break;
+ case 3:
+ case 4:
+ if (reverse)
+ c = 7 - c;
+ dir = c==3? "send": "recv";
+ pkt = c==3? &spkt: &rpkt;
+ printf("end %s", dir);
+ if (pkt->cnt > 0)
+ printf(" [%d bytes in incomplete packet]", pkt->cnt);
+ printf("\n");
+ break;
+ case 5:
+ case 6:
+ case 7:
+ show_time(f, c);
+ break;
+ default:
+ printf("?%.2x\n");
+ }
+ }
+}
+
+extern struct compressor ppp_bsd_compress, ppp_deflate;
+
+struct compressor *compressors[] = {
+#if DO_BSD_COMPRESS
+ &ppp_bsd_compress,
+#endif
+#if DO_DEFLATE
+ &ppp_deflate,
+#endif
+ NULL
+};
+
+handle_ccp(cp, dp, len)
+ struct pkt *cp;
+ u_char *dp;
+ int len;
+{
+ int clen;
+ struct compressor **comp;
+
+ if (len < CCP_HDRLEN)
+ return;
+ clen = CCP_LENGTH(dp);
+ if (clen > len)
+ return;
+
+ switch (CCP_CODE(dp)) {
+ case CCP_CONFACK:
+ cp->flags &= ~(CCP_DECOMP_RUN | CCP_ISUP);
+ if (clen < CCP_HDRLEN + CCP_OPT_MINLEN
+ || clen < CCP_HDRLEN + CCP_OPT_LENGTH(dp + CCP_HDRLEN))
+ break;
+ dp += CCP_HDRLEN;
+ clen -= CCP_HDRLEN;
+ for (comp = compressors; *comp != NULL; ++comp) {
+ if ((*comp)->compress_proto == dp[0]) {
+ if (cp->state != NULL) {
+ (*cp->comp->decomp_free)(cp->state);
+ cp->state = NULL;
+ }
+ cp->comp = *comp;
+ cp->state = (*comp)->decomp_alloc(dp, CCP_OPT_LENGTH(dp));
+ cp->flags |= CCP_ISUP;
+ if (cp->state != NULL
+ && (*cp->comp->decomp_init)
+ (cp->state, dp, clen, 0, 0, 8192, 1))
+ cp->flags = (cp->flags & ~CCP_ERR) | CCP_DECOMP_RUN;
+ break;
+ }
+ }
+ break;
+
+ case CCP_CONFNAK:
+ case CCP_CONFREJ:
+ cp->flags &= ~(CCP_DECOMP_RUN | CCP_ISUP);
+ break;
+
+ case CCP_RESETACK:
+ if (cp->flags & CCP_ISUP) {
+ if (cp->state && (cp->flags & CCP_DECOMP_RUN)) {
+ (*cp->comp->decomp_reset)(cp->state);
+ cp->flags &= ~CCP_ERROR;
+ }
+ }
+ break;
+ }
+}
+
+show_time(f, c)
+ FILE *f;
+ int c;
+{
+ time_t t;
+ int n;
+ struct tm *tm;
+
+ if (c == 7) {
+ t = getc(f);
+ t = (t << 8) + getc(f);
+ t = (t << 8) + getc(f);
+ t = (t << 8) + getc(f);
+ printf("start %s", ctime(&t));
+ start_time = t;
+ start_time_tenths = 0;
+ tot_sent = tot_rcvd = 0;
+ } else {
+ n = getc(f);
+ if (c == 5) {
+ for (c = 3; c > 0; --c)
+ n = (n << 8) + getc(f);
+ }
+ if (abs_times) {
+ n += start_time_tenths;
+ start_time += n / 10;
+ start_time_tenths = n % 10;
+ tm = localtime(&start_time);
+ printf("time %.2d:%.2d:%.2d.%d", tm->tm_hour, tm->tm_min,
+ tm->tm_sec, start_time_tenths);
+ printf(" (sent %d, rcvd %d)\n", tot_sent, tot_rcvd);
+ } else
+ printf("time %.1fs\n", (double) n / 10);
+ }
+}
diff --git a/mdk-stage1/ppp/pppdump/zlib.c b/mdk-stage1/ppp/pppdump/zlib.c
new file mode 100644
index 000000000..8b6a8a138
--- /dev/null
+++ b/mdk-stage1/ppp/pppdump/zlib.c
@@ -0,0 +1,4614 @@
+/*
+ * This file is derived from various .h and .c files from the zlib-0.95
+ * distribution by Jean-loup Gailly and Mark Adler, with some additions
+ * by Paul Mackerras to aid in implementing Deflate compression and
+ * decompression for PPP packets. See zlib.h for conditions of
+ * distribution and use.
+ *
+ * Changes that have been made include:
+ * - changed functions not used outside this file to "local"
+ * - added minCompression parameter to deflateInit2
+ * - added Z_PACKET_FLUSH (see zlib.h for details)
+ * - added inflateIncomp
+ *
+ * $Id: zlib.c 195720 2001-06-11 11:44:34Z gc $
+ */
+
+
+/*+++++*/
+/* zutil.h -- internal interface and configuration of the compression library
+ * Copyright (C) 1995 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+/* From: zutil.h,v 1.9 1995/05/03 17:27:12 jloup Exp */
+
+#define _Z_UTIL_H
+
+#include "zlib.h"
+
+#ifdef STDC
+# include <string.h>
+#endif
+
+#ifndef local
+# define local static
+#endif
+/* compile with -Dlocal if your debugger can't find static symbols */
+
+#define FAR
+
+typedef unsigned char uch;
+typedef uch FAR uchf;
+typedef unsigned short ush;
+typedef ush FAR ushf;
+typedef unsigned long ulg;
+
+extern char *z_errmsg[]; /* indexed by 1-zlib_error */
+
+#define ERR_RETURN(strm,err) return (strm->msg=z_errmsg[1-err], err)
+/* To be used only when the state is known to be valid */
+
+#ifndef NULL
+#define NULL ((void *) 0)
+#endif
+
+ /* common constants */
+
+#define DEFLATED 8
+
+#ifndef DEF_WBITS
+# define DEF_WBITS MAX_WBITS
+#endif
+/* default windowBits for decompression. MAX_WBITS is for compression only */
+
+#if MAX_MEM_LEVEL >= 8
+# define DEF_MEM_LEVEL 8
+#else
+# define DEF_MEM_LEVEL MAX_MEM_LEVEL
+#endif
+/* default memLevel */
+
+#define STORED_BLOCK 0
+#define STATIC_TREES 1
+#define DYN_TREES 2
+/* The three kinds of block type */
+
+#define MIN_MATCH 3
+#define MAX_MATCH 258
+/* The minimum and maximum match lengths */
+
+ /* functions */
+
+#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY)
+# define HAVE_MEMCPY
+#endif
+#ifdef HAVE_MEMCPY
+# define zmemcpy memcpy
+# define zmemzero(dest, len) memset(dest, 0, len)
+#else
+# define zmemcpy(d, s, n) bcopy((s), (d), (n))
+# define zmemzero bzero
+#endif
+
+/* Diagnostic functions */
+#ifdef DEBUG_ZLIB
+# include <stdio.h>
+# ifndef verbose
+# define verbose 0
+# endif
+# define Assert(cond,msg) {if(!(cond)) z_error(msg);}
+# define Trace(x) fprintf x
+# define Tracev(x) {if (verbose) fprintf x ;}
+# define Tracevv(x) {if (verbose>1) fprintf x ;}
+# define Tracec(c,x) {if (verbose && (c)) fprintf x ;}
+# define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;}
+#else
+# define Assert(cond,msg)
+# define Trace(x)
+# define Tracev(x)
+# define Tracevv(x)
+# define Tracec(c,x)
+# define Tracecv(c,x)
+#endif
+
+
+typedef uLong (*check_func) OF((uLong check, Bytef *buf, uInt len));
+
+/* voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size)); */
+/* void zcfree OF((voidpf opaque, voidpf ptr)); */
+
+#define ZALLOC(strm, items, size) \
+ (*((strm)->zalloc))((strm)->opaque, (items), (size))
+#define ZFREE(strm, addr, size) \
+ (*((strm)->zfree))((strm)->opaque, (voidpf)(addr), (size))
+#define TRY_FREE(s, p, n) {if (p) ZFREE(s, p, n);}
+
+/* deflate.h -- internal compression state
+ * Copyright (C) 1995 Jean-loup Gailly
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+
+/*+++++*/
+/* From: deflate.h,v 1.5 1995/05/03 17:27:09 jloup Exp */
+
+/* ===========================================================================
+ * Internal compression state.
+ */
+
+/* Data type */
+#define BINARY 0
+#define ASCII 1
+#define UNKNOWN 2
+
+#define LENGTH_CODES 29
+/* number of length codes, not counting the special END_BLOCK code */
+
+#define LITERALS 256
+/* number of literal bytes 0..255 */
+
+#define L_CODES (LITERALS+1+LENGTH_CODES)
+/* number of Literal or Length codes, including the END_BLOCK code */
+
+#define D_CODES 30
+/* number of distance codes */
+
+#define BL_CODES 19
+/* number of codes used to transfer the bit lengths */
+
+#define HEAP_SIZE (2*L_CODES+1)
+/* maximum heap size */
+
+#define MAX_BITS 15
+/* All codes must not exceed MAX_BITS bits */
+
+#define INIT_STATE 42
+#define BUSY_STATE 113
+#define FLUSH_STATE 124
+#define FINISH_STATE 666
+/* Stream status */
+
+
+/* Data structure describing a single value and its code string. */
+typedef struct ct_data_s {
+ union {
+ ush freq; /* frequency count */
+ ush code; /* bit string */
+ } fc;
+ union {
+ ush dad; /* father node in Huffman tree */
+ ush len; /* length of bit string */
+ } dl;
+} FAR ct_data;
+
+#define Freq fc.freq
+#define Code fc.code
+#define Dad dl.dad
+#define Len dl.len
+
+typedef struct static_tree_desc_s static_tree_desc;
+
+typedef struct tree_desc_s {
+ ct_data *dyn_tree; /* the dynamic tree */
+ int max_code; /* largest code with non zero frequency */
+ static_tree_desc *stat_desc; /* the corresponding static tree */
+} FAR tree_desc;
+
+typedef ush Pos;
+typedef Pos FAR Posf;
+typedef unsigned IPos;
+
+/* A Pos is an index in the character window. We use short instead of int to
+ * save space in the various tables. IPos is used only for parameter passing.
+ */
+
+typedef struct deflate_state {
+ z_stream *strm; /* pointer back to this zlib stream */
+ int status; /* as the name implies */
+ Bytef *pending_buf; /* output still pending */
+ Bytef *pending_out; /* next pending byte to output to the stream */
+ int pending; /* nb of bytes in the pending buffer */
+ uLong adler; /* adler32 of uncompressed data */
+ int noheader; /* suppress zlib header and adler32 */
+ Byte data_type; /* UNKNOWN, BINARY or ASCII */
+ Byte method; /* STORED (for zip only) or DEFLATED */
+ int minCompr; /* min size decrease for Z_FLUSH_NOSTORE */
+
+ /* used by deflate.c: */
+
+ uInt w_size; /* LZ77 window size (32K by default) */
+ uInt w_bits; /* log2(w_size) (8..16) */
+ uInt w_mask; /* w_size - 1 */
+
+ Bytef *window;
+ /* Sliding window. Input bytes are read into the second half of the window,
+ * and move to the first half later to keep a dictionary of at least wSize
+ * bytes. With this organization, matches are limited to a distance of
+ * wSize-MAX_MATCH bytes, but this ensures that IO is always
+ * performed with a length multiple of the block size. Also, it limits
+ * the window size to 64K, which is quite useful on MSDOS.
+ * To do: use the user input buffer as sliding window.
+ */
+
+ ulg window_size;
+ /* Actual size of window: 2*wSize, except when the user input buffer
+ * is directly used as sliding window.
+ */
+
+ Posf *prev;
+ /* Link to older string with same hash index. To limit the size of this
+ * array to 64K, this link is maintained only for the last 32K strings.
+ * An index in this array is thus a window index modulo 32K.
+ */
+
+ Posf *head; /* Heads of the hash chains or NIL. */
+
+ uInt ins_h; /* hash index of string to be inserted */
+ uInt hash_size; /* number of elements in hash table */
+ uInt hash_bits; /* log2(hash_size) */
+ uInt hash_mask; /* hash_size-1 */
+
+ uInt hash_shift;
+ /* Number of bits by which ins_h must be shifted at each input
+ * step. It must be such that after MIN_MATCH steps, the oldest
+ * byte no longer takes part in the hash key, that is:
+ * hash_shift * MIN_MATCH >= hash_bits
+ */
+
+ long block_start;
+ /* Window position at the beginning of the current output block. Gets
+ * negative when the window is moved backwards.
+ */
+
+ uInt match_length; /* length of best match */
+ IPos prev_match; /* previous match */
+ int match_available; /* set if previous match exists */
+ uInt strstart; /* start of string to insert */
+ uInt match_start; /* start of matching string */
+ uInt lookahead; /* number of valid bytes ahead in window */
+
+ uInt prev_length;
+ /* Length of the best match at previous step. Matches not greater than this
+ * are discarded. This is used in the lazy match evaluation.
+ */
+
+ uInt max_chain_length;
+ /* To speed up deflation, hash chains are never searched beyond this
+ * length. A higher limit improves compression ratio but degrades the
+ * speed.
+ */
+
+ uInt max_lazy_match;
+ /* Attempt to find a better match only when the current match is strictly
+ * smaller than this value. This mechanism is used only for compression
+ * levels >= 4.
+ */
+# define max_insert_length max_lazy_match
+ /* Insert new strings in the hash table only if the match length is not
+ * greater than this length. This saves time but degrades compression.
+ * max_insert_length is used only for compression levels <= 3.
+ */
+
+ int level; /* compression level (1..9) */
+ int strategy; /* favor or force Huffman coding*/
+
+ uInt good_match;
+ /* Use a faster search when the previous match is longer than this */
+
+ int nice_match; /* Stop searching when current match exceeds this */
+
+ /* used by trees.c: */
+ /* Didn't use ct_data typedef below to supress compiler warning */
+ struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */
+ struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */
+ struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */
+
+ struct tree_desc_s l_desc; /* desc. for literal tree */
+ struct tree_desc_s d_desc; /* desc. for distance tree */
+ struct tree_desc_s bl_desc; /* desc. for bit length tree */
+
+ ush bl_count[MAX_BITS+1];
+ /* number of codes at each bit length for an optimal tree */
+
+ int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */
+ int heap_len; /* number of elements in the heap */
+ int heap_max; /* element of largest frequency */
+ /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.
+ * The same heap array is used to build all trees.
+ */
+
+ uch depth[2*L_CODES+1];
+ /* Depth of each subtree used as tie breaker for trees of equal frequency
+ */
+
+ uchf *l_buf; /* buffer for literals or lengths */
+
+ uInt lit_bufsize;
+ /* Size of match buffer for literals/lengths. There are 4 reasons for
+ * limiting lit_bufsize to 64K:
+ * - frequencies can be kept in 16 bit counters
+ * - if compression is not successful for the first block, all input
+ * data is still in the window so we can still emit a stored block even
+ * when input comes from standard input. (This can also be done for
+ * all blocks if lit_bufsize is not greater than 32K.)
+ * - if compression is not successful for a file smaller than 64K, we can
+ * even emit a stored file instead of a stored block (saving 5 bytes).
+ * This is applicable only for zip (not gzip or zlib).
+ * - creating new Huffman trees less frequently may not provide fast
+ * adaptation to changes in the input data statistics. (Take for
+ * example a binary file with poorly compressible code followed by
+ * a highly compressible string table.) Smaller buffer sizes give
+ * fast adaptation but have of course the overhead of transmitting
+ * trees more frequently.
+ * - I can't count above 4
+ */
+
+ uInt last_lit; /* running index in l_buf */
+
+ ushf *d_buf;
+ /* Buffer for distances. To simplify the code, d_buf and l_buf have
+ * the same number of elements. To use different lengths, an extra flag
+ * array would be necessary.
+ */
+
+ ulg opt_len; /* bit length of current block with optimal trees */
+ ulg static_len; /* bit length of current block with static trees */
+ ulg compressed_len; /* total bit length of compressed file */
+ uInt matches; /* number of string matches in current block */
+ int last_eob_len; /* bit length of EOB code for last block */
+
+#ifdef DEBUG_ZLIB
+ ulg bits_sent; /* bit length of the compressed data */
+#endif
+
+ ush bi_buf;
+ /* Output buffer. bits are inserted starting at the bottom (least
+ * significant bits).
+ */
+ int bi_valid;
+ /* Number of valid bits in bi_buf. All bits above the last valid bit
+ * are always zero.
+ */
+
+ uInt blocks_in_packet;
+ /* Number of blocks produced since the last time Z_PACKET_FLUSH
+ * was used.
+ */
+
+} FAR deflate_state;
+
+/* Output a byte on the stream.
+ * IN assertion: there is enough room in pending_buf.
+ */
+#define put_byte(s, c) {s->pending_buf[s->pending++] = (c);}
+
+
+#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
+/* Minimum amount of lookahead, except at the end of the input file.
+ * See deflate.c for comments about the MIN_MATCH+1.
+ */
+
+#define MAX_DIST(s) ((s)->w_size-MIN_LOOKAHEAD)
+/* In order to simplify the code, particularly on 16 bit machines, match
+ * distances are limited to MAX_DIST instead of WSIZE.
+ */
+
+ /* in trees.c */
+local void ct_init OF((deflate_state *s));
+local int ct_tally OF((deflate_state *s, int dist, int lc));
+local ulg ct_flush_block OF((deflate_state *s, charf *buf, ulg stored_len,
+ int flush));
+local void ct_align OF((deflate_state *s));
+local void ct_stored_block OF((deflate_state *s, charf *buf, ulg stored_len,
+ int eof));
+local void ct_stored_type_only OF((deflate_state *s));
+
+
+/*+++++*/
+/* deflate.c -- compress data using the deflation algorithm
+ * Copyright (C) 1995 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/*
+ * ALGORITHM
+ *
+ * The "deflation" process depends on being able to identify portions
+ * of the input text which are identical to earlier input (within a
+ * sliding window trailing behind the input currently being processed).
+ *
+ * The most straightforward technique turns out to be the fastest for
+ * most input files: try all possible matches and select the longest.
+ * The key feature of this algorithm is that insertions into the string
+ * dictionary are very simple and thus fast, and deletions are avoided
+ * completely. Insertions are performed at each input character, whereas
+ * string matches are performed only when the previous match ends. So it
+ * is preferable to spend more time in matches to allow very fast string
+ * insertions and avoid deletions. The matching algorithm for small
+ * strings is inspired from that of Rabin & Karp. A brute force approach
+ * is used to find longer strings when a small match has been found.
+ * A similar algorithm is used in comic (by Jan-Mark Wams) and freeze
+ * (by Leonid Broukhis).
+ * A previous version of this file used a more sophisticated algorithm
+ * (by Fiala and Greene) which is guaranteed to run in linear amortized
+ * time, but has a larger average cost, uses more memory and is patented.
+ * However the F&G algorithm may be faster for some highly redundant
+ * files if the parameter max_chain_length (described below) is too large.
+ *
+ * ACKNOWLEDGEMENTS
+ *
+ * The idea of lazy evaluation of matches is due to Jan-Mark Wams, and
+ * I found it in 'freeze' written by Leonid Broukhis.
+ * Thanks to many people for bug reports and testing.
+ *
+ * REFERENCES
+ *
+ * Deutsch, L.P.,"'Deflate' Compressed Data Format Specification".
+ * Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc
+ *
+ * A description of the Rabin and Karp algorithm is given in the book
+ * "Algorithms" by R. Sedgewick, Addison-Wesley, p252.
+ *
+ * Fiala,E.R., and Greene,D.H.
+ * Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595
+ *
+ */
+
+/* From: deflate.c,v 1.8 1995/05/03 17:27:08 jloup Exp */
+
+local char zlib_copyright[] = " deflate Copyright 1995 Jean-loup Gailly ";
+/*
+ If you use the zlib library in a product, an acknowledgment is welcome
+ in the documentation of your product. If for some reason you cannot
+ include such an acknowledgment, I would appreciate that you keep this
+ copyright string in the executable of your product.
+ */
+
+#define NIL 0
+/* Tail of hash chains */
+
+#ifndef TOO_FAR
+# define TOO_FAR 4096
+#endif
+/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */
+
+#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
+/* Minimum amount of lookahead, except at the end of the input file.
+ * See deflate.c for comments about the MIN_MATCH+1.
+ */
+
+/* Values for max_lazy_match, good_match and max_chain_length, depending on
+ * the desired pack level (0..9). The values given below have been tuned to
+ * exclude worst case performance for pathological files. Better values may be
+ * found for specific files.
+ */
+
+typedef struct config_s {
+ ush good_length; /* reduce lazy search above this match length */
+ ush max_lazy; /* do not perform lazy search above this match length */
+ ush nice_length; /* quit search above this match length */
+ ush max_chain;
+} config;
+
+local config configuration_table[10] = {
+/* good lazy nice chain */
+/* 0 */ {0, 0, 0, 0}, /* store only */
+/* 1 */ {4, 4, 8, 4}, /* maximum speed, no lazy matches */
+/* 2 */ {4, 5, 16, 8},
+/* 3 */ {4, 6, 32, 32},
+
+/* 4 */ {4, 4, 16, 16}, /* lazy matches */
+/* 5 */ {8, 16, 32, 32},
+/* 6 */ {8, 16, 128, 128},
+/* 7 */ {8, 32, 128, 256},
+/* 8 */ {32, 128, 258, 1024},
+/* 9 */ {32, 258, 258, 4096}}; /* maximum compression */
+
+/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4
+ * For deflate_fast() (levels <= 3) good is ignored and lazy has a different
+ * meaning.
+ */
+
+#define EQUAL 0
+/* result of memcmp for equal strings */
+
+/* ===========================================================================
+ * Prototypes for local functions.
+ */
+
+local void fill_window OF((deflate_state *s));
+local int deflate_fast OF((deflate_state *s, int flush));
+local int deflate_slow OF((deflate_state *s, int flush));
+local void lm_init OF((deflate_state *s));
+local int longest_match OF((deflate_state *s, IPos cur_match));
+local void putShortMSB OF((deflate_state *s, uInt b));
+local void flush_pending OF((z_stream *strm));
+local int read_buf OF((z_stream *strm, charf *buf, unsigned size));
+#ifdef ASMV
+ void match_init OF((void)); /* asm code initialization */
+#endif
+
+#ifdef DEBUG_ZLIB
+local void check_match OF((deflate_state *s, IPos start, IPos match,
+ int length));
+#endif
+
+
+/* ===========================================================================
+ * Update a hash value with the given input byte
+ * IN assertion: all calls to to UPDATE_HASH are made with consecutive
+ * input characters, so that a running hash key can be computed from the
+ * previous key instead of complete recalculation each time.
+ */
+#define UPDATE_HASH(s,h,c) (h = (((h)<<s->hash_shift) ^ (c)) & s->hash_mask)
+
+
+/* ===========================================================================
+ * Insert string str in the dictionary and set match_head to the previous head
+ * of the hash chain (the most recent string with same hash key). Return
+ * the previous length of the hash chain.
+ * IN assertion: all calls to to INSERT_STRING are made with consecutive
+ * input characters and the first MIN_MATCH bytes of str are valid
+ * (except for the last MIN_MATCH-1 bytes of the input file).
+ */
+#define INSERT_STRING(s, str, match_head) \
+ (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \
+ s->prev[(str) & s->w_mask] = match_head = s->head[s->ins_h], \
+ s->head[s->ins_h] = (str))
+
+/* ===========================================================================
+ * Initialize the hash table (avoiding 64K overflow for 16 bit systems).
+ * prev[] will be initialized on the fly.
+ */
+#define CLEAR_HASH(s) \
+ s->head[s->hash_size-1] = NIL; \
+ zmemzero((charf *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head));
+
+/* ========================================================================= */
+int deflateInit (strm, level)
+ z_stream *strm;
+ int level;
+{
+ return deflateInit2 (strm, level, DEFLATED, MAX_WBITS, DEF_MEM_LEVEL,
+ 0, 0);
+ /* To do: ignore strm->next_in if we use it as window */
+}
+
+/* ========================================================================= */
+int deflateInit2 (strm, level, method, windowBits, memLevel,
+ strategy, minCompression)
+ z_stream *strm;
+ int level;
+ int method;
+ int windowBits;
+ int memLevel;
+ int strategy;
+ int minCompression;
+{
+ deflate_state *s;
+ int noheader = 0;
+
+ if (strm == Z_NULL) return Z_STREAM_ERROR;
+
+ strm->msg = Z_NULL;
+/* if (strm->zalloc == Z_NULL) strm->zalloc = zcalloc; */
+/* if (strm->zfree == Z_NULL) strm->zfree = zcfree; */
+
+ if (level == Z_DEFAULT_COMPRESSION) level = 6;
+
+ if (windowBits < 0) { /* undocumented feature: suppress zlib header */
+ noheader = 1;
+ windowBits = -windowBits;
+ }
+ if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != DEFLATED ||
+ windowBits < 8 || windowBits > 15 || level < 1 || level > 9) {
+ return Z_STREAM_ERROR;
+ }
+ s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state));
+ if (s == Z_NULL) return Z_MEM_ERROR;
+ strm->state = (struct internal_state FAR *)s;
+ s->strm = strm;
+
+ s->noheader = noheader;
+ s->w_bits = windowBits;
+ s->w_size = 1 << s->w_bits;
+ s->w_mask = s->w_size - 1;
+
+ s->hash_bits = memLevel + 7;
+ s->hash_size = 1 << s->hash_bits;
+ s->hash_mask = s->hash_size - 1;
+ s->hash_shift = ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH);
+
+ s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte));
+ s->prev = (Posf *) ZALLOC(strm, s->w_size, sizeof(Pos));
+ s->head = (Posf *) ZALLOC(strm, s->hash_size, sizeof(Pos));
+
+ s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */
+
+ s->pending_buf = (uchf *) ZALLOC(strm, s->lit_bufsize, 2*sizeof(ush));
+
+ if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL ||
+ s->pending_buf == Z_NULL) {
+ strm->msg = z_errmsg[1-Z_MEM_ERROR];
+ deflateEnd (strm);
+ return Z_MEM_ERROR;
+ }
+ s->d_buf = (ushf *) &(s->pending_buf[s->lit_bufsize]);
+ s->l_buf = (uchf *) &(s->pending_buf[3*s->lit_bufsize]);
+ /* We overlay pending_buf and d_buf+l_buf. This works since the average
+ * output size for (length,distance) codes is <= 32 bits (worst case
+ * is 15+15+13=33).
+ */
+
+ s->level = level;
+ s->strategy = strategy;
+ s->method = (Byte)method;
+ s->minCompr = minCompression;
+ s->blocks_in_packet = 0;
+
+ return deflateReset(strm);
+}
+
+/* ========================================================================= */
+int deflateReset (strm)
+ z_stream *strm;
+{
+ deflate_state *s;
+
+ if (strm == Z_NULL || strm->state == Z_NULL ||
+ strm->zalloc == Z_NULL || strm->zfree == Z_NULL) return Z_STREAM_ERROR;
+
+ strm->total_in = strm->total_out = 0;
+ strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */
+ strm->data_type = Z_UNKNOWN;
+
+ s = (deflate_state *)strm->state;
+ s->pending = 0;
+ s->pending_out = s->pending_buf;
+
+ if (s->noheader < 0) {
+ s->noheader = 0; /* was set to -1 by deflate(..., Z_FINISH); */
+ }
+ s->status = s->noheader ? BUSY_STATE : INIT_STATE;
+ s->adler = 1;
+
+ ct_init(s);
+ lm_init(s);
+
+ return Z_OK;
+}
+
+/* =========================================================================
+ * Put a short in the pending buffer. The 16-bit value is put in MSB order.
+ * IN assertion: the stream state is correct and there is enough room in
+ * pending_buf.
+ */
+local void putShortMSB (s, b)
+ deflate_state *s;
+ uInt b;
+{
+ put_byte(s, (Byte)(b >> 8));
+ put_byte(s, (Byte)(b & 0xff));
+}
+
+/* =========================================================================
+ * Flush as much pending output as possible.
+ */
+local void flush_pending(strm)
+ z_stream *strm;
+{
+ deflate_state *state = (deflate_state *) strm->state;
+ unsigned len = state->pending;
+
+ if (len > strm->avail_out) len = strm->avail_out;
+ if (len == 0) return;
+
+ if (strm->next_out != NULL) {
+ zmemcpy(strm->next_out, state->pending_out, len);
+ strm->next_out += len;
+ }
+ state->pending_out += len;
+ strm->total_out += len;
+ strm->avail_out -= len;
+ state->pending -= len;
+ if (state->pending == 0) {
+ state->pending_out = state->pending_buf;
+ }
+}
+
+/* ========================================================================= */
+int deflate (strm, flush)
+ z_stream *strm;
+ int flush;
+{
+ deflate_state *state = (deflate_state *) strm->state;
+
+ if (strm == Z_NULL || state == Z_NULL) return Z_STREAM_ERROR;
+
+ if (strm->next_in == Z_NULL && strm->avail_in != 0) {
+ ERR_RETURN(strm, Z_STREAM_ERROR);
+ }
+ if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR);
+
+ state->strm = strm; /* just in case */
+
+ /* Write the zlib header */
+ if (state->status == INIT_STATE) {
+
+ uInt header = (DEFLATED + ((state->w_bits-8)<<4)) << 8;
+ uInt level_flags = (state->level-1) >> 1;
+
+ if (level_flags > 3) level_flags = 3;
+ header |= (level_flags << 6);
+ header += 31 - (header % 31);
+
+ state->status = BUSY_STATE;
+ putShortMSB(state, header);
+ }
+
+ /* Flush as much pending output as possible */
+ if (state->pending != 0) {
+ flush_pending(strm);
+ if (strm->avail_out == 0) return Z_OK;
+ }
+
+ /* If we came back in here to get the last output from
+ * a previous flush, we're done for now.
+ */
+ if (state->status == FLUSH_STATE) {
+ state->status = BUSY_STATE;
+ if (flush != Z_NO_FLUSH && flush != Z_FINISH)
+ return Z_OK;
+ }
+
+ /* User must not provide more input after the first FINISH: */
+ if (state->status == FINISH_STATE && strm->avail_in != 0) {
+ ERR_RETURN(strm, Z_BUF_ERROR);
+ }
+
+ /* Start a new block or continue the current one.
+ */
+ if (strm->avail_in != 0 || state->lookahead != 0 ||
+ (flush == Z_FINISH && state->status != FINISH_STATE)) {
+ int quit;
+
+ if (flush == Z_FINISH) {
+ state->status = FINISH_STATE;
+ }
+ if (state->level <= 3) {
+ quit = deflate_fast(state, flush);
+ } else {
+ quit = deflate_slow(state, flush);
+ }
+ if (quit || strm->avail_out == 0)
+ return Z_OK;
+ /* If flush != Z_NO_FLUSH && avail_out == 0, the next call
+ * of deflate should use the same flush parameter to make sure
+ * that the flush is complete. So we don't have to output an
+ * empty block here, this will be done at next call. This also
+ * ensures that for a very small output buffer, we emit at most
+ * one empty block.
+ */
+ }
+
+ /* If a flush was requested, we have a little more to output now. */
+ if (flush != Z_NO_FLUSH && flush != Z_FINISH
+ && state->status != FINISH_STATE) {
+ switch (flush) {
+ case Z_PARTIAL_FLUSH:
+ ct_align(state);
+ break;
+ case Z_PACKET_FLUSH:
+ /* Output just the 3-bit `stored' block type value,
+ but not a zero length. */
+ ct_stored_type_only(state);
+ break;
+ default:
+ ct_stored_block(state, (char*)0, 0L, 0);
+ /* For a full flush, this empty block will be recognized
+ * as a special marker by inflate_sync().
+ */
+ if (flush == Z_FULL_FLUSH) {
+ CLEAR_HASH(state); /* forget history */
+ }
+ }
+ flush_pending(strm);
+ if (strm->avail_out == 0) {
+ /* We'll have to come back to get the rest of the output;
+ * this ensures we don't output a second zero-length stored
+ * block (or whatever).
+ */
+ state->status = FLUSH_STATE;
+ return Z_OK;
+ }
+ }
+
+ Assert(strm->avail_out > 0, "bug2");
+
+ if (flush != Z_FINISH) return Z_OK;
+ if (state->noheader) return Z_STREAM_END;
+
+ /* Write the zlib trailer (adler32) */
+ putShortMSB(state, (uInt)(state->adler >> 16));
+ putShortMSB(state, (uInt)(state->adler & 0xffff));
+ flush_pending(strm);
+ /* If avail_out is zero, the application will call deflate again
+ * to flush the rest.
+ */
+ state->noheader = -1; /* write the trailer only once! */
+ return state->pending != 0 ? Z_OK : Z_STREAM_END;
+}
+
+/* ========================================================================= */
+int deflateEnd (strm)
+ z_stream *strm;
+{
+ deflate_state *state = (deflate_state *) strm->state;
+
+ if (strm == Z_NULL || state == Z_NULL) return Z_STREAM_ERROR;
+
+ TRY_FREE(strm, state->window, state->w_size * 2 * sizeof(Byte));
+ TRY_FREE(strm, state->prev, state->w_size * sizeof(Pos));
+ TRY_FREE(strm, state->head, state->hash_size * sizeof(Pos));
+ TRY_FREE(strm, state->pending_buf, state->lit_bufsize * 2 * sizeof(ush));
+
+ ZFREE(strm, state, sizeof(deflate_state));
+ strm->state = Z_NULL;
+
+ return Z_OK;
+}
+
+/* ===========================================================================
+ * Read a new buffer from the current input stream, update the adler32
+ * and total number of bytes read.
+ */
+local int read_buf(strm, buf, size)
+ z_stream *strm;
+ charf *buf;
+ unsigned size;
+{
+ unsigned len = strm->avail_in;
+ deflate_state *state = (deflate_state *) strm->state;
+
+ if (len > size) len = size;
+ if (len == 0) return 0;
+
+ strm->avail_in -= len;
+
+ if (!state->noheader) {
+ state->adler = adler32(state->adler, strm->next_in, len);
+ }
+ zmemcpy(buf, strm->next_in, len);
+ strm->next_in += len;
+ strm->total_in += len;
+
+ return (int)len;
+}
+
+/* ===========================================================================
+ * Initialize the "longest match" routines for a new zlib stream
+ */
+local void lm_init (s)
+ deflate_state *s;
+{
+ s->window_size = (ulg)2L*s->w_size;
+
+ CLEAR_HASH(s);
+
+ /* Set the default configuration parameters:
+ */
+ s->max_lazy_match = configuration_table[s->level].max_lazy;
+ s->good_match = configuration_table[s->level].good_length;
+ s->nice_match = configuration_table[s->level].nice_length;
+ s->max_chain_length = configuration_table[s->level].max_chain;
+
+ s->strstart = 0;
+ s->block_start = 0L;
+ s->lookahead = 0;
+ s->match_length = MIN_MATCH-1;
+ s->match_available = 0;
+ s->ins_h = 0;
+#ifdef ASMV
+ match_init(); /* initialize the asm code */
+#endif
+}
+
+/* ===========================================================================
+ * Set match_start to the longest match starting at the given string and
+ * return its length. Matches shorter or equal to prev_length are discarded,
+ * in which case the result is equal to prev_length and match_start is
+ * garbage.
+ * IN assertions: cur_match is the head of the hash chain for the current
+ * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1
+ */
+#ifndef ASMV
+/* For 80x86 and 680x0, an optimized version will be provided in match.asm or
+ * match.S. The code will be functionally equivalent.
+ */
+local int longest_match(s, cur_match)
+ deflate_state *s;
+ IPos cur_match; /* current match */
+{
+ unsigned chain_length = s->max_chain_length;/* max hash chain length */
+ register Bytef *scan = s->window + s->strstart; /* current string */
+ register Bytef *match; /* matched string */
+ register int len; /* length of current match */
+ int best_len = s->prev_length; /* best match length so far */
+ IPos limit = s->strstart > (IPos)MAX_DIST(s) ?
+ s->strstart - (IPos)MAX_DIST(s) : NIL;
+ /* Stop when cur_match becomes <= limit. To simplify the code,
+ * we prevent matches with the string of window index 0.
+ */
+ Posf *prev = s->prev;
+ uInt wmask = s->w_mask;
+
+#ifdef UNALIGNED_OK
+ /* Compare two bytes at a time. Note: this is not always beneficial.
+ * Try with and without -DUNALIGNED_OK to check.
+ */
+ register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1;
+ register ush scan_start = *(ushf*)scan;
+ register ush scan_end = *(ushf*)(scan+best_len-1);
+#else
+ register Bytef *strend = s->window + s->strstart + MAX_MATCH;
+ register Byte scan_end1 = scan[best_len-1];
+ register Byte scan_end = scan[best_len];
+#endif
+
+ /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
+ * It is easy to get rid of this optimization if necessary.
+ */
+ Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever");
+
+ /* Do not waste too much time if we already have a good match: */
+ if (s->prev_length >= s->good_match) {
+ chain_length >>= 2;
+ }
+ Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead");
+
+ do {
+ Assert(cur_match < s->strstart, "no future");
+ match = s->window + cur_match;
+
+ /* Skip to next match if the match length cannot increase
+ * or if the match length is less than 2:
+ */
+#if (defined(UNALIGNED_OK) && MAX_MATCH == 258)
+ /* This code assumes sizeof(unsigned short) == 2. Do not use
+ * UNALIGNED_OK if your compiler uses a different size.
+ */
+ if (*(ushf*)(match+best_len-1) != scan_end ||
+ *(ushf*)match != scan_start) continue;
+
+ /* It is not necessary to compare scan[2] and match[2] since they are
+ * always equal when the other bytes match, given that the hash keys
+ * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at
+ * strstart+3, +5, ... up to strstart+257. We check for insufficient
+ * lookahead only every 4th comparison; the 128th check will be made
+ * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is
+ * necessary to put more guard bytes at the end of the window, or
+ * to check more often for insufficient lookahead.
+ */
+ Assert(scan[2] == match[2], "scan[2]?");
+ scan++, match++;
+ do {
+ } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+ *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+ *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+ *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+ scan < strend);
+ /* The funny "do {}" generates better code on most compilers */
+
+ /* Here, scan <= window+strstart+257 */
+ Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
+ if (*scan == *match) scan++;
+
+ len = (MAX_MATCH - 1) - (int)(strend-scan);
+ scan = strend - (MAX_MATCH-1);
+
+#else /* UNALIGNED_OK */
+
+ if (match[best_len] != scan_end ||
+ match[best_len-1] != scan_end1 ||
+ *match != *scan ||
+ *++match != scan[1]) continue;
+
+ /* The check at best_len-1 can be removed because it will be made
+ * again later. (This heuristic is not always a win.)
+ * It is not necessary to compare scan[2] and match[2] since they
+ * are always equal when the other bytes match, given that
+ * the hash keys are equal and that HASH_BITS >= 8.
+ */
+ scan += 2, match++;
+ Assert(*scan == *match, "match[2]?");
+
+ /* We check for insufficient lookahead only every 8th comparison;
+ * the 256th check will be made at strstart+258.
+ */
+ do {
+ } while (*++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ scan < strend);
+
+ Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
+
+ len = MAX_MATCH - (int)(strend - scan);
+ scan = strend - MAX_MATCH;
+
+#endif /* UNALIGNED_OK */
+
+ if (len > best_len) {
+ s->match_start = cur_match;
+ best_len = len;
+ if (len >= s->nice_match) break;
+#ifdef UNALIGNED_OK
+ scan_end = *(ushf*)(scan+best_len-1);
+#else
+ scan_end1 = scan[best_len-1];
+ scan_end = scan[best_len];
+#endif
+ }
+ } while ((cur_match = prev[cur_match & wmask]) > limit
+ && --chain_length != 0);
+
+ return best_len;
+}
+#endif /* ASMV */
+
+#ifdef DEBUG_ZLIB
+/* ===========================================================================
+ * Check that the match at match_start is indeed a match.
+ */
+local void check_match(s, start, match, length)
+ deflate_state *s;
+ IPos start, match;
+ int length;
+{
+ /* check that the match is indeed a match */
+ if (memcmp((charf *)s->window + match,
+ (charf *)s->window + start, length) != EQUAL) {
+ fprintf(stderr,
+ " start %u, match %u, length %d\n",
+ start, match, length);
+ do { fprintf(stderr, "%c%c", s->window[match++],
+ s->window[start++]); } while (--length != 0);
+ z_error("invalid match");
+ }
+ if (verbose > 1) {
+ fprintf(stderr,"\\[%d,%d]", start-match, length);
+ do { putc(s->window[start++], stderr); } while (--length != 0);
+ }
+}
+#else
+# define check_match(s, start, match, length)
+#endif
+
+/* ===========================================================================
+ * Fill the window when the lookahead becomes insufficient.
+ * Updates strstart and lookahead.
+ *
+ * IN assertion: lookahead < MIN_LOOKAHEAD
+ * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD
+ * At least one byte has been read, or avail_in == 0; reads are
+ * performed for at least two bytes (required for the zip translate_eol
+ * option -- not supported here).
+ */
+local void fill_window(s)
+ deflate_state *s;
+{
+ register unsigned n, m;
+ register Posf *p;
+ unsigned more; /* Amount of free space at the end of the window. */
+ uInt wsize = s->w_size;
+
+ do {
+ more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart);
+
+ /* Deal with !@#$% 64K limit: */
+ if (more == 0 && s->strstart == 0 && s->lookahead == 0) {
+ more = wsize;
+ } else if (more == (unsigned)(-1)) {
+ /* Very unlikely, but possible on 16 bit machine if strstart == 0
+ * and lookahead == 1 (input done one byte at time)
+ */
+ more--;
+
+ /* If the window is almost full and there is insufficient lookahead,
+ * move the upper half to the lower one to make room in the upper half.
+ */
+ } else if (s->strstart >= wsize+MAX_DIST(s)) {
+
+ /* By the IN assertion, the window is not empty so we can't confuse
+ * more == 0 with more == 64K on a 16 bit machine.
+ */
+ zmemcpy((charf *)s->window, (charf *)s->window+wsize,
+ (unsigned)wsize);
+ s->match_start -= wsize;
+ s->strstart -= wsize; /* we now have strstart >= MAX_DIST */
+
+ s->block_start -= (long) wsize;
+
+ /* Slide the hash table (could be avoided with 32 bit values
+ at the expense of memory usage):
+ */
+ n = s->hash_size;
+ p = &s->head[n];
+ do {
+ m = *--p;
+ *p = (Pos)(m >= wsize ? m-wsize : NIL);
+ } while (--n);
+
+ n = wsize;
+ p = &s->prev[n];
+ do {
+ m = *--p;
+ *p = (Pos)(m >= wsize ? m-wsize : NIL);
+ /* If n is not on any hash chain, prev[n] is garbage but
+ * its value will never be used.
+ */
+ } while (--n);
+
+ more += wsize;
+ }
+ if (s->strm->avail_in == 0) return;
+
+ /* If there was no sliding:
+ * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 &&
+ * more == window_size - lookahead - strstart
+ * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1)
+ * => more >= window_size - 2*WSIZE + 2
+ * In the BIG_MEM or MMAP case (not yet supported),
+ * window_size == input_size + MIN_LOOKAHEAD &&
+ * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD.
+ * Otherwise, window_size == 2*WSIZE so more >= 2.
+ * If there was sliding, more >= WSIZE. So in all cases, more >= 2.
+ */
+ Assert(more >= 2, "more < 2");
+
+ n = read_buf(s->strm, (charf *)s->window + s->strstart + s->lookahead,
+ more);
+ s->lookahead += n;
+
+ /* Initialize the hash value now that we have some input: */
+ if (s->lookahead >= MIN_MATCH) {
+ s->ins_h = s->window[s->strstart];
+ UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]);
+#if MIN_MATCH != 3
+ Call UPDATE_HASH() MIN_MATCH-3 more times
+#endif
+ }
+ /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage,
+ * but this is not important since only literal bytes will be emitted.
+ */
+
+ } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0);
+}
+
+/* ===========================================================================
+ * Flush the current block, with given end-of-file flag.
+ * IN assertion: strstart is set to the end of the current match.
+ */
+#define FLUSH_BLOCK_ONLY(s, flush) { \
+ ct_flush_block(s, (s->block_start >= 0L ? \
+ (charf *)&s->window[(unsigned)s->block_start] : \
+ (charf *)Z_NULL), (long)s->strstart - s->block_start, (flush)); \
+ s->block_start = s->strstart; \
+ flush_pending(s->strm); \
+ Tracev((stderr,"[FLUSH]")); \
+}
+
+/* Same but force premature exit if necessary. */
+#define FLUSH_BLOCK(s, flush) { \
+ FLUSH_BLOCK_ONLY(s, flush); \
+ if (s->strm->avail_out == 0) return 1; \
+}
+
+/* ===========================================================================
+ * Compress as much as possible from the input stream, return true if
+ * processing was terminated prematurely (no more input or output space).
+ * This function does not perform lazy evaluationof matches and inserts
+ * new strings in the dictionary only for unmatched strings or for short
+ * matches. It is used only for the fast compression options.
+ */
+local int deflate_fast(s, flush)
+ deflate_state *s;
+ int flush;
+{
+ IPos hash_head = NIL; /* head of the hash chain */
+ int bflush; /* set if current block must be flushed */
+
+ s->prev_length = MIN_MATCH-1;
+
+ for (;;) {
+ /* Make sure that we always have enough lookahead, except
+ * at the end of the input file. We need MAX_MATCH bytes
+ * for the next match, plus MIN_MATCH bytes to insert the
+ * string following the next match.
+ */
+ if (s->lookahead < MIN_LOOKAHEAD) {
+ fill_window(s);
+ if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) return 1;
+
+ if (s->lookahead == 0) break; /* flush the current block */
+ }
+
+ /* Insert the string window[strstart .. strstart+2] in the
+ * dictionary, and set hash_head to the head of the hash chain:
+ */
+ if (s->lookahead >= MIN_MATCH) {
+ INSERT_STRING(s, s->strstart, hash_head);
+ }
+
+ /* Find the longest match, discarding those <= prev_length.
+ * At this point we have always match_length < MIN_MATCH
+ */
+ if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) {
+ /* To simplify the code, we prevent matches with the string
+ * of window index 0 (in particular we have to avoid a match
+ * of the string with itself at the start of the input file).
+ */
+ if (s->strategy != Z_HUFFMAN_ONLY) {
+ s->match_length = longest_match (s, hash_head);
+ }
+ /* longest_match() sets match_start */
+
+ if (s->match_length > s->lookahead) s->match_length = s->lookahead;
+ }
+ if (s->match_length >= MIN_MATCH) {
+ check_match(s, s->strstart, s->match_start, s->match_length);
+
+ bflush = ct_tally(s, s->strstart - s->match_start,
+ s->match_length - MIN_MATCH);
+
+ s->lookahead -= s->match_length;
+
+ /* Insert new strings in the hash table only if the match length
+ * is not too large. This saves time but degrades compression.
+ */
+ if (s->match_length <= s->max_insert_length &&
+ s->lookahead >= MIN_MATCH) {
+ s->match_length--; /* string at strstart already in hash table */
+ do {
+ s->strstart++;
+ INSERT_STRING(s, s->strstart, hash_head);
+ /* strstart never exceeds WSIZE-MAX_MATCH, so there are
+ * always MIN_MATCH bytes ahead.
+ */
+ } while (--s->match_length != 0);
+ s->strstart++;
+ } else {
+ s->strstart += s->match_length;
+ s->match_length = 0;
+ s->ins_h = s->window[s->strstart];
+ UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]);
+#if MIN_MATCH != 3
+ Call UPDATE_HASH() MIN_MATCH-3 more times
+#endif
+ /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not
+ * matter since it will be recomputed at next deflate call.
+ */
+ }
+ } else {
+ /* No match, output a literal byte */
+ Tracevv((stderr,"%c", s->window[s->strstart]));
+ bflush = ct_tally (s, 0, s->window[s->strstart]);
+ s->lookahead--;
+ s->strstart++;
+ }
+ if (bflush) FLUSH_BLOCK(s, Z_NO_FLUSH);
+ }
+ FLUSH_BLOCK(s, flush);
+ return 0; /* normal exit */
+}
+
+/* ===========================================================================
+ * Same as above, but achieves better compression. We use a lazy
+ * evaluation for matches: a match is finally adopted only if there is
+ * no better match at the next window position.
+ */
+local int deflate_slow(s, flush)
+ deflate_state *s;
+ int flush;
+{
+ IPos hash_head = NIL; /* head of hash chain */
+ int bflush; /* set if current block must be flushed */
+
+ /* Process the input block. */
+ for (;;) {
+ /* Make sure that we always have enough lookahead, except
+ * at the end of the input file. We need MAX_MATCH bytes
+ * for the next match, plus MIN_MATCH bytes to insert the
+ * string following the next match.
+ */
+ if (s->lookahead < MIN_LOOKAHEAD) {
+ fill_window(s);
+ if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) return 1;
+
+ if (s->lookahead == 0) break; /* flush the current block */
+ }
+
+ /* Insert the string window[strstart .. strstart+2] in the
+ * dictionary, and set hash_head to the head of the hash chain:
+ */
+ if (s->lookahead >= MIN_MATCH) {
+ INSERT_STRING(s, s->strstart, hash_head);
+ }
+
+ /* Find the longest match, discarding those <= prev_length.
+ */
+ s->prev_length = s->match_length, s->prev_match = s->match_start;
+ s->match_length = MIN_MATCH-1;
+
+ if (hash_head != NIL && s->prev_length < s->max_lazy_match &&
+ s->strstart - hash_head <= MAX_DIST(s)) {
+ /* To simplify the code, we prevent matches with the string
+ * of window index 0 (in particular we have to avoid a match
+ * of the string with itself at the start of the input file).
+ */
+ if (s->strategy != Z_HUFFMAN_ONLY) {
+ s->match_length = longest_match (s, hash_head);
+ }
+ /* longest_match() sets match_start */
+ if (s->match_length > s->lookahead) s->match_length = s->lookahead;
+
+ if (s->match_length <= 5 && (s->strategy == Z_FILTERED ||
+ (s->match_length == MIN_MATCH &&
+ s->strstart - s->match_start > TOO_FAR))) {
+
+ /* If prev_match is also MIN_MATCH, match_start is garbage
+ * but we will ignore the current match anyway.
+ */
+ s->match_length = MIN_MATCH-1;
+ }
+ }
+ /* If there was a match at the previous step and the current
+ * match is not better, output the previous match:
+ */
+ if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) {
+ uInt max_insert = s->strstart + s->lookahead - MIN_MATCH;
+ /* Do not insert strings in hash table beyond this. */
+
+ check_match(s, s->strstart-1, s->prev_match, s->prev_length);
+
+ bflush = ct_tally(s, s->strstart -1 - s->prev_match,
+ s->prev_length - MIN_MATCH);
+
+ /* Insert in hash table all strings up to the end of the match.
+ * strstart-1 and strstart are already inserted. If there is not
+ * enough lookahead, the last two strings are not inserted in
+ * the hash table.
+ */
+ s->lookahead -= s->prev_length-1;
+ s->prev_length -= 2;
+ do {
+ if (++s->strstart <= max_insert) {
+ INSERT_STRING(s, s->strstart, hash_head);
+ }
+ } while (--s->prev_length != 0);
+ s->match_available = 0;
+ s->match_length = MIN_MATCH-1;
+ s->strstart++;
+
+ if (bflush) FLUSH_BLOCK(s, Z_NO_FLUSH);
+
+ } else if (s->match_available) {
+ /* If there was no match at the previous position, output a
+ * single literal. If there was a match but the current match
+ * is longer, truncate the previous match to a single literal.
+ */
+ Tracevv((stderr,"%c", s->window[s->strstart-1]));
+ if (ct_tally (s, 0, s->window[s->strstart-1])) {
+ FLUSH_BLOCK_ONLY(s, Z_NO_FLUSH);
+ }
+ s->strstart++;
+ s->lookahead--;
+ if (s->strm->avail_out == 0) return 1;
+ } else {
+ /* There is no previous match to compare with, wait for
+ * the next step to decide.
+ */
+ s->match_available = 1;
+ s->strstart++;
+ s->lookahead--;
+ }
+ }
+ Assert (flush != Z_NO_FLUSH, "no flush?");
+ if (s->match_available) {
+ Tracevv((stderr,"%c", s->window[s->strstart-1]));
+ ct_tally (s, 0, s->window[s->strstart-1]);
+ s->match_available = 0;
+ }
+ FLUSH_BLOCK(s, flush);
+ return 0;
+}
+
+
+/*+++++*/
+/* trees.c -- output deflated data using Huffman coding
+ * Copyright (C) 1995 Jean-loup Gailly
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/*
+ * ALGORITHM
+ *
+ * The "deflation" process uses several Huffman trees. The more
+ * common source values are represented by shorter bit sequences.
+ *
+ * Each code tree is stored in a compressed form which is itself
+ * a Huffman encoding of the lengths of all the code strings (in
+ * ascending order by source values). The actual code strings are
+ * reconstructed from the lengths in the inflate process, as described
+ * in the deflate specification.
+ *
+ * REFERENCES
+ *
+ * Deutsch, L.P.,"'Deflate' Compressed Data Format Specification".
+ * Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc
+ *
+ * Storer, James A.
+ * Data Compression: Methods and Theory, pp. 49-50.
+ * Computer Science Press, 1988. ISBN 0-7167-8156-5.
+ *
+ * Sedgewick, R.
+ * Algorithms, p290.
+ * Addison-Wesley, 1983. ISBN 0-201-06672-6.
+ */
+
+/* From: trees.c,v 1.5 1995/05/03 17:27:12 jloup Exp */
+
+#ifdef DEBUG_ZLIB
+# include <ctype.h>
+#endif
+
+/* ===========================================================================
+ * Constants
+ */
+
+#define MAX_BL_BITS 7
+/* Bit length codes must not exceed MAX_BL_BITS bits */
+
+#define END_BLOCK 256
+/* end of block literal code */
+
+#define REP_3_6 16
+/* repeat previous bit length 3-6 times (2 bits of repeat count) */
+
+#define REPZ_3_10 17
+/* repeat a zero length 3-10 times (3 bits of repeat count) */
+
+#define REPZ_11_138 18
+/* repeat a zero length 11-138 times (7 bits of repeat count) */
+
+local int extra_lbits[LENGTH_CODES] /* extra bits for each length code */
+ = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0};
+
+local int extra_dbits[D_CODES] /* extra bits for each distance code */
+ = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13};
+
+local int extra_blbits[BL_CODES]/* extra bits for each bit length code */
+ = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7};
+
+local uch bl_order[BL_CODES]
+ = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15};
+/* The lengths of the bit length codes are sent in order of decreasing
+ * probability, to avoid transmitting the lengths for unused bit length codes.
+ */
+
+#define Buf_size (8 * 2*sizeof(char))
+/* Number of bits used within bi_buf. (bi_buf might be implemented on
+ * more than 16 bits on some systems.)
+ */
+
+/* ===========================================================================
+ * Local data. These are initialized only once.
+ * To do: initialize at compile time to be completely reentrant. ???
+ */
+
+local ct_data static_ltree[L_CODES+2];
+/* The static literal tree. Since the bit lengths are imposed, there is no
+ * need for the L_CODES extra codes used during heap construction. However
+ * The codes 286 and 287 are needed to build a canonical tree (see ct_init
+ * below).
+ */
+
+local ct_data static_dtree[D_CODES];
+/* The static distance tree. (Actually a trivial tree since all codes use
+ * 5 bits.)
+ */
+
+local uch dist_code[512];
+/* distance codes. The first 256 values correspond to the distances
+ * 3 .. 258, the last 256 values correspond to the top 8 bits of
+ * the 15 bit distances.
+ */
+
+local uch length_code[MAX_MATCH-MIN_MATCH+1];
+/* length code for each normalized match length (0 == MIN_MATCH) */
+
+local int base_length[LENGTH_CODES];
+/* First normalized length for each code (0 = MIN_MATCH) */
+
+local int base_dist[D_CODES];
+/* First normalized distance for each code (0 = distance of 1) */
+
+struct static_tree_desc_s {
+ ct_data *static_tree; /* static tree or NULL */
+ intf *extra_bits; /* extra bits for each code or NULL */
+ int extra_base; /* base index for extra_bits */
+ int elems; /* max number of elements in the tree */
+ int max_length; /* max bit length for the codes */
+};
+
+local static_tree_desc static_l_desc =
+{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS};
+
+local static_tree_desc static_d_desc =
+{static_dtree, extra_dbits, 0, D_CODES, MAX_BITS};
+
+local static_tree_desc static_bl_desc =
+{(ct_data *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS};
+
+/* ===========================================================================
+ * Local (static) routines in this file.
+ */
+
+local void ct_static_init OF((void));
+local void init_block OF((deflate_state *s));
+local void pqdownheap OF((deflate_state *s, ct_data *tree, int k));
+local void gen_bitlen OF((deflate_state *s, tree_desc *desc));
+local void gen_codes OF((ct_data *tree, int max_code, ushf *bl_count));
+local void build_tree OF((deflate_state *s, tree_desc *desc));
+local void scan_tree OF((deflate_state *s, ct_data *tree, int max_code));
+local void send_tree OF((deflate_state *s, ct_data *tree, int max_code));
+local int build_bl_tree OF((deflate_state *s));
+local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes,
+ int blcodes));
+local void compress_block OF((deflate_state *s, ct_data *ltree,
+ ct_data *dtree));
+local void set_data_type OF((deflate_state *s));
+local unsigned bi_reverse OF((unsigned value, int length));
+local void bi_windup OF((deflate_state *s));
+local void bi_flush OF((deflate_state *s));
+local void copy_block OF((deflate_state *s, charf *buf, unsigned len,
+ int header));
+
+#ifndef DEBUG_ZLIB
+# define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len)
+ /* Send a code of the given tree. c and tree must not have side effects */
+
+#else /* DEBUG_ZLIB */
+# define send_code(s, c, tree) \
+ { if (verbose>1) fprintf(stderr,"\ncd %3d ",(c)); \
+ send_bits(s, tree[c].Code, tree[c].Len); }
+#endif
+
+#define d_code(dist) \
+ ((dist) < 256 ? dist_code[dist] : dist_code[256+((dist)>>7)])
+/* Mapping from a distance to a distance code. dist is the distance - 1 and
+ * must not have side effects. dist_code[256] and dist_code[257] are never
+ * used.
+ */
+
+/* ===========================================================================
+ * Output a short LSB first on the stream.
+ * IN assertion: there is enough room in pendingBuf.
+ */
+#define put_short(s, w) { \
+ put_byte(s, (uch)((w) & 0xff)); \
+ put_byte(s, (uch)((ush)(w) >> 8)); \
+}
+
+/* ===========================================================================
+ * Send a value on a given number of bits.
+ * IN assertion: length <= 16 and value fits in length bits.
+ */
+#ifdef DEBUG_ZLIB
+local void send_bits OF((deflate_state *s, int value, int length));
+
+local void send_bits(s, value, length)
+ deflate_state *s;
+ int value; /* value to send */
+ int length; /* number of bits */
+{
+ Tracev((stderr," l %2d v %4x ", length, value));
+ Assert(length > 0 && length <= 15, "invalid length");
+ s->bits_sent += (ulg)length;
+
+ /* If not enough room in bi_buf, use (valid) bits from bi_buf and
+ * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid))
+ * unused bits in value.
+ */
+ if (s->bi_valid > (int)Buf_size - length) {
+ s->bi_buf |= (value << s->bi_valid);
+ put_short(s, s->bi_buf);
+ s->bi_buf = (ush)value >> (Buf_size - s->bi_valid);
+ s->bi_valid += length - Buf_size;
+ } else {
+ s->bi_buf |= value << s->bi_valid;
+ s->bi_valid += length;
+ }
+}
+#else /* !DEBUG_ZLIB */
+
+#define send_bits(s, value, length) \
+{ int len = length;\
+ if (s->bi_valid > (int)Buf_size - len) {\
+ int val = value;\
+ s->bi_buf |= (val << s->bi_valid);\
+ put_short(s, s->bi_buf);\
+ s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\
+ s->bi_valid += len - Buf_size;\
+ } else {\
+ s->bi_buf |= (value) << s->bi_valid;\
+ s->bi_valid += len;\
+ }\
+}
+#endif /* DEBUG_ZLIB */
+
+
+#define MAX(a,b) (a >= b ? a : b)
+/* the arguments must not have side effects */
+
+/* ===========================================================================
+ * Initialize the various 'constant' tables.
+ * To do: do this at compile time.
+ */
+local void ct_static_init()
+{
+ int n; /* iterates over tree elements */
+ int bits; /* bit counter */
+ int length; /* length value */
+ int code; /* code value */
+ int dist; /* distance index */
+ ush bl_count[MAX_BITS+1];
+ /* number of codes at each bit length for an optimal tree */
+
+ /* Initialize the mapping length (0..255) -> length code (0..28) */
+ length = 0;
+ for (code = 0; code < LENGTH_CODES-1; code++) {
+ base_length[code] = length;
+ for (n = 0; n < (1<<extra_lbits[code]); n++) {
+ length_code[length++] = (uch)code;
+ }
+ }
+ Assert (length == 256, "ct_static_init: length != 256");
+ /* Note that the length 255 (match length 258) can be represented
+ * in two different ways: code 284 + 5 bits or code 285, so we
+ * overwrite length_code[255] to use the best encoding:
+ */
+ length_code[length-1] = (uch)code;
+
+ /* Initialize the mapping dist (0..32K) -> dist code (0..29) */
+ dist = 0;
+ for (code = 0 ; code < 16; code++) {
+ base_dist[code] = dist;
+ for (n = 0; n < (1<<extra_dbits[code]); n++) {
+ dist_code[dist++] = (uch)code;
+ }
+ }
+ Assert (dist == 256, "ct_static_init: dist != 256");
+ dist >>= 7; /* from now on, all distances are divided by 128 */
+ for ( ; code < D_CODES; code++) {
+ base_dist[code] = dist << 7;
+ for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) {
+ dist_code[256 + dist++] = (uch)code;
+ }
+ }
+ Assert (dist == 256, "ct_static_init: 256+dist != 512");
+
+ /* Construct the codes of the static literal tree */
+ for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0;
+ n = 0;
+ while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++;
+ while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++;
+ while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++;
+ while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++;
+ /* Codes 286 and 287 do not exist, but we must include them in the
+ * tree construction to get a canonical Huffman tree (longest code
+ * all ones)
+ */
+ gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count);
+
+ /* The static distance tree is trivial: */
+ for (n = 0; n < D_CODES; n++) {
+ static_dtree[n].Len = 5;
+ static_dtree[n].Code = bi_reverse(n, 5);
+ }
+}
+
+/* ===========================================================================
+ * Initialize the tree data structures for a new zlib stream.
+ */
+local void ct_init(s)
+ deflate_state *s;
+{
+ if (static_dtree[0].Len == 0) {
+ ct_static_init(); /* To do: at compile time */
+ }
+
+ s->compressed_len = 0L;
+
+ s->l_desc.dyn_tree = s->dyn_ltree;
+ s->l_desc.stat_desc = &static_l_desc;
+
+ s->d_desc.dyn_tree = s->dyn_dtree;
+ s->d_desc.stat_desc = &static_d_desc;
+
+ s->bl_desc.dyn_tree = s->bl_tree;
+ s->bl_desc.stat_desc = &static_bl_desc;
+
+ s->bi_buf = 0;
+ s->bi_valid = 0;
+ s->last_eob_len = 8; /* enough lookahead for inflate */
+#ifdef DEBUG_ZLIB
+ s->bits_sent = 0L;
+#endif
+ s->blocks_in_packet = 0;
+
+ /* Initialize the first block of the first file: */
+ init_block(s);
+}
+
+/* ===========================================================================
+ * Initialize a new block.
+ */
+local void init_block(s)
+ deflate_state *s;
+{
+ int n; /* iterates over tree elements */
+
+ /* Initialize the trees. */
+ for (n = 0; n < L_CODES; n++) s->dyn_ltree[n].Freq = 0;
+ for (n = 0; n < D_CODES; n++) s->dyn_dtree[n].Freq = 0;
+ for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0;
+
+ s->dyn_ltree[END_BLOCK].Freq = 1;
+ s->opt_len = s->static_len = 0L;
+ s->last_lit = s->matches = 0;
+}
+
+#define SMALLEST 1
+/* Index within the heap array of least frequent node in the Huffman tree */
+
+
+/* ===========================================================================
+ * Remove the smallest element from the heap and recreate the heap with
+ * one less element. Updates heap and heap_len.
+ */
+#define pqremove(s, tree, top) \
+{\
+ top = s->heap[SMALLEST]; \
+ s->heap[SMALLEST] = s->heap[s->heap_len--]; \
+ pqdownheap(s, tree, SMALLEST); \
+}
+
+/* ===========================================================================
+ * Compares to subtrees, using the tree depth as tie breaker when
+ * the subtrees have equal frequency. This minimizes the worst case length.
+ */
+#define smaller(tree, n, m, depth) \
+ (tree[n].Freq < tree[m].Freq || \
+ (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m]))
+
+/* ===========================================================================
+ * Restore the heap property by moving down the tree starting at node k,
+ * exchanging a node with the smallest of its two sons if necessary, stopping
+ * when the heap property is re-established (each father smaller than its
+ * two sons).
+ */
+local void pqdownheap(s, tree, k)
+ deflate_state *s;
+ ct_data *tree; /* the tree to restore */
+ int k; /* node to move down */
+{
+ int v = s->heap[k];
+ int j = k << 1; /* left son of k */
+ while (j <= s->heap_len) {
+ /* Set j to the smallest of the two sons: */
+ if (j < s->heap_len &&
+ smaller(tree, s->heap[j+1], s->heap[j], s->depth)) {
+ j++;
+ }
+ /* Exit if v is smaller than both sons */
+ if (smaller(tree, v, s->heap[j], s->depth)) break;
+
+ /* Exchange v with the smallest son */
+ s->heap[k] = s->heap[j]; k = j;
+
+ /* And continue down the tree, setting j to the left son of k */
+ j <<= 1;
+ }
+ s->heap[k] = v;
+}
+
+/* ===========================================================================
+ * Compute the optimal bit lengths for a tree and update the total bit length
+ * for the current block.
+ * IN assertion: the fields freq and dad are set, heap[heap_max] and
+ * above are the tree nodes sorted by increasing frequency.
+ * OUT assertions: the field len is set to the optimal bit length, the
+ * array bl_count contains the frequencies for each bit length.
+ * The length opt_len is updated; static_len is also updated if stree is
+ * not null.
+ */
+local void gen_bitlen(s, desc)
+ deflate_state *s;
+ tree_desc *desc; /* the tree descriptor */
+{
+ ct_data *tree = desc->dyn_tree;
+ int max_code = desc->max_code;
+ ct_data *stree = desc->stat_desc->static_tree;
+ intf *extra = desc->stat_desc->extra_bits;
+ int base = desc->stat_desc->extra_base;
+ int max_length = desc->stat_desc->max_length;
+ int h; /* heap index */
+ int n, m; /* iterate over the tree elements */
+ int bits; /* bit length */
+ int xbits; /* extra bits */
+ ush f; /* frequency */
+ int overflow = 0; /* number of elements with bit length too large */
+
+ for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0;
+
+ /* In a first pass, compute the optimal bit lengths (which may
+ * overflow in the case of the bit length tree).
+ */
+ tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */
+
+ for (h = s->heap_max+1; h < HEAP_SIZE; h++) {
+ n = s->heap[h];
+ bits = tree[tree[n].Dad].Len + 1;
+ if (bits > max_length) bits = max_length, overflow++;
+ tree[n].Len = (ush)bits;
+ /* We overwrite tree[n].Dad which is no longer needed */
+
+ if (n > max_code) continue; /* not a leaf node */
+
+ s->bl_count[bits]++;
+ xbits = 0;
+ if (n >= base) xbits = extra[n-base];
+ f = tree[n].Freq;
+ s->opt_len += (ulg)f * (bits + xbits);
+ if (stree) s->static_len += (ulg)f * (stree[n].Len + xbits);
+ }
+ if (overflow == 0) return;
+
+ Trace((stderr,"\nbit length overflow\n"));
+ /* This happens for example on obj2 and pic of the Calgary corpus */
+
+ /* Find the first bit length which could increase: */
+ do {
+ bits = max_length-1;
+ while (s->bl_count[bits] == 0) bits--;
+ s->bl_count[bits]--; /* move one leaf down the tree */
+ s->bl_count[bits+1] += 2; /* move one overflow item as its brother */
+ s->bl_count[max_length]--;
+ /* The brother of the overflow item also moves one step up,
+ * but this does not affect bl_count[max_length]
+ */
+ overflow -= 2;
+ } while (overflow > 0);
+
+ /* Now recompute all bit lengths, scanning in increasing frequency.
+ * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all
+ * lengths instead of fixing only the wrong ones. This idea is taken
+ * from 'ar' written by Haruhiko Okumura.)
+ */
+ for (bits = max_length; bits != 0; bits--) {
+ n = s->bl_count[bits];
+ while (n != 0) {
+ m = s->heap[--h];
+ if (m > max_code) continue;
+ if (tree[m].Len != (unsigned) bits) {
+ Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits));
+ s->opt_len += ((long)bits - (long)tree[m].Len)
+ *(long)tree[m].Freq;
+ tree[m].Len = (ush)bits;
+ }
+ n--;
+ }
+ }
+}
+
+/* ===========================================================================
+ * Generate the codes for a given tree and bit counts (which need not be
+ * optimal).
+ * IN assertion: the array bl_count contains the bit length statistics for
+ * the given tree and the field len is set for all tree elements.
+ * OUT assertion: the field code is set for all tree elements of non
+ * zero code length.
+ */
+local void gen_codes (tree, max_code, bl_count)
+ ct_data *tree; /* the tree to decorate */
+ int max_code; /* largest code with non zero frequency */
+ ushf *bl_count; /* number of codes at each bit length */
+{
+ ush next_code[MAX_BITS+1]; /* next code value for each bit length */
+ ush code = 0; /* running code value */
+ int bits; /* bit index */
+ int n; /* code index */
+
+ /* The distribution counts are first used to generate the code values
+ * without bit reversal.
+ */
+ for (bits = 1; bits <= MAX_BITS; bits++) {
+ next_code[bits] = code = (code + bl_count[bits-1]) << 1;
+ }
+ /* Check that the bit counts in bl_count are consistent. The last code
+ * must be all ones.
+ */
+ Assert (code + bl_count[MAX_BITS]-1 == (1<<MAX_BITS)-1,
+ "inconsistent bit counts");
+ Tracev((stderr,"\ngen_codes: max_code %d ", max_code));
+
+ for (n = 0; n <= max_code; n++) {
+ int len = tree[n].Len;
+ if (len == 0) continue;
+ /* Now reverse the bits */
+ tree[n].Code = bi_reverse(next_code[len]++, len);
+
+ Tracec(tree != static_ltree, (stderr,"\nn %3d %c l %2d c %4x (%x) ",
+ n, (isgraph(n) ? n : ' '), len, tree[n].Code, next_code[len]-1));
+ }
+}
+
+/* ===========================================================================
+ * Construct one Huffman tree and assigns the code bit strings and lengths.
+ * Update the total bit length for the current block.
+ * IN assertion: the field freq is set for all tree elements.
+ * OUT assertions: the fields len and code are set to the optimal bit length
+ * and corresponding code. The length opt_len is updated; static_len is
+ * also updated if stree is not null. The field max_code is set.
+ */
+local void build_tree(s, desc)
+ deflate_state *s;
+ tree_desc *desc; /* the tree descriptor */
+{
+ ct_data *tree = desc->dyn_tree;
+ ct_data *stree = desc->stat_desc->static_tree;
+ int elems = desc->stat_desc->elems;
+ int n, m; /* iterate over heap elements */
+ int max_code = -1; /* largest code with non zero frequency */
+ int node; /* new node being created */
+
+ /* Construct the initial heap, with least frequent element in
+ * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1].
+ * heap[0] is not used.
+ */
+ s->heap_len = 0, s->heap_max = HEAP_SIZE;
+
+ for (n = 0; n < elems; n++) {
+ if (tree[n].Freq != 0) {
+ s->heap[++(s->heap_len)] = max_code = n;
+ s->depth[n] = 0;
+ } else {
+ tree[n].Len = 0;
+ }
+ }
+
+ /* The pkzip format requires that at least one distance code exists,
+ * and that at least one bit should be sent even if there is only one
+ * possible code. So to avoid special checks later on we force at least
+ * two codes of non zero frequency.
+ */
+ while (s->heap_len < 2) {
+ node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0);
+ tree[node].Freq = 1;
+ s->depth[node] = 0;
+ s->opt_len--; if (stree) s->static_len -= stree[node].Len;
+ /* node is 0 or 1 so it does not have extra bits */
+ }
+ desc->max_code = max_code;
+
+ /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree,
+ * establish sub-heaps of increasing lengths:
+ */
+ for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n);
+
+ /* Construct the Huffman tree by repeatedly combining the least two
+ * frequent nodes.
+ */
+ node = elems; /* next internal node of the tree */
+ do {
+ pqremove(s, tree, n); /* n = node of least frequency */
+ m = s->heap[SMALLEST]; /* m = node of next least frequency */
+
+ s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */
+ s->heap[--(s->heap_max)] = m;
+
+ /* Create a new node father of n and m */
+ tree[node].Freq = tree[n].Freq + tree[m].Freq;
+ s->depth[node] = (uch) (MAX(s->depth[n], s->depth[m]) + 1);
+ tree[n].Dad = tree[m].Dad = (ush)node;
+#ifdef DUMP_BL_TREE
+ if (tree == s->bl_tree) {
+ fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)",
+ node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq);
+ }
+#endif
+ /* and insert the new node in the heap */
+ s->heap[SMALLEST] = node++;
+ pqdownheap(s, tree, SMALLEST);
+
+ } while (s->heap_len >= 2);
+
+ s->heap[--(s->heap_max)] = s->heap[SMALLEST];
+
+ /* At this point, the fields freq and dad are set. We can now
+ * generate the bit lengths.
+ */
+ gen_bitlen(s, (tree_desc *)desc);
+
+ /* The field len is now set, we can generate the bit codes */
+ gen_codes ((ct_data *)tree, max_code, s->bl_count);
+}
+
+/* ===========================================================================
+ * Scan a literal or distance tree to determine the frequencies of the codes
+ * in the bit length tree.
+ */
+local void scan_tree (s, tree, max_code)
+ deflate_state *s;
+ ct_data *tree; /* the tree to be scanned */
+ int max_code; /* and its largest code of non zero frequency */
+{
+ int n; /* iterates over all tree elements */
+ int prevlen = -1; /* last emitted length */
+ int curlen; /* length of current code */
+ int nextlen = tree[0].Len; /* length of next code */
+ int count = 0; /* repeat count of the current code */
+ int max_count = 7; /* max repeat count */
+ int min_count = 4; /* min repeat count */
+
+ if (nextlen == 0) max_count = 138, min_count = 3;
+ tree[max_code+1].Len = (ush)0xffff; /* guard */
+
+ for (n = 0; n <= max_code; n++) {
+ curlen = nextlen; nextlen = tree[n+1].Len;
+ if (++count < max_count && curlen == nextlen) {
+ continue;
+ } else if (count < min_count) {
+ s->bl_tree[curlen].Freq += count;
+ } else if (curlen != 0) {
+ if (curlen != prevlen) s->bl_tree[curlen].Freq++;
+ s->bl_tree[REP_3_6].Freq++;
+ } else if (count <= 10) {
+ s->bl_tree[REPZ_3_10].Freq++;
+ } else {
+ s->bl_tree[REPZ_11_138].Freq++;
+ }
+ count = 0; prevlen = curlen;
+ if (nextlen == 0) {
+ max_count = 138, min_count = 3;
+ } else if (curlen == nextlen) {
+ max_count = 6, min_count = 3;
+ } else {
+ max_count = 7, min_count = 4;
+ }
+ }
+}
+
+/* ===========================================================================
+ * Send a literal or distance tree in compressed form, using the codes in
+ * bl_tree.
+ */
+local void send_tree (s, tree, max_code)
+ deflate_state *s;
+ ct_data *tree; /* the tree to be scanned */
+ int max_code; /* and its largest code of non zero frequency */
+{
+ int n; /* iterates over all tree elements */
+ int prevlen = -1; /* last emitted length */
+ int curlen; /* length of current code */
+ int nextlen = tree[0].Len; /* length of next code */
+ int count = 0; /* repeat count of the current code */
+ int max_count = 7; /* max repeat count */
+ int min_count = 4; /* min repeat count */
+
+ /* tree[max_code+1].Len = -1; */ /* guard already set */
+ if (nextlen == 0) max_count = 138, min_count = 3;
+
+ for (n = 0; n <= max_code; n++) {
+ curlen = nextlen; nextlen = tree[n+1].Len;
+ if (++count < max_count && curlen == nextlen) {
+ continue;
+ } else if (count < min_count) {
+ do { send_code(s, curlen, s->bl_tree); } while (--count != 0);
+
+ } else if (curlen != 0) {
+ if (curlen != prevlen) {
+ send_code(s, curlen, s->bl_tree); count--;
+ }
+ Assert(count >= 3 && count <= 6, " 3_6?");
+ send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2);
+
+ } else if (count <= 10) {
+ send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3);
+
+ } else {
+ send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7);
+ }
+ count = 0; prevlen = curlen;
+ if (nextlen == 0) {
+ max_count = 138, min_count = 3;
+ } else if (curlen == nextlen) {
+ max_count = 6, min_count = 3;
+ } else {
+ max_count = 7, min_count = 4;
+ }
+ }
+}
+
+/* ===========================================================================
+ * Construct the Huffman tree for the bit lengths and return the index in
+ * bl_order of the last bit length code to send.
+ */
+local int build_bl_tree(s)
+ deflate_state *s;
+{
+ int max_blindex; /* index of last bit length code of non zero freq */
+
+ /* Determine the bit length frequencies for literal and distance trees */
+ scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code);
+ scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code);
+
+ /* Build the bit length tree: */
+ build_tree(s, (tree_desc *)(&(s->bl_desc)));
+ /* opt_len now includes the length of the tree representations, except
+ * the lengths of the bit lengths codes and the 5+5+4 bits for the counts.
+ */
+
+ /* Determine the number of bit length codes to send. The pkzip format
+ * requires that at least 4 bit length codes be sent. (appnote.txt says
+ * 3 but the actual value used is 4.)
+ */
+ for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) {
+ if (s->bl_tree[bl_order[max_blindex]].Len != 0) break;
+ }
+ /* Update opt_len to include the bit length tree and counts */
+ s->opt_len += 3*(max_blindex+1) + 5+5+4;
+ Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld",
+ s->opt_len, s->static_len));
+
+ return max_blindex;
+}
+
+/* ===========================================================================
+ * Send the header for a block using dynamic Huffman trees: the counts, the
+ * lengths of the bit length codes, the literal tree and the distance tree.
+ * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4.
+ */
+local void send_all_trees(s, lcodes, dcodes, blcodes)
+ deflate_state *s;
+ int lcodes, dcodes, blcodes; /* number of codes for each tree */
+{
+ int rank; /* index in bl_order */
+
+ Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes");
+ Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES,
+ "too many codes");
+ Tracev((stderr, "\nbl counts: "));
+ send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */
+ send_bits(s, dcodes-1, 5);
+ send_bits(s, blcodes-4, 4); /* not -3 as stated in appnote.txt */
+ for (rank = 0; rank < blcodes; rank++) {
+ Tracev((stderr, "\nbl code %2d ", bl_order[rank]));
+ send_bits(s, s->bl_tree[bl_order[rank]].Len, 3);
+ }
+ Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent));
+
+ send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */
+ Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent));
+
+ send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */
+ Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent));
+}
+
+/* ===========================================================================
+ * Send a stored block
+ */
+local void ct_stored_block(s, buf, stored_len, eof)
+ deflate_state *s;
+ charf *buf; /* input block */
+ ulg stored_len; /* length of input block */
+ int eof; /* true if this is the last block for a file */
+{
+ send_bits(s, (STORED_BLOCK<<1)+eof, 3); /* send block type */
+ s->compressed_len = (s->compressed_len + 3 + 7) & ~7L;
+ s->compressed_len += (stored_len + 4) << 3;
+
+ copy_block(s, buf, (unsigned)stored_len, 1); /* with header */
+}
+
+/* Send just the `stored block' type code without any length bytes or data.
+ */
+local void ct_stored_type_only(s)
+ deflate_state *s;
+{
+ send_bits(s, (STORED_BLOCK << 1), 3);
+ bi_windup(s);
+ s->compressed_len = (s->compressed_len + 3) & ~7L;
+}
+
+
+/* ===========================================================================
+ * Send one empty static block to give enough lookahead for inflate.
+ * This takes 10 bits, of which 7 may remain in the bit buffer.
+ * The current inflate code requires 9 bits of lookahead. If the EOB
+ * code for the previous block was coded on 5 bits or less, inflate
+ * may have only 5+3 bits of lookahead to decode this EOB.
+ * (There are no problems if the previous block is stored or fixed.)
+ */
+local void ct_align(s)
+ deflate_state *s;
+{
+ send_bits(s, STATIC_TREES<<1, 3);
+ send_code(s, END_BLOCK, static_ltree);
+ s->compressed_len += 10L; /* 3 for block type, 7 for EOB */
+ bi_flush(s);
+ /* Of the 10 bits for the empty block, we have already sent
+ * (10 - bi_valid) bits. The lookahead for the EOB of the previous
+ * block was thus its length plus what we have just sent.
+ */
+ if (s->last_eob_len + 10 - s->bi_valid < 9) {
+ send_bits(s, STATIC_TREES<<1, 3);
+ send_code(s, END_BLOCK, static_ltree);
+ s->compressed_len += 10L;
+ bi_flush(s);
+ }
+ s->last_eob_len = 7;
+}
+
+/* ===========================================================================
+ * Determine the best encoding for the current block: dynamic trees, static
+ * trees or store, and output the encoded block to the zip file. This function
+ * returns the total compressed length for the file so far.
+ */
+local ulg ct_flush_block(s, buf, stored_len, flush)
+ deflate_state *s;
+ charf *buf; /* input block, or NULL if too old */
+ ulg stored_len; /* length of input block */
+ int flush; /* Z_FINISH if this is the last block for a file */
+{
+ ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */
+ int max_blindex; /* index of last bit length code of non zero freq */
+ int eof = flush == Z_FINISH;
+
+ ++s->blocks_in_packet;
+
+ /* Check if the file is ascii or binary */
+ if (s->data_type == UNKNOWN) set_data_type(s);
+
+ /* Construct the literal and distance trees */
+ build_tree(s, (tree_desc *)(&(s->l_desc)));
+ Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len,
+ s->static_len));
+
+ build_tree(s, (tree_desc *)(&(s->d_desc)));
+ Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len,
+ s->static_len));
+ /* At this point, opt_len and static_len are the total bit lengths of
+ * the compressed block data, excluding the tree representations.
+ */
+
+ /* Build the bit length tree for the above two trees, and get the index
+ * in bl_order of the last bit length code to send.
+ */
+ max_blindex = build_bl_tree(s);
+
+ /* Determine the best encoding. Compute first the block length in bytes */
+ opt_lenb = (s->opt_len+3+7)>>3;
+ static_lenb = (s->static_len+3+7)>>3;
+
+ Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ",
+ opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len,
+ s->last_lit));
+
+ if (static_lenb <= opt_lenb) opt_lenb = static_lenb;
+
+ /* If compression failed and this is the first and last block,
+ * and if the .zip file can be seeked (to rewrite the local header),
+ * the whole file is transformed into a stored file:
+ */
+#ifdef STORED_FILE_OK
+# ifdef FORCE_STORED_FILE
+ if (eof && compressed_len == 0L) /* force stored file */
+# else
+ if (stored_len <= opt_lenb && eof && s->compressed_len==0L && seekable())
+# endif
+ {
+ /* Since LIT_BUFSIZE <= 2*WSIZE, the input data must be there: */
+ if (buf == (charf*)0) error ("block vanished");
+
+ copy_block(buf, (unsigned)stored_len, 0); /* without header */
+ s->compressed_len = stored_len << 3;
+ s->method = STORED;
+ } else
+#endif /* STORED_FILE_OK */
+
+ /* For Z_PACKET_FLUSH, if we don't achieve the required minimum
+ * compression, and this block contains all the data since the last
+ * time we used Z_PACKET_FLUSH, then just omit this block completely
+ * from the output.
+ */
+ if (flush == Z_PACKET_FLUSH && s->blocks_in_packet == 1
+ && opt_lenb > stored_len - s->minCompr) {
+ s->blocks_in_packet = 0;
+ /* output nothing */
+ } else
+
+#ifdef FORCE_STORED
+ if (buf != (char*)0) /* force stored block */
+#else
+ if (stored_len+4 <= opt_lenb && buf != (char*)0)
+ /* 4: two words for the lengths */
+#endif
+ {
+ /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE.
+ * Otherwise we can't have processed more than WSIZE input bytes since
+ * the last block flush, because compression would have been
+ * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to
+ * transform a block into a stored block.
+ */
+ ct_stored_block(s, buf, stored_len, eof);
+ } else
+
+#ifdef FORCE_STATIC
+ if (static_lenb >= 0) /* force static trees */
+#else
+ if (static_lenb == opt_lenb)
+#endif
+ {
+ send_bits(s, (STATIC_TREES<<1)+eof, 3);
+ compress_block(s, (ct_data *)static_ltree, (ct_data *)static_dtree);
+ s->compressed_len += 3 + s->static_len;
+ } else {
+ send_bits(s, (DYN_TREES<<1)+eof, 3);
+ send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1,
+ max_blindex+1);
+ compress_block(s, (ct_data *)s->dyn_ltree, (ct_data *)s->dyn_dtree);
+ s->compressed_len += 3 + s->opt_len;
+ }
+ Assert (s->compressed_len == s->bits_sent, "bad compressed size");
+ init_block(s);
+
+ if (eof) {
+ bi_windup(s);
+ s->compressed_len += 7; /* align on byte boundary */
+ }
+ Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3,
+ s->compressed_len-7*eof));
+
+ return s->compressed_len >> 3;
+}
+
+/* ===========================================================================
+ * Save the match info and tally the frequency counts. Return true if
+ * the current block must be flushed.
+ */
+local int ct_tally (s, dist, lc)
+ deflate_state *s;
+ int dist; /* distance of matched string */
+ int lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */
+{
+ s->d_buf[s->last_lit] = (ush)dist;
+ s->l_buf[s->last_lit++] = (uch)lc;
+ if (dist == 0) {
+ /* lc is the unmatched char */
+ s->dyn_ltree[lc].Freq++;
+ } else {
+ s->matches++;
+ /* Here, lc is the match length - MIN_MATCH */
+ dist--; /* dist = match distance - 1 */
+ Assert((ush)dist < (ush)MAX_DIST(s) &&
+ (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) &&
+ (ush)d_code(dist) < (ush)D_CODES, "ct_tally: bad match");
+
+ s->dyn_ltree[length_code[lc]+LITERALS+1].Freq++;
+ s->dyn_dtree[d_code(dist)].Freq++;
+ }
+
+ /* Try to guess if it is profitable to stop the current block here */
+ if (s->level > 2 && (s->last_lit & 0xfff) == 0) {
+ /* Compute an upper bound for the compressed length */
+ ulg out_length = (ulg)s->last_lit*8L;
+ ulg in_length = (ulg)s->strstart - s->block_start;
+ int dcode;
+ for (dcode = 0; dcode < D_CODES; dcode++) {
+ out_length += (ulg)s->dyn_dtree[dcode].Freq *
+ (5L+extra_dbits[dcode]);
+ }
+ out_length >>= 3;
+ Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ",
+ s->last_lit, in_length, out_length,
+ 100L - out_length*100L/in_length));
+ if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1;
+ }
+ return (s->last_lit == s->lit_bufsize-1);
+ /* We avoid equality with lit_bufsize because of wraparound at 64K
+ * on 16 bit machines and because stored blocks are restricted to
+ * 64K-1 bytes.
+ */
+}
+
+/* ===========================================================================
+ * Send the block data compressed using the given Huffman trees
+ */
+local void compress_block(s, ltree, dtree)
+ deflate_state *s;
+ ct_data *ltree; /* literal tree */
+ ct_data *dtree; /* distance tree */
+{
+ unsigned dist; /* distance of matched string */
+ int lc; /* match length or unmatched char (if dist == 0) */
+ unsigned lx = 0; /* running index in l_buf */
+ unsigned code; /* the code to send */
+ int extra; /* number of extra bits to send */
+
+ if (s->last_lit != 0) do {
+ dist = s->d_buf[lx];
+ lc = s->l_buf[lx++];
+ if (dist == 0) {
+ send_code(s, lc, ltree); /* send a literal byte */
+ Tracecv(isgraph(lc), (stderr," '%c' ", lc));
+ } else {
+ /* Here, lc is the match length - MIN_MATCH */
+ code = length_code[lc];
+ send_code(s, code+LITERALS+1, ltree); /* send the length code */
+ extra = extra_lbits[code];
+ if (extra != 0) {
+ lc -= base_length[code];
+ send_bits(s, lc, extra); /* send the extra length bits */
+ }
+ dist--; /* dist is now the match distance - 1 */
+ code = d_code(dist);
+ Assert (code < D_CODES, "bad d_code");
+
+ send_code(s, code, dtree); /* send the distance code */
+ extra = extra_dbits[code];
+ if (extra != 0) {
+ dist -= base_dist[code];
+ send_bits(s, dist, extra); /* send the extra distance bits */
+ }
+ } /* literal or match pair ? */
+
+ /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */
+ Assert(s->pending < s->lit_bufsize + 2*lx, "pendingBuf overflow");
+
+ } while (lx < s->last_lit);
+
+ send_code(s, END_BLOCK, ltree);
+ s->last_eob_len = ltree[END_BLOCK].Len;
+}
+
+/* ===========================================================================
+ * Set the data type to ASCII or BINARY, using a crude approximation:
+ * binary if more than 20% of the bytes are <= 6 or >= 128, ascii otherwise.
+ * IN assertion: the fields freq of dyn_ltree are set and the total of all
+ * frequencies does not exceed 64K (to fit in an int on 16 bit machines).
+ */
+local void set_data_type(s)
+ deflate_state *s;
+{
+ int n = 0;
+ unsigned ascii_freq = 0;
+ unsigned bin_freq = 0;
+ while (n < 7) bin_freq += s->dyn_ltree[n++].Freq;
+ while (n < 128) ascii_freq += s->dyn_ltree[n++].Freq;
+ while (n < LITERALS) bin_freq += s->dyn_ltree[n++].Freq;
+ s->data_type = (Byte)(bin_freq > (ascii_freq >> 2) ? BINARY : ASCII);
+}
+
+/* ===========================================================================
+ * Reverse the first len bits of a code, using straightforward code (a faster
+ * method would use a table)
+ * IN assertion: 1 <= len <= 15
+ */
+local unsigned bi_reverse(code, len)
+ unsigned code; /* the value to invert */
+ int len; /* its bit length */
+{
+ register unsigned res = 0;
+ do {
+ res |= code & 1;
+ code >>= 1, res <<= 1;
+ } while (--len > 0);
+ return res >> 1;
+}
+
+/* ===========================================================================
+ * Flush the bit buffer, keeping at most 7 bits in it.
+ */
+local void bi_flush(s)
+ deflate_state *s;
+{
+ if (s->bi_valid == 16) {
+ put_short(s, s->bi_buf);
+ s->bi_buf = 0;
+ s->bi_valid = 0;
+ } else if (s->bi_valid >= 8) {
+ put_byte(s, (Byte)s->bi_buf);
+ s->bi_buf >>= 8;
+ s->bi_valid -= 8;
+ }
+}
+
+/* ===========================================================================
+ * Flush the bit buffer and align the output on a byte boundary
+ */
+local void bi_windup(s)
+ deflate_state *s;
+{
+ if (s->bi_valid > 8) {
+ put_short(s, s->bi_buf);
+ } else if (s->bi_valid > 0) {
+ put_byte(s, (Byte)s->bi_buf);
+ }
+ s->bi_buf = 0;
+ s->bi_valid = 0;
+#ifdef DEBUG_ZLIB
+ s->bits_sent = (s->bits_sent+7) & ~7;
+#endif
+}
+
+/* ===========================================================================
+ * Copy a stored block, storing first the length and its
+ * one's complement if requested.
+ */
+local void copy_block(s, buf, len, header)
+ deflate_state *s;
+ charf *buf; /* the input data */
+ unsigned len; /* its length */
+ int header; /* true if block header must be written */
+{
+ bi_windup(s); /* align on byte boundary */
+ s->last_eob_len = 8; /* enough lookahead for inflate */
+
+ if (header) {
+ put_short(s, (ush)len);
+ put_short(s, (ush)~len);
+#ifdef DEBUG_ZLIB
+ s->bits_sent += 2*16;
+#endif
+ }
+#ifdef DEBUG_ZLIB
+ s->bits_sent += (ulg)len<<3;
+#endif
+ while (len--) {
+ put_byte(s, *buf++);
+ }
+}
+
+
+/*+++++*/
+/* infblock.h -- header to use infblock.c
+ * Copyright (C) 1995 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+struct inflate_blocks_state;
+typedef struct inflate_blocks_state FAR inflate_blocks_statef;
+
+local inflate_blocks_statef * inflate_blocks_new OF((
+ z_stream *z,
+ check_func c, /* check function */
+ uInt w)); /* window size */
+
+local int inflate_blocks OF((
+ inflate_blocks_statef *,
+ z_stream *,
+ int)); /* initial return code */
+
+local void inflate_blocks_reset OF((
+ inflate_blocks_statef *,
+ z_stream *,
+ uLongf *)); /* check value on output */
+
+local int inflate_blocks_free OF((
+ inflate_blocks_statef *,
+ z_stream *,
+ uLongf *)); /* check value on output */
+
+local int inflate_addhistory OF((
+ inflate_blocks_statef *,
+ z_stream *));
+
+local int inflate_packet_flush OF((
+ inflate_blocks_statef *));
+
+/*+++++*/
+/* inftrees.h -- header to use inftrees.c
+ * Copyright (C) 1995 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+/* Huffman code lookup table entry--this entry is four bytes for machines
+ that have 16-bit pointers (e.g. PC's in the small or medium model). */
+
+typedef struct inflate_huft_s FAR inflate_huft;
+
+struct inflate_huft_s {
+ union {
+ struct {
+ Byte Exop; /* number of extra bits or operation */
+ Byte Bits; /* number of bits in this code or subcode */
+ } what;
+ uInt Nalloc; /* number of these allocated here */
+ Bytef *pad; /* pad structure to a power of 2 (4 bytes for */
+ } word; /* 16-bit, 8 bytes for 32-bit machines) */
+ union {
+ uInt Base; /* literal, length base, or distance base */
+ inflate_huft *Next; /* pointer to next level of table */
+ } more;
+};
+
+#ifdef DEBUG_ZLIB
+ local uInt inflate_hufts;
+#endif
+
+local int inflate_trees_bits OF((
+ uIntf *, /* 19 code lengths */
+ uIntf *, /* bits tree desired/actual depth */
+ inflate_huft * FAR *, /* bits tree result */
+ z_stream *)); /* for zalloc, zfree functions */
+
+local int inflate_trees_dynamic OF((
+ uInt, /* number of literal/length codes */
+ uInt, /* number of distance codes */
+ uIntf *, /* that many (total) code lengths */
+ uIntf *, /* literal desired/actual bit depth */
+ uIntf *, /* distance desired/actual bit depth */
+ inflate_huft * FAR *, /* literal/length tree result */
+ inflate_huft * FAR *, /* distance tree result */
+ z_stream *)); /* for zalloc, zfree functions */
+
+local int inflate_trees_fixed OF((
+ uIntf *, /* literal desired/actual bit depth */
+ uIntf *, /* distance desired/actual bit depth */
+ inflate_huft * FAR *, /* literal/length tree result */
+ inflate_huft * FAR *)); /* distance tree result */
+
+local int inflate_trees_free OF((
+ inflate_huft *, /* tables to free */
+ z_stream *)); /* for zfree function */
+
+
+/*+++++*/
+/* infcodes.h -- header to use infcodes.c
+ * Copyright (C) 1995 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+struct inflate_codes_state;
+typedef struct inflate_codes_state FAR inflate_codes_statef;
+
+local inflate_codes_statef *inflate_codes_new OF((
+ uInt, uInt,
+ inflate_huft *, inflate_huft *,
+ z_stream *));
+
+local int inflate_codes OF((
+ inflate_blocks_statef *,
+ z_stream *,
+ int));
+
+local void inflate_codes_free OF((
+ inflate_codes_statef *,
+ z_stream *));
+
+
+/*+++++*/
+/* inflate.c -- zlib interface to inflate modules
+ * Copyright (C) 1995 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* inflate private state */
+struct internal_state {
+
+ /* mode */
+ enum {
+ METHOD, /* waiting for method byte */
+ FLAG, /* waiting for flag byte */
+ BLOCKS, /* decompressing blocks */
+ CHECK4, /* four check bytes to go */
+ CHECK3, /* three check bytes to go */
+ CHECK2, /* two check bytes to go */
+ CHECK1, /* one check byte to go */
+ DONE, /* finished check, done */
+ BAD} /* got an error--stay here */
+ mode; /* current inflate mode */
+
+ /* mode dependent information */
+ union {
+ uInt method; /* if FLAGS, method byte */
+ struct {
+ uLong was; /* computed check value */
+ uLong need; /* stream check value */
+ } check; /* if CHECK, check values to compare */
+ uInt marker; /* if BAD, inflateSync's marker bytes count */
+ } sub; /* submode */
+
+ /* mode independent information */
+ int nowrap; /* flag for no wrapper */
+ uInt wbits; /* log2(window size) (8..15, defaults to 15) */
+ inflate_blocks_statef
+ *blocks; /* current inflate_blocks state */
+
+};
+
+
+int inflateReset(z)
+z_stream *z;
+{
+ uLong c;
+
+ if (z == Z_NULL || z->state == Z_NULL)
+ return Z_STREAM_ERROR;
+ z->total_in = z->total_out = 0;
+ z->msg = Z_NULL;
+ z->state->mode = z->state->nowrap ? BLOCKS : METHOD;
+ inflate_blocks_reset(z->state->blocks, z, &c);
+ Trace((stderr, "inflate: reset\n"));
+ return Z_OK;
+}
+
+
+int inflateEnd(z)
+z_stream *z;
+{
+ uLong c;
+
+ if (z == Z_NULL || z->state == Z_NULL || z->zfree == Z_NULL)
+ return Z_STREAM_ERROR;
+ if (z->state->blocks != Z_NULL)
+ inflate_blocks_free(z->state->blocks, z, &c);
+ ZFREE(z, z->state, sizeof(struct internal_state));
+ z->state = Z_NULL;
+ Trace((stderr, "inflate: end\n"));
+ return Z_OK;
+}
+
+
+int inflateInit2(z, w)
+z_stream *z;
+int w;
+{
+ /* initialize state */
+ if (z == Z_NULL)
+ return Z_STREAM_ERROR;
+/* if (z->zalloc == Z_NULL) z->zalloc = zcalloc; */
+/* if (z->zfree == Z_NULL) z->zfree = zcfree; */
+ if ((z->state = (struct internal_state FAR *)
+ ZALLOC(z,1,sizeof(struct internal_state))) == Z_NULL)
+ return Z_MEM_ERROR;
+ z->state->blocks = Z_NULL;
+
+ /* handle undocumented nowrap option (no zlib header or check) */
+ z->state->nowrap = 0;
+ if (w < 0)
+ {
+ w = - w;
+ z->state->nowrap = 1;
+ }
+
+ /* set window size */
+ if (w < 8 || w > 15)
+ {
+ inflateEnd(z);
+ return Z_STREAM_ERROR;
+ }
+ z->state->wbits = (uInt)w;
+
+ /* create inflate_blocks state */
+ if ((z->state->blocks =
+ inflate_blocks_new(z, z->state->nowrap ? Z_NULL : adler32, 1 << w))
+ == Z_NULL)
+ {
+ inflateEnd(z);
+ return Z_MEM_ERROR;
+ }
+ Trace((stderr, "inflate: allocated\n"));
+
+ /* reset state */
+ inflateReset(z);
+ return Z_OK;
+}
+
+
+int inflateInit(z)
+z_stream *z;
+{
+ return inflateInit2(z, DEF_WBITS);
+}
+
+
+#define NEEDBYTE {if(z->avail_in==0)goto empty;r=Z_OK;}
+#define NEXTBYTE (z->avail_in--,z->total_in++,*z->next_in++)
+
+int inflate(z, f)
+z_stream *z;
+int f;
+{
+ int r;
+ uInt b;
+
+ if (z == Z_NULL || z->next_in == Z_NULL)
+ return Z_STREAM_ERROR;
+ r = Z_BUF_ERROR;
+ while (1) switch (z->state->mode)
+ {
+ case METHOD:
+ NEEDBYTE
+ if (((z->state->sub.method = NEXTBYTE) & 0xf) != DEFLATED)
+ {
+ z->state->mode = BAD;
+ z->msg = "unknown compression method";
+ z->state->sub.marker = 5; /* can't try inflateSync */
+ break;
+ }
+ if ((z->state->sub.method >> 4) + 8 > z->state->wbits)
+ {
+ z->state->mode = BAD;
+ z->msg = "invalid window size";
+ z->state->sub.marker = 5; /* can't try inflateSync */
+ break;
+ }
+ z->state->mode = FLAG;
+ case FLAG:
+ NEEDBYTE
+ if ((b = NEXTBYTE) & 0x20)
+ {
+ z->state->mode = BAD;
+ z->msg = "invalid reserved bit";
+ z->state->sub.marker = 5; /* can't try inflateSync */
+ break;
+ }
+ if (((z->state->sub.method << 8) + b) % 31)
+ {
+ z->state->mode = BAD;
+ z->msg = "incorrect header check";
+ z->state->sub.marker = 5; /* can't try inflateSync */
+ break;
+ }
+ Trace((stderr, "inflate: zlib header ok\n"));
+ z->state->mode = BLOCKS;
+ case BLOCKS:
+ r = inflate_blocks(z->state->blocks, z, r);
+ if (f == Z_PACKET_FLUSH && z->avail_in == 0 && z->avail_out != 0)
+ r = inflate_packet_flush(z->state->blocks);
+ if (r == Z_DATA_ERROR)
+ {
+ z->state->mode = BAD;
+ z->state->sub.marker = 0; /* can try inflateSync */
+ break;
+ }
+ if (r != Z_STREAM_END)
+ return r;
+ r = Z_OK;
+ inflate_blocks_reset(z->state->blocks, z, &z->state->sub.check.was);
+ if (z->state->nowrap)
+ {
+ z->state->mode = DONE;
+ break;
+ }
+ z->state->mode = CHECK4;
+ case CHECK4:
+ NEEDBYTE
+ z->state->sub.check.need = (uLong)NEXTBYTE << 24;
+ z->state->mode = CHECK3;
+ case CHECK3:
+ NEEDBYTE
+ z->state->sub.check.need += (uLong)NEXTBYTE << 16;
+ z->state->mode = CHECK2;
+ case CHECK2:
+ NEEDBYTE
+ z->state->sub.check.need += (uLong)NEXTBYTE << 8;
+ z->state->mode = CHECK1;
+ case CHECK1:
+ NEEDBYTE
+ z->state->sub.check.need += (uLong)NEXTBYTE;
+
+ if (z->state->sub.check.was != z->state->sub.check.need)
+ {
+ z->state->mode = BAD;
+ z->msg = "incorrect data check";
+ z->state->sub.marker = 5; /* can't try inflateSync */
+ break;
+ }
+ Trace((stderr, "inflate: zlib check ok\n"));
+ z->state->mode = DONE;
+ case DONE:
+ return Z_STREAM_END;
+ case BAD:
+ return Z_DATA_ERROR;
+ default:
+ return Z_STREAM_ERROR;
+ }
+
+ empty:
+ if (f != Z_PACKET_FLUSH)
+ return r;
+ z->state->mode = BAD;
+ z->state->sub.marker = 0; /* can try inflateSync */
+ return Z_DATA_ERROR;
+}
+
+/*
+ * This subroutine adds the data at next_in/avail_in to the output history
+ * without performing any output. The output buffer must be "caught up";
+ * i.e. no pending output (hence s->read equals s->write), and the state must
+ * be BLOCKS (i.e. we should be willing to see the start of a series of
+ * BLOCKS). On exit, the output will also be caught up, and the checksum
+ * will have been updated if need be.
+ */
+
+int inflateIncomp(z)
+z_stream *z;
+{
+ if (z->state->mode != BLOCKS)
+ return Z_DATA_ERROR;
+ return inflate_addhistory(z->state->blocks, z);
+}
+
+
+int inflateSync(z)
+z_stream *z;
+{
+ uInt n; /* number of bytes to look at */
+ Bytef *p; /* pointer to bytes */
+ uInt m; /* number of marker bytes found in a row */
+ uLong r, w; /* temporaries to save total_in and total_out */
+
+ /* set up */
+ if (z == Z_NULL || z->state == Z_NULL)
+ return Z_STREAM_ERROR;
+ if (z->state->mode != BAD)
+ {
+ z->state->mode = BAD;
+ z->state->sub.marker = 0;
+ }
+ if ((n = z->avail_in) == 0)
+ return Z_BUF_ERROR;
+ p = z->next_in;
+ m = z->state->sub.marker;
+
+ /* search */
+ while (n && m < 4)
+ {
+ if (*p == (Byte)(m < 2 ? 0 : 0xff))
+ m++;
+ else if (*p)
+ m = 0;
+ else
+ m = 4 - m;
+ p++, n--;
+ }
+
+ /* restore */
+ z->total_in += p - z->next_in;
+ z->next_in = p;
+ z->avail_in = n;
+ z->state->sub.marker = m;
+
+ /* return no joy or set up to restart on a new block */
+ if (m != 4)
+ return Z_DATA_ERROR;
+ r = z->total_in; w = z->total_out;
+ inflateReset(z);
+ z->total_in = r; z->total_out = w;
+ z->state->mode = BLOCKS;
+ return Z_OK;
+}
+
+#undef NEEDBYTE
+#undef NEXTBYTE
+
+/*+++++*/
+/* infutil.h -- types and macros common to blocks and codes
+ * Copyright (C) 1995 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+/* inflate blocks semi-private state */
+struct inflate_blocks_state {
+
+ /* mode */
+ enum {
+ TYPE, /* get type bits (3, including end bit) */
+ LENS, /* get lengths for stored */
+ STORED, /* processing stored block */
+ TABLE, /* get table lengths */
+ BTREE, /* get bit lengths tree for a dynamic block */
+ DTREE, /* get length, distance trees for a dynamic block */
+ CODES, /* processing fixed or dynamic block */
+ DRY, /* output remaining window bytes */
+ DONEB, /* finished last block, done */
+ BADB} /* got a data error--stuck here */
+ mode; /* current inflate_block mode */
+
+ /* mode dependent information */
+ union {
+ uInt left; /* if STORED, bytes left to copy */
+ struct {
+ uInt table; /* table lengths (14 bits) */
+ uInt index; /* index into blens (or border) */
+ uIntf *blens; /* bit lengths of codes */
+ uInt bb; /* bit length tree depth */
+ inflate_huft *tb; /* bit length decoding tree */
+ int nblens; /* # elements allocated at blens */
+ } trees; /* if DTREE, decoding info for trees */
+ struct {
+ inflate_huft *tl, *td; /* trees to free */
+ inflate_codes_statef
+ *codes;
+ } decode; /* if CODES, current state */
+ } sub; /* submode */
+ uInt last; /* true if this block is the last block */
+
+ /* mode independent information */
+ uInt bitk; /* bits in bit buffer */
+ uLong bitb; /* bit buffer */
+ Bytef *window; /* sliding window */
+ Bytef *end; /* one byte after sliding window */
+ Bytef *read; /* window read pointer */
+ Bytef *write; /* window write pointer */
+ check_func checkfn; /* check function */
+ uLong check; /* check on output */
+
+};
+
+
+/* defines for inflate input/output */
+/* update pointers and return */
+#define UPDBITS {s->bitb=b;s->bitk=k;}
+#define UPDIN {z->avail_in=n;z->total_in+=p-z->next_in;z->next_in=p;}
+#define UPDOUT {s->write=q;}
+#define UPDATE {UPDBITS UPDIN UPDOUT}
+#define LEAVE {UPDATE return inflate_flush(s,z,r);}
+/* get bytes and bits */
+#define LOADIN {p=z->next_in;n=z->avail_in;b=s->bitb;k=s->bitk;}
+#define NEEDBYTE {if(n)r=Z_OK;else LEAVE}
+#define NEXTBYTE (n--,*p++)
+#define NEEDBITS(j) {while(k<(j)){NEEDBYTE;b|=((uLong)NEXTBYTE)<<k;k+=8;}}
+#define DUMPBITS(j) {b>>=(j);k-=(j);}
+/* output bytes */
+#define WAVAIL (q<s->read?s->read-q-1:s->end-q)
+#define LOADOUT {q=s->write;m=WAVAIL;}
+#define WRAP {if(q==s->end&&s->read!=s->window){q=s->window;m=WAVAIL;}}
+#define FLUSH {UPDOUT r=inflate_flush(s,z,r); LOADOUT}
+#define NEEDOUT {if(m==0){WRAP if(m==0){FLUSH WRAP if(m==0) LEAVE}}r=Z_OK;}
+#define OUTBYTE(a) {*q++=(Byte)(a);m--;}
+/* load local pointers */
+#define LOAD {LOADIN LOADOUT}
+
+/* And'ing with mask[n] masks the lower n bits */
+local uInt inflate_mask[] = {
+ 0x0000,
+ 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,
+ 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff
+};
+
+/* copy as much as possible from the sliding window to the output area */
+local int inflate_flush OF((
+ inflate_blocks_statef *,
+ z_stream *,
+ int));
+
+/*+++++*/
+/* inffast.h -- header to use inffast.c
+ * Copyright (C) 1995 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+local int inflate_fast OF((
+ uInt,
+ uInt,
+ inflate_huft *,
+ inflate_huft *,
+ inflate_blocks_statef *,
+ z_stream *));
+
+
+/*+++++*/
+/* infblock.c -- interpret and process block types to last block
+ * Copyright (C) 1995 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* Table for deflate from PKZIP's appnote.txt. */
+local uInt border[] = { /* Order of the bit length code lengths */
+ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
+
+/*
+ Notes beyond the 1.93a appnote.txt:
+
+ 1. Distance pointers never point before the beginning of the output
+ stream.
+ 2. Distance pointers can point back across blocks, up to 32k away.
+ 3. There is an implied maximum of 7 bits for the bit length table and
+ 15 bits for the actual data.
+ 4. If only one code exists, then it is encoded using one bit. (Zero
+ would be more efficient, but perhaps a little confusing.) If two
+ codes exist, they are coded using one bit each (0 and 1).
+ 5. There is no way of sending zero distance codes--a dummy must be
+ sent if there are none. (History: a pre 2.0 version of PKZIP would
+ store blocks with no distance codes, but this was discovered to be
+ too harsh a criterion.) Valid only for 1.93a. 2.04c does allow
+ zero distance codes, which is sent as one code of zero bits in
+ length.
+ 6. There are up to 286 literal/length codes. Code 256 represents the
+ end-of-block. Note however that the static length tree defines
+ 288 codes just to fill out the Huffman codes. Codes 286 and 287
+ cannot be used though, since there is no length base or extra bits
+ defined for them. Similarily, there are up to 30 distance codes.
+ However, static trees define 32 codes (all 5 bits) to fill out the
+ Huffman codes, but the last two had better not show up in the data.
+ 7. Unzip can check dynamic Huffman blocks for complete code sets.
+ The exception is that a single code would not be complete (see #4).
+ 8. The five bits following the block type is really the number of
+ literal codes sent minus 257.
+ 9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits
+ (1+6+6). Therefore, to output three times the length, you output
+ three codes (1+1+1), whereas to output four times the same length,
+ you only need two codes (1+3). Hmm.
+ 10. In the tree reconstruction algorithm, Code = Code + Increment
+ only if BitLength(i) is not zero. (Pretty obvious.)
+ 11. Correction: 4 Bits: # of Bit Length codes - 4 (4 - 19)
+ 12. Note: length code 284 can represent 227-258, but length code 285
+ really is 258. The last length deserves its own, short code
+ since it gets used a lot in very redundant files. The length
+ 258 is special since 258 - 3 (the min match length) is 255.
+ 13. The literal/length and distance code bit lengths are read as a
+ single stream of lengths. It is possible (and advantageous) for
+ a repeat code (16, 17, or 18) to go across the boundary between
+ the two sets of lengths.
+ */
+
+
+local void inflate_blocks_reset(s, z, c)
+inflate_blocks_statef *s;
+z_stream *z;
+uLongf *c;
+{
+ if (s->checkfn != Z_NULL)
+ *c = s->check;
+ if (s->mode == BTREE || s->mode == DTREE)
+ ZFREE(z, s->sub.trees.blens, s->sub.trees.nblens * sizeof(uInt));
+ if (s->mode == CODES)
+ {
+ inflate_codes_free(s->sub.decode.codes, z);
+ inflate_trees_free(s->sub.decode.td, z);
+ inflate_trees_free(s->sub.decode.tl, z);
+ }
+ s->mode = TYPE;
+ s->bitk = 0;
+ s->bitb = 0;
+ s->read = s->write = s->window;
+ if (s->checkfn != Z_NULL)
+ s->check = (*s->checkfn)(0L, Z_NULL, 0);
+ Trace((stderr, "inflate: blocks reset\n"));
+}
+
+
+local inflate_blocks_statef *inflate_blocks_new(z, c, w)
+z_stream *z;
+check_func c;
+uInt w;
+{
+ inflate_blocks_statef *s;
+
+ if ((s = (inflate_blocks_statef *)ZALLOC
+ (z,1,sizeof(struct inflate_blocks_state))) == Z_NULL)
+ return s;
+ if ((s->window = (Bytef *)ZALLOC(z, 1, w)) == Z_NULL)
+ {
+ ZFREE(z, s, sizeof(struct inflate_blocks_state));
+ return Z_NULL;
+ }
+ s->end = s->window + w;
+ s->checkfn = c;
+ s->mode = TYPE;
+ Trace((stderr, "inflate: blocks allocated\n"));
+ inflate_blocks_reset(s, z, &s->check);
+ return s;
+}
+
+
+local int inflate_blocks(s, z, r)
+inflate_blocks_statef *s;
+z_stream *z;
+int r;
+{
+ uInt t; /* temporary storage */
+ uLong b; /* bit buffer */
+ uInt k; /* bits in bit buffer */
+ Bytef *p; /* input data pointer */
+ uInt n; /* bytes available there */
+ Bytef *q; /* output window write pointer */
+ uInt m; /* bytes to end of window or read pointer */
+
+ /* copy input/output information to locals (UPDATE macro restores) */
+ LOAD
+
+ /* process input based on current state */
+ while (1) switch (s->mode)
+ {
+ case TYPE:
+ NEEDBITS(3)
+ t = (uInt)b & 7;
+ s->last = t & 1;
+ switch (t >> 1)
+ {
+ case 0: /* stored */
+ Trace((stderr, "inflate: stored block%s\n",
+ s->last ? " (last)" : ""));
+ DUMPBITS(3)
+ t = k & 7; /* go to byte boundary */
+ DUMPBITS(t)
+ s->mode = LENS; /* get length of stored block */
+ break;
+ case 1: /* fixed */
+ Trace((stderr, "inflate: fixed codes block%s\n",
+ s->last ? " (last)" : ""));
+ {
+ uInt bl, bd;
+ inflate_huft *tl, *td;
+
+ inflate_trees_fixed(&bl, &bd, &tl, &td);
+ s->sub.decode.codes = inflate_codes_new(bl, bd, tl, td, z);
+ if (s->sub.decode.codes == Z_NULL)
+ {
+ r = Z_MEM_ERROR;
+ LEAVE
+ }
+ s->sub.decode.tl = Z_NULL; /* don't try to free these */
+ s->sub.decode.td = Z_NULL;
+ }
+ DUMPBITS(3)
+ s->mode = CODES;
+ break;
+ case 2: /* dynamic */
+ Trace((stderr, "inflate: dynamic codes block%s\n",
+ s->last ? " (last)" : ""));
+ DUMPBITS(3)
+ s->mode = TABLE;
+ break;
+ case 3: /* illegal */
+ DUMPBITS(3)
+ s->mode = BADB;
+ z->msg = "invalid block type";
+ r = Z_DATA_ERROR;
+ LEAVE
+ }
+ break;
+ case LENS:
+ NEEDBITS(32)
+ if (((~b) >> 16) != (b & 0xffff))
+ {
+ s->mode = BADB;
+ z->msg = "invalid stored block lengths";
+ r = Z_DATA_ERROR;
+ LEAVE
+ }
+ s->sub.left = (uInt)b & 0xffff;
+ b = k = 0; /* dump bits */
+ Tracev((stderr, "inflate: stored length %u\n", s->sub.left));
+ s->mode = s->sub.left ? STORED : TYPE;
+ break;
+ case STORED:
+ if (n == 0)
+ LEAVE
+ NEEDOUT
+ t = s->sub.left;
+ if (t > n) t = n;
+ if (t > m) t = m;
+ zmemcpy(q, p, t);
+ p += t; n -= t;
+ q += t; m -= t;
+ if ((s->sub.left -= t) != 0)
+ break;
+ Tracev((stderr, "inflate: stored end, %lu total out\n",
+ z->total_out + (q >= s->read ? q - s->read :
+ (s->end - s->read) + (q - s->window))));
+ s->mode = s->last ? DRY : TYPE;
+ break;
+ case TABLE:
+ NEEDBITS(14)
+ s->sub.trees.table = t = (uInt)b & 0x3fff;
+#ifndef PKZIP_BUG_WORKAROUND
+ if ((t & 0x1f) > 29 || ((t >> 5) & 0x1f) > 29)
+ {
+ s->mode = BADB;
+ z->msg = "too many length or distance symbols";
+ r = Z_DATA_ERROR;
+ LEAVE
+ }
+#endif
+ t = 258 + (t & 0x1f) + ((t >> 5) & 0x1f);
+ if (t < 19)
+ t = 19;
+ if ((s->sub.trees.blens = (uIntf*)ZALLOC(z, t, sizeof(uInt))) == Z_NULL)
+ {
+ r = Z_MEM_ERROR;
+ LEAVE
+ }
+ s->sub.trees.nblens = t;
+ DUMPBITS(14)
+ s->sub.trees.index = 0;
+ Tracev((stderr, "inflate: table sizes ok\n"));
+ s->mode = BTREE;
+ case BTREE:
+ while (s->sub.trees.index < 4 + (s->sub.trees.table >> 10))
+ {
+ NEEDBITS(3)
+ s->sub.trees.blens[border[s->sub.trees.index++]] = (uInt)b & 7;
+ DUMPBITS(3)
+ }
+ while (s->sub.trees.index < 19)
+ s->sub.trees.blens[border[s->sub.trees.index++]] = 0;
+ s->sub.trees.bb = 7;
+ t = inflate_trees_bits(s->sub.trees.blens, &s->sub.trees.bb,
+ &s->sub.trees.tb, z);
+ if (t != Z_OK)
+ {
+ r = t;
+ if (r == Z_DATA_ERROR)
+ s->mode = BADB;
+ LEAVE
+ }
+ s->sub.trees.index = 0;
+ Tracev((stderr, "inflate: bits tree ok\n"));
+ s->mode = DTREE;
+ case DTREE:
+ while (t = s->sub.trees.table,
+ s->sub.trees.index < 258 + (t & 0x1f) + ((t >> 5) & 0x1f))
+ {
+ inflate_huft *h;
+ uInt i, j, c;
+
+ t = s->sub.trees.bb;
+ NEEDBITS(t)
+ h = s->sub.trees.tb + ((uInt)b & inflate_mask[t]);
+ t = h->word.what.Bits;
+ c = h->more.Base;
+ if (c < 16)
+ {
+ DUMPBITS(t)
+ s->sub.trees.blens[s->sub.trees.index++] = c;
+ }
+ else /* c == 16..18 */
+ {
+ i = c == 18 ? 7 : c - 14;
+ j = c == 18 ? 11 : 3;
+ NEEDBITS(t + i)
+ DUMPBITS(t)
+ j += (uInt)b & inflate_mask[i];
+ DUMPBITS(i)
+ i = s->sub.trees.index;
+ t = s->sub.trees.table;
+ if (i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) ||
+ (c == 16 && i < 1))
+ {
+ s->mode = BADB;
+ z->msg = "invalid bit length repeat";
+ r = Z_DATA_ERROR;
+ LEAVE
+ }
+ c = c == 16 ? s->sub.trees.blens[i - 1] : 0;
+ do {
+ s->sub.trees.blens[i++] = c;
+ } while (--j);
+ s->sub.trees.index = i;
+ }
+ }
+ inflate_trees_free(s->sub.trees.tb, z);
+ s->sub.trees.tb = Z_NULL;
+ {
+ uInt bl, bd;
+ inflate_huft *tl, *td;
+ inflate_codes_statef *c;
+
+ bl = 9; /* must be <= 9 for lookahead assumptions */
+ bd = 6; /* must be <= 9 for lookahead assumptions */
+ t = s->sub.trees.table;
+ t = inflate_trees_dynamic(257 + (t & 0x1f), 1 + ((t >> 5) & 0x1f),
+ s->sub.trees.blens, &bl, &bd, &tl, &td, z);
+ if (t != Z_OK)
+ {
+ if (t == (uInt)Z_DATA_ERROR)
+ s->mode = BADB;
+ r = t;
+ LEAVE
+ }
+ Tracev((stderr, "inflate: trees ok\n"));
+ if ((c = inflate_codes_new(bl, bd, tl, td, z)) == Z_NULL)
+ {
+ inflate_trees_free(td, z);
+ inflate_trees_free(tl, z);
+ r = Z_MEM_ERROR;
+ LEAVE
+ }
+ ZFREE(z, s->sub.trees.blens, s->sub.trees.nblens * sizeof(uInt));
+ s->sub.decode.codes = c;
+ s->sub.decode.tl = tl;
+ s->sub.decode.td = td;
+ }
+ s->mode = CODES;
+ case CODES:
+ UPDATE
+ if ((r = inflate_codes(s, z, r)) != Z_STREAM_END)
+ return inflate_flush(s, z, r);
+ r = Z_OK;
+ inflate_codes_free(s->sub.decode.codes, z);
+ inflate_trees_free(s->sub.decode.td, z);
+ inflate_trees_free(s->sub.decode.tl, z);
+ LOAD
+ Tracev((stderr, "inflate: codes end, %lu total out\n",
+ z->total_out + (q >= s->read ? q - s->read :
+ (s->end - s->read) + (q - s->window))));
+ if (!s->last)
+ {
+ s->mode = TYPE;
+ break;
+ }
+ if (k > 7) /* return unused byte, if any */
+ {
+ Assert(k < 16, "inflate_codes grabbed too many bytes")
+ k -= 8;
+ n++;
+ p--; /* can always return one */
+ }
+ s->mode = DRY;
+ case DRY:
+ FLUSH
+ if (s->read != s->write)
+ LEAVE
+ s->mode = DONEB;
+ case DONEB:
+ r = Z_STREAM_END;
+ LEAVE
+ case BADB:
+ r = Z_DATA_ERROR;
+ LEAVE
+ default:
+ r = Z_STREAM_ERROR;
+ LEAVE
+ }
+}
+
+
+local int inflate_blocks_free(s, z, c)
+inflate_blocks_statef *s;
+z_stream *z;
+uLongf *c;
+{
+ inflate_blocks_reset(s, z, c);
+ ZFREE(z, s->window, s->end - s->window);
+ ZFREE(z, s, sizeof(struct inflate_blocks_state));
+ Trace((stderr, "inflate: blocks freed\n"));
+ return Z_OK;
+}
+
+/*
+ * This subroutine adds the data at next_in/avail_in to the output history
+ * without performing any output. The output buffer must be "caught up";
+ * i.e. no pending output (hence s->read equals s->write), and the state must
+ * be BLOCKS (i.e. we should be willing to see the start of a series of
+ * BLOCKS). On exit, the output will also be caught up, and the checksum
+ * will have been updated if need be.
+ */
+local int inflate_addhistory(s, z)
+inflate_blocks_statef *s;
+z_stream *z;
+{
+ uLong b; /* bit buffer */ /* NOT USED HERE */
+ uInt k; /* bits in bit buffer */ /* NOT USED HERE */
+ uInt t; /* temporary storage */
+ Bytef *p; /* input data pointer */
+ uInt n; /* bytes available there */
+ Bytef *q; /* output window write pointer */
+ uInt m; /* bytes to end of window or read pointer */
+
+ if (s->read != s->write)
+ return Z_STREAM_ERROR;
+ if (s->mode != TYPE)
+ return Z_DATA_ERROR;
+
+ /* we're ready to rock */
+ LOAD
+ /* while there is input ready, copy to output buffer, moving
+ * pointers as needed.
+ */
+ while (n) {
+ t = n; /* how many to do */
+ /* is there room until end of buffer? */
+ if (t > m) t = m;
+ /* update check information */
+ if (s->checkfn != Z_NULL)
+ s->check = (*s->checkfn)(s->check, q, t);
+ zmemcpy(q, p, t);
+ q += t;
+ p += t;
+ n -= t;
+ z->total_out += t;
+ s->read = q; /* drag read pointer forward */
+/* WRAP */ /* expand WRAP macro by hand to handle s->read */
+ if (q == s->end) {
+ s->read = q = s->window;
+ m = WAVAIL;
+ }
+ }
+ UPDATE
+ return Z_OK;
+}
+
+
+/*
+ * At the end of a Deflate-compressed PPP packet, we expect to have seen
+ * a `stored' block type value but not the (zero) length bytes.
+ */
+local int inflate_packet_flush(s)
+ inflate_blocks_statef *s;
+{
+ if (s->mode != LENS)
+ return Z_DATA_ERROR;
+ s->mode = TYPE;
+ return Z_OK;
+}
+
+
+/*+++++*/
+/* inftrees.c -- generate Huffman trees for efficient decoding
+ * Copyright (C) 1995 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* simplify the use of the inflate_huft type with some defines */
+#define base more.Base
+#define next more.Next
+#define exop word.what.Exop
+#define bits word.what.Bits
+
+
+local int huft_build OF((
+ uIntf *, /* code lengths in bits */
+ uInt, /* number of codes */
+ uInt, /* number of "simple" codes */
+ uIntf *, /* list of base values for non-simple codes */
+ uIntf *, /* list of extra bits for non-simple codes */
+ inflate_huft * FAR*,/* result: starting table */
+ uIntf *, /* maximum lookup bits (returns actual) */
+ z_stream *)); /* for zalloc function */
+
+local voidpf falloc OF((
+ voidpf, /* opaque pointer (not used) */
+ uInt, /* number of items */
+ uInt)); /* size of item */
+
+local void ffree OF((
+ voidpf q, /* opaque pointer (not used) */
+ voidpf p, /* what to free (not used) */
+ uInt n)); /* number of bytes (not used) */
+
+/* Tables for deflate from PKZIP's appnote.txt. */
+local uInt cplens[] = { /* Copy lengths for literal codes 257..285 */
+ 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
+ 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
+ /* actually lengths - 2; also see note #13 above about 258 */
+local uInt cplext[] = { /* Extra bits for literal codes 257..285 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
+ 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 192, 192}; /* 192==invalid */
+local uInt cpdist[] = { /* Copy offsets for distance codes 0..29 */
+ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
+ 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
+ 8193, 12289, 16385, 24577};
+local uInt cpdext[] = { /* Extra bits for distance codes */
+ 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
+ 7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
+ 12, 12, 13, 13};
+
+/*
+ Huffman code decoding is performed using a multi-level table lookup.
+ The fastest way to decode is to simply build a lookup table whose
+ size is determined by the longest code. However, the time it takes
+ to build this table can also be a factor if the data being decoded
+ is not very long. The most common codes are necessarily the
+ shortest codes, so those codes dominate the decoding time, and hence
+ the speed. The idea is you can have a shorter table that decodes the
+ shorter, more probable codes, and then point to subsidiary tables for
+ the longer codes. The time it costs to decode the longer codes is
+ then traded against the time it takes to make longer tables.
+
+ This results of this trade are in the variables lbits and dbits
+ below. lbits is the number of bits the first level table for literal/
+ length codes can decode in one step, and dbits is the same thing for
+ the distance codes. Subsequent tables are also less than or equal to
+ those sizes. These values may be adjusted either when all of the
+ codes are shorter than that, in which case the longest code length in
+ bits is used, or when the shortest code is *longer* than the requested
+ table size, in which case the length of the shortest code in bits is
+ used.
+
+ There are two different values for the two tables, since they code a
+ different number of possibilities each. The literal/length table
+ codes 286 possible values, or in a flat code, a little over eight
+ bits. The distance table codes 30 possible values, or a little less
+ than five bits, flat. The optimum values for speed end up being
+ about one bit more than those, so lbits is 8+1 and dbits is 5+1.
+ The optimum values may differ though from machine to machine, and
+ possibly even between compilers. Your mileage may vary.
+ */
+
+
+/* If BMAX needs to be larger than 16, then h and x[] should be uLong. */
+#define BMAX 15 /* maximum bit length of any code */
+#define N_MAX 288 /* maximum number of codes in any set */
+
+#ifdef DEBUG_ZLIB
+ uInt inflate_hufts;
+#endif
+
+local int huft_build(b, n, s, d, e, t, m, zs)
+uIntf *b; /* code lengths in bits (all assumed <= BMAX) */
+uInt n; /* number of codes (assumed <= N_MAX) */
+uInt s; /* number of simple-valued codes (0..s-1) */
+uIntf *d; /* list of base values for non-simple codes */
+uIntf *e; /* list of extra bits for non-simple codes */
+inflate_huft * FAR *t; /* result: starting table */
+uIntf *m; /* maximum lookup bits, returns actual */
+z_stream *zs; /* for zalloc function */
+/* Given a list of code lengths and a maximum table size, make a set of
+ tables to decode that set of codes. Return Z_OK on success, Z_BUF_ERROR
+ if the given code set is incomplete (the tables are still built in this
+ case), Z_DATA_ERROR if the input is invalid (all zero length codes or an
+ over-subscribed set of lengths), or Z_MEM_ERROR if not enough memory. */
+{
+
+ uInt a; /* counter for codes of length k */
+ uInt c[BMAX+1]; /* bit length count table */
+ uInt f; /* i repeats in table every f entries */
+ int g; /* maximum code length */
+ int h; /* table level */
+ register uInt i; /* counter, current code */
+ register uInt j; /* counter */
+ register int k; /* number of bits in current code */
+ int l; /* bits per table (returned in m) */
+ register uIntf *p; /* pointer into c[], b[], or v[] */
+ inflate_huft *q; /* points to current table */
+ struct inflate_huft_s r; /* table entry for structure assignment */
+ inflate_huft *u[BMAX]; /* table stack */
+ uInt v[N_MAX]; /* values in order of bit length */
+ register int w; /* bits before this table == (l * h) */
+ uInt x[BMAX+1]; /* bit offsets, then code stack */
+ uIntf *xp; /* pointer into x */
+ int y; /* number of dummy codes added */
+ uInt z; /* number of entries in current table */
+
+
+ /* Generate counts for each bit length */
+ p = c;
+#define C0 *p++ = 0;
+#define C2 C0 C0 C0 C0
+#define C4 C2 C2 C2 C2
+ C4 /* clear c[]--assume BMAX+1 is 16 */
+ p = b; i = n;
+ do {
+ c[*p++]++; /* assume all entries <= BMAX */
+ } while (--i);
+ if (c[0] == n) /* null input--all zero length codes */
+ {
+ *t = (inflate_huft *)Z_NULL;
+ *m = 0;
+ return Z_OK;
+ }
+
+
+ /* Find minimum and maximum length, bound *m by those */
+ l = *m;
+ for (j = 1; j <= BMAX; j++)
+ if (c[j])
+ break;
+ k = j; /* minimum code length */
+ if ((uInt)l < j)
+ l = j;
+ for (i = BMAX; i; i--)
+ if (c[i])
+ break;
+ g = i; /* maximum code length */
+ if ((uInt)l > i)
+ l = i;
+ *m = l;
+
+
+ /* Adjust last length count to fill out codes, if needed */
+ for (y = 1 << j; j < i; j++, y <<= 1)
+ if ((y -= c[j]) < 0)
+ return Z_DATA_ERROR;
+ if ((y -= c[i]) < 0)
+ return Z_DATA_ERROR;
+ c[i] += y;
+
+
+ /* Generate starting offsets into the value table for each length */
+ x[1] = j = 0;
+ p = c + 1; xp = x + 2;
+ while (--i) { /* note that i == g from above */
+ *xp++ = (j += *p++);
+ }
+
+
+ /* Make a table of values in order of bit lengths */
+ p = b; i = 0;
+ do {
+ if ((j = *p++) != 0)
+ v[x[j]++] = i;
+ } while (++i < n);
+
+
+ /* Generate the Huffman codes and for each, make the table entries */
+ x[0] = i = 0; /* first Huffman code is zero */
+ p = v; /* grab values in bit order */
+ h = -1; /* no tables yet--level -1 */
+ w = -l; /* bits decoded == (l * h) */
+ u[0] = (inflate_huft *)Z_NULL; /* just to keep compilers happy */
+ q = (inflate_huft *)Z_NULL; /* ditto */
+ z = 0; /* ditto */
+
+ /* go through the bit lengths (k already is bits in shortest code) */
+ for (; k <= g; k++)
+ {
+ a = c[k];
+ while (a--)
+ {
+ /* here i is the Huffman code of length k bits for value *p */
+ /* make tables up to required level */
+ while (k > w + l)
+ {
+ h++;
+ w += l; /* previous table always l bits */
+
+ /* compute minimum size table less than or equal to l bits */
+ z = (z = g - w) > (uInt)l ? l : z; /* table size upper limit */
+ if ((f = 1 << (j = k - w)) > a + 1) /* try a k-w bit table */
+ { /* too few codes for k-w bit table */
+ f -= a + 1; /* deduct codes from patterns left */
+ xp = c + k;
+ if (j < z)
+ while (++j < z) /* try smaller tables up to z bits */
+ {
+ if ((f <<= 1) <= *++xp)
+ break; /* enough codes to use up j bits */
+ f -= *xp; /* else deduct codes from patterns */
+ }
+ }
+ z = 1 << j; /* table entries for j-bit table */
+
+ /* allocate and link in new table */
+ if ((q = (inflate_huft *)ZALLOC
+ (zs,z + 1,sizeof(inflate_huft))) == Z_NULL)
+ {
+ if (h)
+ inflate_trees_free(u[0], zs);
+ return Z_MEM_ERROR; /* not enough memory */
+ }
+ q->word.Nalloc = z + 1;
+#ifdef DEBUG_ZLIB
+ inflate_hufts += z + 1;
+#endif
+ *t = q + 1; /* link to list for huft_free() */
+ *(t = &(q->next)) = Z_NULL;
+ u[h] = ++q; /* table starts after link */
+
+ /* connect to last table, if there is one */
+ if (h)
+ {
+ x[h] = i; /* save pattern for backing up */
+ r.bits = (Byte)l; /* bits to dump before this table */
+ r.exop = (Byte)j; /* bits in this table */
+ r.next = q; /* pointer to this table */
+ j = i >> (w - l); /* (get around Turbo C bug) */
+ u[h-1][j] = r; /* connect to last table */
+ }
+ }
+
+ /* set up table entry in r */
+ r.bits = (Byte)(k - w);
+ if (p >= v + n)
+ r.exop = 128 + 64; /* out of values--invalid code */
+ else if (*p < s)
+ {
+ r.exop = (Byte)(*p < 256 ? 0 : 32 + 64); /* 256 is end-of-block */
+ r.base = *p++; /* simple code is just the value */
+ }
+ else
+ {
+ r.exop = (Byte)e[*p - s] + 16 + 64; /* non-simple--look up in lists */
+ r.base = d[*p++ - s];
+ }
+
+ /* fill code-like entries with r */
+ f = 1 << (k - w);
+ for (j = i >> w; j < z; j += f)
+ q[j] = r;
+
+ /* backwards increment the k-bit code i */
+ for (j = 1 << (k - 1); i & j; j >>= 1)
+ i ^= j;
+ i ^= j;
+
+ /* backup over finished tables */
+ while ((i & ((1 << w) - 1)) != x[h])
+ {
+ h--; /* don't need to update q */
+ w -= l;
+ }
+ }
+ }
+
+
+ /* Return Z_BUF_ERROR if we were given an incomplete table */
+ return y != 0 && g != 1 ? Z_BUF_ERROR : Z_OK;
+}
+
+
+local int inflate_trees_bits(c, bb, tb, z)
+uIntf *c; /* 19 code lengths */
+uIntf *bb; /* bits tree desired/actual depth */
+inflate_huft * FAR *tb; /* bits tree result */
+z_stream *z; /* for zfree function */
+{
+ int r;
+
+ r = huft_build(c, 19, 19, (uIntf*)Z_NULL, (uIntf*)Z_NULL, tb, bb, z);
+ if (r == Z_DATA_ERROR)
+ z->msg = "oversubscribed dynamic bit lengths tree";
+ else if (r == Z_BUF_ERROR)
+ {
+ inflate_trees_free(*tb, z);
+ z->msg = "incomplete dynamic bit lengths tree";
+ r = Z_DATA_ERROR;
+ }
+ return r;
+}
+
+
+local int inflate_trees_dynamic(nl, nd, c, bl, bd, tl, td, z)
+uInt nl; /* number of literal/length codes */
+uInt nd; /* number of distance codes */
+uIntf *c; /* that many (total) code lengths */
+uIntf *bl; /* literal desired/actual bit depth */
+uIntf *bd; /* distance desired/actual bit depth */
+inflate_huft * FAR *tl; /* literal/length tree result */
+inflate_huft * FAR *td; /* distance tree result */
+z_stream *z; /* for zfree function */
+{
+ int r;
+
+ /* build literal/length tree */
+ if ((r = huft_build(c, nl, 257, cplens, cplext, tl, bl, z)) != Z_OK)
+ {
+ if (r == Z_DATA_ERROR)
+ z->msg = "oversubscribed literal/length tree";
+ else if (r == Z_BUF_ERROR)
+ {
+ inflate_trees_free(*tl, z);
+ z->msg = "incomplete literal/length tree";
+ r = Z_DATA_ERROR;
+ }
+ return r;
+ }
+
+ /* build distance tree */
+ if ((r = huft_build(c + nl, nd, 0, cpdist, cpdext, td, bd, z)) != Z_OK)
+ {
+ if (r == Z_DATA_ERROR)
+ z->msg = "oversubscribed literal/length tree";
+ else if (r == Z_BUF_ERROR) {
+#ifdef PKZIP_BUG_WORKAROUND
+ r = Z_OK;
+ }
+#else
+ inflate_trees_free(*td, z);
+ z->msg = "incomplete literal/length tree";
+ r = Z_DATA_ERROR;
+ }
+ inflate_trees_free(*tl, z);
+ return r;
+#endif
+ }
+
+ /* done */
+ return Z_OK;
+}
+
+
+/* build fixed tables only once--keep them here */
+local int fixed_lock = 0;
+local int fixed_built = 0;
+#define FIXEDH 530 /* number of hufts used by fixed tables */
+local uInt fixed_left = FIXEDH;
+local inflate_huft fixed_mem[FIXEDH];
+local uInt fixed_bl;
+local uInt fixed_bd;
+local inflate_huft *fixed_tl;
+local inflate_huft *fixed_td;
+
+
+local voidpf falloc(q, n, s)
+voidpf q; /* opaque pointer (not used) */
+uInt n; /* number of items */
+uInt s; /* size of item */
+{
+ Assert(s == sizeof(inflate_huft) && n <= fixed_left,
+ "inflate_trees falloc overflow");
+ if (q) s++; /* to make some compilers happy */
+ fixed_left -= n;
+ return (voidpf)(fixed_mem + fixed_left);
+}
+
+
+local void ffree(q, p, n)
+voidpf q;
+voidpf p;
+uInt n;
+{
+ Assert(0, "inflate_trees ffree called!");
+ if (q) q = p; /* to make some compilers happy */
+}
+
+
+local int inflate_trees_fixed(bl, bd, tl, td)
+uIntf *bl; /* literal desired/actual bit depth */
+uIntf *bd; /* distance desired/actual bit depth */
+inflate_huft * FAR *tl; /* literal/length tree result */
+inflate_huft * FAR *td; /* distance tree result */
+{
+ /* build fixed tables if not built already--lock out other instances */
+ while (++fixed_lock > 1)
+ fixed_lock--;
+ if (!fixed_built)
+ {
+ int k; /* temporary variable */
+ unsigned c[288]; /* length list for huft_build */
+ z_stream z; /* for falloc function */
+
+ /* set up fake z_stream for memory routines */
+ z.zalloc = falloc;
+ z.zfree = ffree;
+ z.opaque = Z_NULL;
+
+ /* literal table */
+ for (k = 0; k < 144; k++)
+ c[k] = 8;
+ for (; k < 256; k++)
+ c[k] = 9;
+ for (; k < 280; k++)
+ c[k] = 7;
+ for (; k < 288; k++)
+ c[k] = 8;
+ fixed_bl = 7;
+ huft_build(c, 288, 257, cplens, cplext, &fixed_tl, &fixed_bl, &z);
+
+ /* distance table */
+ for (k = 0; k < 30; k++)
+ c[k] = 5;
+ fixed_bd = 5;
+ huft_build(c, 30, 0, cpdist, cpdext, &fixed_td, &fixed_bd, &z);
+
+ /* done */
+ fixed_built = 1;
+ }
+ fixed_lock--;
+ *bl = fixed_bl;
+ *bd = fixed_bd;
+ *tl = fixed_tl;
+ *td = fixed_td;
+ return Z_OK;
+}
+
+
+local int inflate_trees_free(t, z)
+inflate_huft *t; /* table to free */
+z_stream *z; /* for zfree function */
+/* Free the malloc'ed tables built by huft_build(), which makes a linked
+ list of the tables it made, with the links in a dummy first entry of
+ each table. */
+{
+ register inflate_huft *p, *q;
+
+ /* Go through linked list, freeing from the malloced (t[-1]) address. */
+ p = t;
+ while (p != Z_NULL)
+ {
+ q = (--p)->next;
+ ZFREE(z, p, p->word.Nalloc * sizeof(inflate_huft));
+ p = q;
+ }
+ return Z_OK;
+}
+
+/*+++++*/
+/* infcodes.c -- process literals and length/distance pairs
+ * Copyright (C) 1995 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* simplify the use of the inflate_huft type with some defines */
+#define base more.Base
+#define next more.Next
+#define exop word.what.Exop
+#define bits word.what.Bits
+
+/* inflate codes private state */
+struct inflate_codes_state {
+
+ /* mode */
+ enum { /* waiting for "i:"=input, "o:"=output, "x:"=nothing */
+ START, /* x: set up for LEN */
+ LEN, /* i: get length/literal/eob next */
+ LENEXT, /* i: getting length extra (have base) */
+ DIST, /* i: get distance next */
+ DISTEXT, /* i: getting distance extra */
+ COPY, /* o: copying bytes in window, waiting for space */
+ LIT, /* o: got literal, waiting for output space */
+ WASH, /* o: got eob, possibly still output waiting */
+ END, /* x: got eob and all data flushed */
+ BADCODE} /* x: got error */
+ mode; /* current inflate_codes mode */
+
+ /* mode dependent information */
+ uInt len;
+ union {
+ struct {
+ inflate_huft *tree; /* pointer into tree */
+ uInt need; /* bits needed */
+ } code; /* if LEN or DIST, where in tree */
+ uInt lit; /* if LIT, literal */
+ struct {
+ uInt get; /* bits to get for extra */
+ uInt dist; /* distance back to copy from */
+ } copy; /* if EXT or COPY, where and how much */
+ } sub; /* submode */
+
+ /* mode independent information */
+ Byte lbits; /* ltree bits decoded per branch */
+ Byte dbits; /* dtree bits decoder per branch */
+ inflate_huft *ltree; /* literal/length/eob tree */
+ inflate_huft *dtree; /* distance tree */
+
+};
+
+
+local inflate_codes_statef *inflate_codes_new(bl, bd, tl, td, z)
+uInt bl, bd;
+inflate_huft *tl, *td;
+z_stream *z;
+{
+ inflate_codes_statef *c;
+
+ if ((c = (inflate_codes_statef *)
+ ZALLOC(z,1,sizeof(struct inflate_codes_state))) != Z_NULL)
+ {
+ c->mode = START;
+ c->lbits = (Byte)bl;
+ c->dbits = (Byte)bd;
+ c->ltree = tl;
+ c->dtree = td;
+ Tracev((stderr, "inflate: codes new\n"));
+ }
+ return c;
+}
+
+
+local int inflate_codes(s, z, r)
+inflate_blocks_statef *s;
+z_stream *z;
+int r;
+{
+ uInt j; /* temporary storage */
+ inflate_huft *t; /* temporary pointer */
+ uInt e; /* extra bits or operation */
+ uLong b; /* bit buffer */
+ uInt k; /* bits in bit buffer */
+ Bytef *p; /* input data pointer */
+ uInt n; /* bytes available there */
+ Bytef *q; /* output window write pointer */
+ uInt m; /* bytes to end of window or read pointer */
+ Bytef *f; /* pointer to copy strings from */
+ inflate_codes_statef *c = s->sub.decode.codes; /* codes state */
+
+ /* copy input/output information to locals (UPDATE macro restores) */
+ LOAD
+
+ /* process input and output based on current state */
+ while (1) switch (c->mode)
+ { /* waiting for "i:"=input, "o:"=output, "x:"=nothing */
+ case START: /* x: set up for LEN */
+#ifndef SLOW
+ if (m >= 258 && n >= 10)
+ {
+ UPDATE
+ r = inflate_fast(c->lbits, c->dbits, c->ltree, c->dtree, s, z);
+ LOAD
+ if (r != Z_OK)
+ {
+ c->mode = r == Z_STREAM_END ? WASH : BADCODE;
+ break;
+ }
+ }
+#endif /* !SLOW */
+ c->sub.code.need = c->lbits;
+ c->sub.code.tree = c->ltree;
+ c->mode = LEN;
+ case LEN: /* i: get length/literal/eob next */
+ j = c->sub.code.need;
+ NEEDBITS(j)
+ t = c->sub.code.tree + ((uInt)b & inflate_mask[j]);
+ DUMPBITS(t->bits)
+ e = (uInt)(t->exop);
+ if (e == 0) /* literal */
+ {
+ c->sub.lit = t->base;
+ Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ?
+ "inflate: literal '%c'\n" :
+ "inflate: literal 0x%02x\n", t->base));
+ c->mode = LIT;
+ break;
+ }
+ if (e & 16) /* length */
+ {
+ c->sub.copy.get = e & 15;
+ c->len = t->base;
+ c->mode = LENEXT;
+ break;
+ }
+ if ((e & 64) == 0) /* next table */
+ {
+ c->sub.code.need = e;
+ c->sub.code.tree = t->next;
+ break;
+ }
+ if (e & 32) /* end of block */
+ {
+ Tracevv((stderr, "inflate: end of block\n"));
+ c->mode = WASH;
+ break;
+ }
+ c->mode = BADCODE; /* invalid code */
+ z->msg = "invalid literal/length code";
+ r = Z_DATA_ERROR;
+ LEAVE
+ case LENEXT: /* i: getting length extra (have base) */
+ j = c->sub.copy.get;
+ NEEDBITS(j)
+ c->len += (uInt)b & inflate_mask[j];
+ DUMPBITS(j)
+ c->sub.code.need = c->dbits;
+ c->sub.code.tree = c->dtree;
+ Tracevv((stderr, "inflate: length %u\n", c->len));
+ c->mode = DIST;
+ case DIST: /* i: get distance next */
+ j = c->sub.code.need;
+ NEEDBITS(j)
+ t = c->sub.code.tree + ((uInt)b & inflate_mask[j]);
+ DUMPBITS(t->bits)
+ e = (uInt)(t->exop);
+ if (e & 16) /* distance */
+ {
+ c->sub.copy.get = e & 15;
+ c->sub.copy.dist = t->base;
+ c->mode = DISTEXT;
+ break;
+ }
+ if ((e & 64) == 0) /* next table */
+ {
+ c->sub.code.need = e;
+ c->sub.code.tree = t->next;
+ break;
+ }
+ c->mode = BADCODE; /* invalid code */
+ z->msg = "invalid distance code";
+ r = Z_DATA_ERROR;
+ LEAVE
+ case DISTEXT: /* i: getting distance extra */
+ j = c->sub.copy.get;
+ NEEDBITS(j)
+ c->sub.copy.dist += (uInt)b & inflate_mask[j];
+ DUMPBITS(j)
+ Tracevv((stderr, "inflate: distance %u\n", c->sub.copy.dist));
+ c->mode = COPY;
+ case COPY: /* o: copying bytes in window, waiting for space */
+#ifndef __TURBOC__ /* Turbo C bug for following expression */
+ f = (uInt)(q - s->window) < c->sub.copy.dist ?
+ s->end - (c->sub.copy.dist - (q - s->window)) :
+ q - c->sub.copy.dist;
+#else
+ f = q - c->sub.copy.dist;
+ if ((uInt)(q - s->window) < c->sub.copy.dist)
+ f = s->end - (c->sub.copy.dist - (q - s->window));
+#endif
+ while (c->len)
+ {
+ NEEDOUT
+ OUTBYTE(*f++)
+ if (f == s->end)
+ f = s->window;
+ c->len--;
+ }
+ c->mode = START;
+ break;
+ case LIT: /* o: got literal, waiting for output space */
+ NEEDOUT
+ OUTBYTE(c->sub.lit)
+ c->mode = START;
+ break;
+ case WASH: /* o: got eob, possibly more output */
+ FLUSH
+ if (s->read != s->write)
+ LEAVE
+ c->mode = END;
+ case END:
+ r = Z_STREAM_END;
+ LEAVE
+ case BADCODE: /* x: got error */
+ r = Z_DATA_ERROR;
+ LEAVE
+ default:
+ r = Z_STREAM_ERROR;
+ LEAVE
+ }
+}
+
+
+local void inflate_codes_free(c, z)
+inflate_codes_statef *c;
+z_stream *z;
+{
+ ZFREE(z, c, sizeof(struct inflate_codes_state));
+ Tracev((stderr, "inflate: codes free\n"));
+}
+
+/*+++++*/
+/* inflate_util.c -- data and routines common to blocks and codes
+ * Copyright (C) 1995 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* copy as much as possible from the sliding window to the output area */
+local int inflate_flush(s, z, r)
+inflate_blocks_statef *s;
+z_stream *z;
+int r;
+{
+ uInt n;
+ Bytef *p, *q;
+
+ /* local copies of source and destination pointers */
+ p = z->next_out;
+ q = s->read;
+
+ /* compute number of bytes to copy as far as end of window */
+ n = (uInt)((q <= s->write ? s->write : s->end) - q);
+ if (n > z->avail_out) n = z->avail_out;
+ if (n && r == Z_BUF_ERROR) r = Z_OK;
+
+ /* update counters */
+ z->avail_out -= n;
+ z->total_out += n;
+
+ /* update check information */
+ if (s->checkfn != Z_NULL)
+ s->check = (*s->checkfn)(s->check, q, n);
+
+ /* copy as far as end of window */
+ if (p != NULL) {
+ zmemcpy(p, q, n);
+ p += n;
+ }
+ q += n;
+
+ /* see if more to copy at beginning of window */
+ if (q == s->end)
+ {
+ /* wrap pointers */
+ q = s->window;
+ if (s->write == s->end)
+ s->write = s->window;
+
+ /* compute bytes to copy */
+ n = (uInt)(s->write - q);
+ if (n > z->avail_out) n = z->avail_out;
+ if (n && r == Z_BUF_ERROR) r = Z_OK;
+
+ /* update counters */
+ z->avail_out -= n;
+ z->total_out += n;
+
+ /* update check information */
+ if (s->checkfn != Z_NULL)
+ s->check = (*s->checkfn)(s->check, q, n);
+
+ /* copy */
+ if (p != NULL) {
+ zmemcpy(p, q, n);
+ p += n;
+ }
+ q += n;
+ }
+
+ /* update pointers */
+ z->next_out = p;
+ s->read = q;
+
+ /* done */
+ return r;
+}
+
+
+/*+++++*/
+/* inffast.c -- process literals and length/distance pairs fast
+ * Copyright (C) 1995 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* simplify the use of the inflate_huft type with some defines */
+#define base more.Base
+#define next more.Next
+#define exop word.what.Exop
+#define bits word.what.Bits
+
+/* macros for bit input with no checking and for returning unused bytes */
+#define GRABBITS(j) {while(k<(j)){b|=((uLong)NEXTBYTE)<<k;k+=8;}}
+#define UNGRAB {n+=(c=k>>3);p-=c;k&=7;}
+
+/* Called with number of bytes left to write in window at least 258
+ (the maximum string length) and number of input bytes available
+ at least ten. The ten bytes are six bytes for the longest length/
+ distance pair plus four bytes for overloading the bit buffer. */
+
+local int inflate_fast(bl, bd, tl, td, s, z)
+uInt bl, bd;
+inflate_huft *tl, *td;
+inflate_blocks_statef *s;
+z_stream *z;
+{
+ inflate_huft *t; /* temporary pointer */
+ uInt e; /* extra bits or operation */
+ uLong b; /* bit buffer */
+ uInt k; /* bits in bit buffer */
+ Bytef *p; /* input data pointer */
+ uInt n; /* bytes available there */
+ Bytef *q; /* output window write pointer */
+ uInt m; /* bytes to end of window or read pointer */
+ uInt ml; /* mask for literal/length tree */
+ uInt md; /* mask for distance tree */
+ uInt c; /* bytes to copy */
+ uInt d; /* distance back to copy from */
+ Bytef *r; /* copy source pointer */
+
+ /* load input, output, bit values */
+ LOAD
+
+ /* initialize masks */
+ ml = inflate_mask[bl];
+ md = inflate_mask[bd];
+
+ /* do until not enough input or output space for fast loop */
+ do { /* assume called with m >= 258 && n >= 10 */
+ /* get literal/length code */
+ GRABBITS(20) /* max bits for literal/length code */
+ if ((e = (t = tl + ((uInt)b & ml))->exop) == 0)
+ {
+ DUMPBITS(t->bits)
+ Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ?
+ "inflate: * literal '%c'\n" :
+ "inflate: * literal 0x%02x\n", t->base));
+ *q++ = (Byte)t->base;
+ m--;
+ continue;
+ }
+ do {
+ DUMPBITS(t->bits)
+ if (e & 16)
+ {
+ /* get extra bits for length */
+ e &= 15;
+ c = t->base + ((uInt)b & inflate_mask[e]);
+ DUMPBITS(e)
+ Tracevv((stderr, "inflate: * length %u\n", c));
+
+ /* decode distance base of block to copy */
+ GRABBITS(15); /* max bits for distance code */
+ e = (t = td + ((uInt)b & md))->exop;
+ do {
+ DUMPBITS(t->bits)
+ if (e & 16)
+ {
+ /* get extra bits to add to distance base */
+ e &= 15;
+ GRABBITS(e) /* get extra bits (up to 13) */
+ d = t->base + ((uInt)b & inflate_mask[e]);
+ DUMPBITS(e)
+ Tracevv((stderr, "inflate: * distance %u\n", d));
+
+ /* do the copy */
+ m -= c;
+ if ((uInt)(q - s->window) >= d) /* offset before dest */
+ { /* just copy */
+ r = q - d;
+ *q++ = *r++; c--; /* minimum count is three, */
+ *q++ = *r++; c--; /* so unroll loop a little */
+ }
+ else /* else offset after destination */
+ {
+ e = d - (q - s->window); /* bytes from offset to end */
+ r = s->end - e; /* pointer to offset */
+ if (c > e) /* if source crosses, */
+ {
+ c -= e; /* copy to end of window */
+ do {
+ *q++ = *r++;
+ } while (--e);
+ r = s->window; /* copy rest from start of window */
+ }
+ }
+ do { /* copy all or what's left */
+ *q++ = *r++;
+ } while (--c);
+ break;
+ }
+ else if ((e & 64) == 0)
+ e = (t = t->next + ((uInt)b & inflate_mask[e]))->exop;
+ else
+ {
+ z->msg = "invalid distance code";
+ UNGRAB
+ UPDATE
+ return Z_DATA_ERROR;
+ }
+ } while (1);
+ break;
+ }
+ if ((e & 64) == 0)
+ {
+ if ((e = (t = t->next + ((uInt)b & inflate_mask[e]))->exop) == 0)
+ {
+ DUMPBITS(t->bits)
+ Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ?
+ "inflate: * literal '%c'\n" :
+ "inflate: * literal 0x%02x\n", t->base));
+ *q++ = (Byte)t->base;
+ m--;
+ break;
+ }
+ }
+ else if (e & 32)
+ {
+ Tracevv((stderr, "inflate: * end of block\n"));
+ UNGRAB
+ UPDATE
+ return Z_STREAM_END;
+ }
+ else
+ {
+ z->msg = "invalid literal/length code";
+ UNGRAB
+ UPDATE
+ return Z_DATA_ERROR;
+ }
+ } while (1);
+ } while (m >= 258 && n >= 10);
+
+ /* not enough input or output--restore pointers and return */
+ UNGRAB
+ UPDATE
+ return Z_OK;
+}
+
+
+/*+++++*/
+/* zutil.c -- target dependent utility functions for the compression library
+ * Copyright (C) 1995 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* From: zutil.c,v 1.8 1995/05/03 17:27:12 jloup Exp */
+
+char *zlib_version = ZLIB_VERSION;
+
+char *z_errmsg[] = {
+"stream end", /* Z_STREAM_END 1 */
+"", /* Z_OK 0 */
+"file error", /* Z_ERRNO (-1) */
+"stream error", /* Z_STREAM_ERROR (-2) */
+"data error", /* Z_DATA_ERROR (-3) */
+"insufficient memory", /* Z_MEM_ERROR (-4) */
+"buffer error", /* Z_BUF_ERROR (-5) */
+""};
+
+
+/*+++++*/
+/* adler32.c -- compute the Adler-32 checksum of a data stream
+ * Copyright (C) 1995 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* From: adler32.c,v 1.6 1995/05/03 17:27:08 jloup Exp */
+
+#define BASE 65521L /* largest prime smaller than 65536 */
+#define NMAX 5552
+/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
+
+#define DO1(buf) {s1 += *buf++; s2 += s1;}
+#define DO2(buf) DO1(buf); DO1(buf);
+#define DO4(buf) DO2(buf); DO2(buf);
+#define DO8(buf) DO4(buf); DO4(buf);
+#define DO16(buf) DO8(buf); DO8(buf);
+
+/* ========================================================================= */
+uLong adler32(adler, buf, len)
+ uLong adler;
+ Bytef *buf;
+ uInt len;
+{
+ unsigned long s1 = adler & 0xffff;
+ unsigned long s2 = (adler >> 16) & 0xffff;
+ int k;
+
+ if (buf == Z_NULL) return 1L;
+
+ while (len > 0) {
+ k = len < NMAX ? len : NMAX;
+ len -= k;
+ while (k >= 16) {
+ DO16(buf);
+ k -= 16;
+ }
+ if (k != 0) do {
+ DO1(buf);
+ } while (--k);
+ s1 %= BASE;
+ s2 %= BASE;
+ }
+ return (s2 << 16) | s1;
+}
diff --git a/mdk-stage1/ppp/pppdump/zlib.h b/mdk-stage1/ppp/pppdump/zlib.h
new file mode 100644
index 000000000..b4a7d91a9
--- /dev/null
+++ b/mdk-stage1/ppp/pppdump/zlib.h
@@ -0,0 +1,631 @@
+/* $Id: zlib.h 195720 2001-06-11 11:44:34Z gc $ */
+
+/*
+ * This file is derived from zlib.h and zconf.h from the zlib-0.95
+ * distribution by Jean-loup Gailly and Mark Adler, with some additions
+ * by Paul Mackerras to aid in implementing Deflate compression and
+ * decompression for PPP packets.
+ */
+
+/* zlib.h -- interface of the 'zlib' general purpose compression library
+ version 0.95, Aug 16th, 1995.
+
+ Copyright (C) 1995 Jean-loup Gailly and Mark Adler
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Jean-loup Gailly Mark Adler
+ gzip@prep.ai.mit.edu madler@alumni.caltech.edu
+ */
+
+#ifndef _ZLIB_H
+#define _ZLIB_H
+
+/* #include "zconf.h" */ /* included directly here */
+
+/* zconf.h -- configuration of the zlib compression library
+ * Copyright (C) 1995 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* From: zconf.h,v 1.12 1995/05/03 17:27:12 jloup Exp */
+
+/*
+ The library does not install any signal handler. It is recommended to
+ add at least a handler for SIGSEGV when decompressing; the library checks
+ the consistency of the input data whenever possible but may go nuts
+ for some forms of corrupted input.
+ */
+
+/*
+ * Compile with -DMAXSEG_64K if the alloc function cannot allocate more
+ * than 64k bytes at a time (needed on systems with 16-bit int).
+ * Compile with -DUNALIGNED_OK if it is OK to access shorts or ints
+ * at addresses which are not a multiple of their size.
+ * Under DOS, -DFAR=far or -DFAR=__far may be needed.
+ */
+
+#ifndef STDC
+# if defined(MSDOS) || defined(__STDC__) || defined(__cplusplus)
+# define STDC
+# endif
+#endif
+
+#ifdef __MWERKS__ /* Metrowerks CodeWarrior declares fileno() in unix.h */
+# include <unix.h>
+#endif
+
+/* Maximum value for memLevel in deflateInit2 */
+#ifndef MAX_MEM_LEVEL
+# ifdef MAXSEG_64K
+# define MAX_MEM_LEVEL 8
+# else
+# define MAX_MEM_LEVEL 9
+# endif
+#endif
+
+#ifndef FAR
+# define FAR
+#endif
+
+/* Maximum value for windowBits in deflateInit2 and inflateInit2 */
+#ifndef MAX_WBITS
+# define MAX_WBITS 15 /* 32K LZ77 window */
+#endif
+
+/* The memory requirements for deflate are (in bytes):
+ 1 << (windowBits+2) + 1 << (memLevel+9)
+ that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values)
+ plus a few kilobytes for small objects. For example, if you want to reduce
+ the default memory requirements from 256K to 128K, compile with
+ make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7"
+ Of course this will generally degrade compression (there's no free lunch).
+
+ The memory requirements for inflate are (in bytes) 1 << windowBits
+ that is, 32K for windowBits=15 (default value) plus a few kilobytes
+ for small objects.
+*/
+
+ /* Type declarations */
+
+#ifndef OF /* function prototypes */
+# ifdef STDC
+# define OF(args) args
+# else
+# define OF(args) ()
+# endif
+#endif
+
+typedef unsigned char Byte; /* 8 bits */
+typedef unsigned int uInt; /* 16 bits or more */
+typedef unsigned long uLong; /* 32 bits or more */
+
+typedef Byte FAR Bytef;
+typedef char FAR charf;
+typedef int FAR intf;
+typedef uInt FAR uIntf;
+typedef uLong FAR uLongf;
+
+#ifdef STDC
+ typedef void FAR *voidpf;
+ typedef void *voidp;
+#else
+ typedef Byte FAR *voidpf;
+ typedef Byte *voidp;
+#endif
+
+/* end of original zconf.h */
+
+#define ZLIB_VERSION "0.95P"
+
+/*
+ The 'zlib' compression library provides in-memory compression and
+ decompression functions, including integrity checks of the uncompressed
+ data. This version of the library supports only one compression method
+ (deflation) but other algorithms may be added later and will have the same
+ stream interface.
+
+ For compression the application must provide the output buffer and
+ may optionally provide the input buffer for optimization. For decompression,
+ the application must provide the input buffer and may optionally provide
+ the output buffer for optimization.
+
+ Compression can be done in a single step if the buffers are large
+ enough (for example if an input file is mmap'ed), or can be done by
+ repeated calls of the compression function. In the latter case, the
+ application must provide more input and/or consume the output
+ (providing more output space) before each call.
+*/
+
+typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size));
+typedef void (*free_func) OF((voidpf opaque, voidpf address, uInt nbytes));
+
+struct internal_state;
+
+typedef struct z_stream_s {
+ Bytef *next_in; /* next input byte */
+ uInt avail_in; /* number of bytes available at next_in */
+ uLong total_in; /* total nb of input bytes read so far */
+
+ Bytef *next_out; /* next output byte should be put there */
+ uInt avail_out; /* remaining free space at next_out */
+ uLong total_out; /* total nb of bytes output so far */
+
+ char *msg; /* last error message, NULL if no error */
+ struct internal_state FAR *state; /* not visible by applications */
+
+ alloc_func zalloc; /* used to allocate the internal state */
+ free_func zfree; /* used to free the internal state */
+ voidp opaque; /* private data object passed to zalloc and zfree */
+
+ Byte data_type; /* best guess about the data type: ascii or binary */
+
+} z_stream;
+
+/*
+ The application must update next_in and avail_in when avail_in has
+ dropped to zero. It must update next_out and avail_out when avail_out
+ has dropped to zero. The application must initialize zalloc, zfree and
+ opaque before calling the init function. All other fields are set by the
+ compression library and must not be updated by the application.
+
+ The opaque value provided by the application will be passed as the first
+ parameter for calls of zalloc and zfree. This can be useful for custom
+ memory management. The compression library attaches no meaning to the
+ opaque value.
+
+ zalloc must return Z_NULL if there is not enough memory for the object.
+ On 16-bit systems, the functions zalloc and zfree must be able to allocate
+ exactly 65536 bytes, but will not be required to allocate more than this
+ if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS,
+ pointers returned by zalloc for objects of exactly 65536 bytes *must*
+ have their offset normalized to zero. The default allocation function
+ provided by this library ensures this (see zutil.c). To reduce memory
+ requirements and avoid any allocation of 64K objects, at the expense of
+ compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h).
+
+ The fields total_in and total_out can be used for statistics or
+ progress reports. After compression, total_in holds the total size of
+ the uncompressed data and may be saved for use in the decompressor
+ (particularly if the decompressor wants to decompress everything in
+ a single step).
+*/
+
+ /* constants */
+
+#define Z_NO_FLUSH 0
+#define Z_PARTIAL_FLUSH 1
+#define Z_FULL_FLUSH 2
+#define Z_SYNC_FLUSH 3 /* experimental: partial_flush + byte align */
+#define Z_FINISH 4
+#define Z_PACKET_FLUSH 5
+/* See deflate() below for the usage of these constants */
+
+#define Z_OK 0
+#define Z_STREAM_END 1
+#define Z_ERRNO (-1)
+#define Z_STREAM_ERROR (-2)
+#define Z_DATA_ERROR (-3)
+#define Z_MEM_ERROR (-4)
+#define Z_BUF_ERROR (-5)
+/* error codes for the compression/decompression functions */
+
+#define Z_BEST_SPEED 1
+#define Z_BEST_COMPRESSION 9
+#define Z_DEFAULT_COMPRESSION (-1)
+/* compression levels */
+
+#define Z_FILTERED 1
+#define Z_HUFFMAN_ONLY 2
+#define Z_DEFAULT_STRATEGY 0
+
+#define Z_BINARY 0
+#define Z_ASCII 1
+#define Z_UNKNOWN 2
+/* Used to set the data_type field */
+
+#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */
+
+extern char *zlib_version;
+/* The application can compare zlib_version and ZLIB_VERSION for consistency.
+ If the first character differs, the library code actually used is
+ not compatible with the zlib.h header file used by the application.
+ */
+
+ /* basic functions */
+
+extern int deflateInit OF((z_stream *strm, int level));
+/*
+ Initializes the internal stream state for compression. The fields
+ zalloc, zfree and opaque must be initialized before by the caller.
+ If zalloc and zfree are set to Z_NULL, deflateInit updates them to
+ use default allocation functions.
+
+ The compression level must be Z_DEFAULT_COMPRESSION, or between 1 and 9:
+ 1 gives best speed, 9 gives best compression. Z_DEFAULT_COMPRESSION requests
+ a default compromise between speed and compression (currently equivalent
+ to level 6).
+
+ deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_STREAM_ERROR if level is not a valid compression level.
+ msg is set to null if there is no error message. deflateInit does not
+ perform any compression: this will be done by deflate().
+*/
+
+
+extern int deflate OF((z_stream *strm, int flush));
+/*
+ Performs one or both of the following actions:
+
+ - Compress more input starting at next_in and update next_in and avail_in
+ accordingly. If not all input can be processed (because there is not
+ enough room in the output buffer), next_in and avail_in are updated and
+ processing will resume at this point for the next call of deflate().
+
+ - Provide more output starting at next_out and update next_out and avail_out
+ accordingly. This action is forced if the parameter flush is non zero.
+ Forcing flush frequently degrades the compression ratio, so this parameter
+ should be set only when necessary (in interactive applications).
+ Some output may be provided even if flush is not set.
+
+ Before the call of deflate(), the application should ensure that at least
+ one of the actions is possible, by providing more input and/or consuming
+ more output, and updating avail_in or avail_out accordingly; avail_out
+ should never be zero before the call. The application can consume the
+ compressed output when it wants, for example when the output buffer is full
+ (avail_out == 0), or after each call of deflate().
+
+ If the parameter flush is set to Z_PARTIAL_FLUSH, the current compression
+ block is terminated and flushed to the output buffer so that the
+ decompressor can get all input data available so far. For method 9, a future
+ variant on method 8, the current block will be flushed but not terminated.
+ If flush is set to Z_FULL_FLUSH, the compression block is terminated, a
+ special marker is output and the compression dictionary is discarded; this
+ is useful to allow the decompressor to synchronize if one compressed block
+ has been damaged (see inflateSync below). Flushing degrades compression and
+ so should be used only when necessary. Using Z_FULL_FLUSH too often can
+ seriously degrade the compression. If deflate returns with avail_out == 0,
+ this function must be called again with the same value of the flush
+ parameter and more output space (updated avail_out), until the flush is
+ complete (deflate returns with non-zero avail_out).
+
+ If the parameter flush is set to Z_PACKET_FLUSH, the compression
+ block is terminated, and a zero-length stored block is output,
+ omitting the length bytes (the effect of this is that the 3-bit type
+ code 000 for a stored block is output, and the output is then
+ byte-aligned). This is designed for use at the end of a PPP packet.
+ In addition, if the current compression block contains all the data
+ since the last Z_PACKET_FLUSH, it is never output as a stored block.
+ If the current compression block output as a static or dynamic block
+ would not be at least `minCompression' bytes smaller than the
+ original data, then nothing is output for that block. (The type
+ code for the zero-length stored block is still output, resulting in
+ a single zero byte being output for the whole packet.)
+ `MinCompression' is a parameter to deflateInit2, or 0 if deflateInit
+ is used.
+
+ If the parameter flush is set to Z_FINISH, all pending input is processed,
+ all pending output is flushed and deflate returns with Z_STREAM_END if there
+ was enough output space; if deflate returns with Z_OK, this function must be
+ called again with Z_FINISH and more output space (updated avail_out) but no
+ more input data, until it returns with Z_STREAM_END or an error. After
+ deflate has returned Z_STREAM_END, the only possible operations on the
+ stream are deflateReset or deflateEnd.
+
+ Z_FINISH can be used immediately after deflateInit if all the compression
+ is to be done in a single step. In this case, avail_out must be at least
+ 0.1% larger than avail_in plus 12 bytes. If deflate does not return
+ Z_STREAM_END, then it must be called again as described above.
+
+ deflate() may update data_type if it can make a good guess about
+ the input data type (Z_ASCII or Z_BINARY). In doubt, the data is considered
+ binary. This field is only for information purposes and does not affect
+ the compression algorithm in any manner.
+
+ deflate() returns Z_OK if some progress has been made (more input
+ processed or more output produced), Z_STREAM_END if all input has been
+ consumed and all output has been produced (only when flush is set to
+ Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example
+ if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible.
+*/
+
+
+extern int deflateEnd OF((z_stream *strm));
+/*
+ All dynamically allocated data structures for this stream are freed.
+ This function discards any unprocessed input and does not flush any
+ pending output.
+
+ deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the
+ stream state was inconsistent. In the error case, msg may be set
+ but then points to a static string (which must not be deallocated).
+*/
+
+
+extern int inflateInit OF((z_stream *strm));
+/*
+ Initializes the internal stream state for decompression. The fields
+ zalloc and zfree must be initialized before by the caller. If zalloc and
+ zfree are set to Z_NULL, inflateInit updates them to use default allocation
+ functions.
+
+ inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory. msg is set to null if there is no error message.
+ inflateInit does not perform any decompression: this will be done by
+ inflate().
+*/
+
+
+extern int inflate OF((z_stream *strm, int flush));
+/*
+ Performs one or both of the following actions:
+
+ - Decompress more input starting at next_in and update next_in and avail_in
+ accordingly. If not all input can be processed (because there is not
+ enough room in the output buffer), next_in is updated and processing
+ will resume at this point for the next call of inflate().
+
+ - Provide more output starting at next_out and update next_out and avail_out
+ accordingly. inflate() always provides as much output as possible
+ (until there is no more input data or no more space in the output buffer).
+
+ Before the call of inflate(), the application should ensure that at least
+ one of the actions is possible, by providing more input and/or consuming
+ more output, and updating the next_* and avail_* values accordingly.
+ The application can consume the uncompressed output when it wants, for
+ example when the output buffer is full (avail_out == 0), or after each
+ call of inflate().
+
+ If the parameter flush is set to Z_PARTIAL_FLUSH or Z_PACKET_FLUSH,
+ inflate flushes as much output as possible to the output buffer. The
+ flushing behavior of inflate is not specified for values of the flush
+ parameter other than Z_PARTIAL_FLUSH, Z_PACKET_FLUSH or Z_FINISH, but the
+ current implementation actually flushes as much output as possible
+ anyway. For Z_PACKET_FLUSH, inflate checks that once all the input data
+ has been consumed, it is expecting to see the length field of a stored
+ block; if not, it returns Z_DATA_ERROR.
+
+ inflate() should normally be called until it returns Z_STREAM_END or an
+ error. However if all decompression is to be performed in a single step
+ (a single call of inflate), the parameter flush should be set to
+ Z_FINISH. In this case all pending input is processed and all pending
+ output is flushed; avail_out must be large enough to hold all the
+ uncompressed data. (The size of the uncompressed data may have been saved
+ by the compressor for this purpose.) The next operation on this stream must
+ be inflateEnd to deallocate the decompression state. The use of Z_FINISH
+ is never required, but can be used to inform inflate that a faster routine
+ may be used for the single inflate() call.
+
+ inflate() returns Z_OK if some progress has been made (more input
+ processed or more output produced), Z_STREAM_END if the end of the
+ compressed data has been reached and all uncompressed output has been
+ produced, Z_DATA_ERROR if the input data was corrupted, Z_STREAM_ERROR if
+ the stream structure was inconsistent (for example if next_in or next_out
+ was NULL), Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if no
+ progress is possible or if there was not enough room in the output buffer
+ when Z_FINISH is used. In the Z_DATA_ERROR case, the application may then
+ call inflateSync to look for a good compression block. */
+
+
+extern int inflateEnd OF((z_stream *strm));
+/*
+ All dynamically allocated data structures for this stream are freed.
+ This function discards any unprocessed input and does not flush any
+ pending output.
+
+ inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state
+ was inconsistent. In the error case, msg may be set but then points to a
+ static string (which must not be deallocated).
+*/
+
+ /* advanced functions */
+
+/*
+ The following functions are needed only in some special applications.
+*/
+
+extern int deflateInit2 OF((z_stream *strm,
+ int level,
+ int method,
+ int windowBits,
+ int memLevel,
+ int strategy,
+ int minCompression));
+/*
+ This is another version of deflateInit with more compression options. The
+ fields next_in, zalloc and zfree must be initialized before by the caller.
+
+ The method parameter is the compression method. It must be 8 in this
+ version of the library. (Method 9 will allow a 64K history buffer and
+ partial block flushes.)
+
+ The windowBits parameter is the base two logarithm of the window size
+ (the size of the history buffer). It should be in the range 8..15 for this
+ version of the library (the value 16 will be allowed for method 9). Larger
+ values of this parameter result in better compression at the expense of
+ memory usage. The default value is 15 if deflateInit is used instead.
+
+ The memLevel parameter specifies how much memory should be allocated
+ for the internal compression state. memLevel=1 uses minimum memory but
+ is slow and reduces compression ratio; memLevel=9 uses maximum memory
+ for optimal speed. The default value is 8. See zconf.h for total memory
+ usage as a function of windowBits and memLevel.
+
+ The strategy parameter is used to tune the compression algorithm. Use
+ the value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data
+ produced by a filter (or predictor), or Z_HUFFMAN_ONLY to force Huffman
+ encoding only (no string match). Filtered data consists mostly of small
+ values with a somewhat random distribution. In this case, the
+ compression algorithm is tuned to compress them better. The strategy
+ parameter only affects the compression ratio but not the correctness of
+ the compressed output even if it is not set appropriately.
+
+ The minCompression parameter specifies the minimum reduction in size
+ required for a compressed block to be output when Z_PACKET_FLUSH is
+ used (see the description of deflate above).
+
+ If next_in is not null, the library will use this buffer to hold also
+ some history information; the buffer must either hold the entire input
+ data, or have at least 1<<(windowBits+1) bytes and be writable. If next_in
+ is null, the library will allocate its own history buffer (and leave next_in
+ null). next_out need not be provided here but must be provided by the
+ application for the next call of deflate().
+
+ If the history buffer is provided by the application, next_in must
+ must never be changed by the application since the compressor maintains
+ information inside this buffer from call to call; the application
+ must provide more input only by increasing avail_in. next_in is always
+ reset by the library in this case.
+
+ deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was
+ not enough memory, Z_STREAM_ERROR if a parameter is invalid (such as
+ an invalid method). msg is set to null if there is no error message.
+ deflateInit2 does not perform any compression: this will be done by
+ deflate().
+*/
+
+extern int deflateCopy OF((z_stream *dest,
+ z_stream *source));
+/*
+ Sets the destination stream as a complete copy of the source stream. If
+ the source stream is using an application-supplied history buffer, a new
+ buffer is allocated for the destination stream. The compressed output
+ buffer is always application-supplied. It's the responsibility of the
+ application to provide the correct values of next_out and avail_out for the
+ next call of deflate.
+
+ This function is useful when several compression strategies will be
+ tried, for example when there are several ways of pre-processing the input
+ data with a filter. The streams that will be discarded should then be freed
+ by calling deflateEnd. Note that deflateCopy duplicates the internal
+ compression state which can be quite large, so this strategy is slow and
+ can consume lots of memory.
+
+ deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
+ (such as zalloc being NULL). msg is left unchanged in both source and
+ destination.
+*/
+
+extern int deflateReset OF((z_stream *strm));
+/*
+ This function is equivalent to deflateEnd followed by deflateInit,
+ but does not free and reallocate all the internal compression state.
+ The stream will keep the same compression level and any other attributes
+ that may have been set by deflateInit2.
+
+ deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent (such as zalloc or state being NULL).
+*/
+
+extern int inflateInit2 OF((z_stream *strm,
+ int windowBits));
+/*
+ This is another version of inflateInit with more compression options. The
+ fields next_out, zalloc and zfree must be initialized before by the caller.
+
+ The windowBits parameter is the base two logarithm of the maximum window
+ size (the size of the history buffer). It should be in the range 8..15 for
+ this version of the library (the value 16 will be allowed soon). The
+ default value is 15 if inflateInit is used instead. If a compressed stream
+ with a larger window size is given as input, inflate() will return with
+ the error code Z_DATA_ERROR instead of trying to allocate a larger window.
+
+ If next_out is not null, the library will use this buffer for the history
+ buffer; the buffer must either be large enough to hold the entire output
+ data, or have at least 1<<windowBits bytes. If next_out is null, the
+ library will allocate its own buffer (and leave next_out null). next_in
+ need not be provided here but must be provided by the application for the
+ next call of inflate().
+
+ If the history buffer is provided by the application, next_out must
+ never be changed by the application since the decompressor maintains
+ history information inside this buffer from call to call; the application
+ can only reset next_out to the beginning of the history buffer when
+ avail_out is zero and all output has been consumed.
+
+ inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was
+ not enough memory, Z_STREAM_ERROR if a parameter is invalid (such as
+ windowBits < 8). msg is set to null if there is no error message.
+ inflateInit2 does not perform any decompression: this will be done by
+ inflate().
+*/
+
+extern int inflateSync OF((z_stream *strm));
+/*
+ Skips invalid compressed data until the special marker (see deflate()
+ above) can be found, or until all available input is skipped. No output
+ is provided.
+
+ inflateSync returns Z_OK if the special marker has been found, Z_BUF_ERROR
+ if no more input was provided, Z_DATA_ERROR if no marker has been found,
+ or Z_STREAM_ERROR if the stream structure was inconsistent. In the success
+ case, the application may save the current current value of total_in which
+ indicates where valid compressed data was found. In the error case, the
+ application may repeatedly call inflateSync, providing more input each time,
+ until success or end of the input data.
+*/
+
+extern int inflateReset OF((z_stream *strm));
+/*
+ This function is equivalent to inflateEnd followed by inflateInit,
+ but does not free and reallocate all the internal decompression state.
+ The stream will keep attributes that may have been set by inflateInit2.
+
+ inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent (such as zalloc or state being NULL).
+*/
+
+extern int inflateIncomp OF((z_stream *strm));
+/*
+ This function adds the data at next_in (avail_in bytes) to the output
+ history without performing any output. There must be no pending output,
+ and the decompressor must be expecting to see the start of a block.
+ Calling this function is equivalent to decompressing a stored block
+ containing the data at next_in (except that the data is not output).
+*/
+
+ /* checksum functions */
+
+/*
+ This function is not related to compression but is exported
+ anyway because it might be useful in applications using the
+ compression library.
+*/
+
+extern uLong adler32 OF((uLong adler, Bytef *buf, uInt len));
+
+/*
+ Update a running Adler-32 checksum with the bytes buf[0..len-1] and
+ return the updated checksum. If buf is NULL, this function returns
+ the required initial value for the checksum.
+ An Adler-32 checksum is almost as reliable as a CRC32 but can be computed
+ much faster. Usage example:
+
+ uLong adler = adler32(0L, Z_NULL, 0);
+
+ while (read_buffer(buffer, length) != EOF) {
+ adler = adler32(adler, buffer, length);
+ }
+ if (adler != original_adler) error();
+*/
+
+#ifndef _Z_UTIL_H
+ struct internal_state {int dummy;}; /* hack for buggy compilers */
+#endif
+
+#endif /* _ZLIB_H */
diff --git a/mdk-stage1/ppp/pppstats/Makefile.linux b/mdk-stage1/ppp/pppstats/Makefile.linux
new file mode 100644
index 000000000..fc9da74a5
--- /dev/null
+++ b/mdk-stage1/ppp/pppstats/Makefile.linux
@@ -0,0 +1,32 @@
+#
+# pppstats makefile
+# $Id: Makefile.linux 195720 2001-06-11 11:44:34Z gc $
+#
+
+PPPSTATSRCS = pppstats.c
+PPPSTATOBJS = pppstats.o
+
+#CC = gcc
+COPTS = -O
+COMPILE_FLAGS = -D_linux_ -I../include
+LIBS =
+
+INSTALL= install -o root -g daemon
+
+CFLAGS = $(COPTS) $(COMPILE_FLAGS)
+
+all: pppstats
+
+install: pppstats
+ $(INSTALL) -s -c pppstats $(BINDIR)/pppstats
+ $(INSTALL) -c -m 444 pppstats.8 $(MANDIR)/man8/pppstats.8
+
+pppstats: $(PPPSTATSRCS)
+ $(CC) $(CFLAGS) -o pppstats pppstats.c $(LIBS)
+
+clean:
+ rm -f pppstats *~ #* core
+
+depend:
+ cpp -M $(CFLAGS) $(PPPSTATSRCS) >.depend
+# makedepend $(CFLAGS) $(PPPSTATSRCS)
diff --git a/mdk-stage1/ppp/pppstats/Makefile.sol2 b/mdk-stage1/ppp/pppstats/Makefile.sol2
new file mode 100644
index 000000000..6ae4c173f
--- /dev/null
+++ b/mdk-stage1/ppp/pppstats/Makefile.sol2
@@ -0,0 +1,20 @@
+#
+# pppstats Makefile for SVR4 systems
+# $Id: Makefile.sol2 195720 2001-06-11 11:44:34Z gc $
+#
+
+include ../solaris/Makedefs
+
+CFLAGS = -DSTREAMS -I../include $(COPTS)
+
+all: pppstats
+
+pppstats: pppstats.c
+ $(CC) $(CFLAGS) -o pppstats pppstats.c
+
+install: pppstats
+ $(INSTALL) -f $(BINDIR) pppstats
+ $(INSTALL) -m 444 -f $(MANDIR)/man8 pppstats.8
+
+clean:
+ rm -f pppstats *~ core
diff --git a/mdk-stage1/ppp/pppstats/Makefile.sunos4 b/mdk-stage1/ppp/pppstats/Makefile.sunos4
new file mode 100644
index 000000000..cfcfca541
--- /dev/null
+++ b/mdk-stage1/ppp/pppstats/Makefile.sunos4
@@ -0,0 +1,30 @@
+#
+# pppstats makefile
+# $Id: Makefile.sunos4 195720 2001-06-11 11:44:34Z gc $
+#
+
+include ../sunos4/Makedefs
+
+PPPSTATSRCS = pppstats.c
+PPPSTATOBJS = pppstats.o
+
+COMPILE_FLAGS = -DSTREAMS -DSUNOS4
+LIBS =
+
+CFLAGS = -I../include $(COPTS) $(COMPILE_FLAGS)
+
+all: pppstats
+
+install: pppstats
+ $(INSTALL) -c pppstats $(BINDIR)/pppstats
+ $(INSTALL) -c -m 444 pppstats.8 $(MANDIR)/man8/pppstats.8
+
+pppstats: $(PPPSTATSRCS)
+ $(CC) $(CFLAGS) -o pppstats pppstats.c $(LIBS)
+
+clean:
+ rm -f pppstats *~ #* core
+
+depend:
+ cpp -M $(CFLAGS) $(PPPSTATSRCS) >.depend
+# makedepend $(CFLAGS) $(PPPSTATSRCS)
diff --git a/mdk-stage1/ppp/pppstats/pppstats.8 b/mdk-stage1/ppp/pppstats/pppstats.8
new file mode 100644
index 000000000..507202eb2
--- /dev/null
+++ b/mdk-stage1/ppp/pppstats/pppstats.8
@@ -0,0 +1,217 @@
+.\" @(#) $Id: pppstats.8 195720 2001-06-11 11:44:34Z gc $
+.TH PPPSTATS 8 "26 June 1995"
+.SH NAME
+pppstats \- print PPP statistics
+.SH SYNOPSIS
+.B pppstats
+[
+.B -a
+] [
+.B -v
+] [
+.B -r
+] [
+.B -z
+] [
+.B -c
+.I <count>
+] [
+.B -w
+.I <secs>
+] [
+.I interface
+]
+.ti 12
+.SH DESCRIPTION
+The
+.B pppstats
+utility reports PPP-related statistics at regular intervals for the
+specified PPP interface. If the interface is unspecified, it will
+default to ppp0.
+The display is split horizontally
+into input and output sections containing columns of statistics
+describing the properties and volume of packets received and
+transmitted by the interface.
+.PP
+The options are as follows:
+.TP
+.B -a
+Display absolute values rather than deltas. With this option, all
+reports show statistics for the time since the link was initiated.
+Without this option, the second and subsequent reports show statistics
+for the time since the last report.
+.TP
+.B -c \fIcount
+Repeat the display
+.I count
+times. If this option is not specified, the default repeat count is 1
+if the
+.B -w
+option is not specified, otherwise infinity.
+.TP
+.B -r
+Display additional statistics summarizing the compression ratio
+achieved by the packet compression algorithm in use.
+.TP
+.B -v
+Display additional statistics relating to the performance of the Van
+Jacobson TCP header compression algorithm.
+.TP
+.B -w \fIwait
+Pause
+.I wait
+seconds between each display. If this option is not specified, the
+default interval is 5 seconds.
+.TP
+.B -z
+Instead of the standard display, show statistics indicating the
+performance of the packet compression algorithm in use.
+.PP
+The following fields are printed on the input side when the
+.B -z
+option is not used:
+.TP
+.B IN
+The total number of bytes received by this interface.
+.TP
+.B PACK
+The total number of packets received by this interface.
+.TP
+.B VJCOMP
+The number of header-compressed TCP packets received by this interface.
+.TP
+.B VJUNC
+The number of header-uncompressed TCP packets received by this
+interface. Not reported when the
+.B -r
+option is specified.
+.TP
+.B VJERR
+The number of corrupted or bogus header-compressed TCP packets
+received by this interface. Not reported when the
+.B -r
+option is specified.
+.TP
+.B VJTOSS
+The number of VJ header-compressed TCP packets dropped on reception by
+this interface because of preceding errors. Only reported when the
+.B -v
+option is specified.
+.TP
+.B NON-VJ
+The total number of non-TCP packets received by this interface. Only
+reported when the
+.B -v
+option is specified.
+.TP
+.B RATIO
+The compression ratio achieved for received packets by the
+packet compression scheme in use, defined as the uncompressed size
+divided by the compressed size.
+Only reported when the
+.B -r
+option is specified.
+.TP
+.B UBYTE
+The total number of bytes received, after decompression of compressed
+packets. Only reported when the
+.B -r
+option is specified.
+.PP
+The following fields are printed on the output side:
+.TP
+.B OUT
+The total number of bytes transmitted from this interface.
+.TP
+.B PACK
+The total number of packets transmitted from this interface.
+.TP
+.B VJCOMP
+The number of TCP packets transmitted from this interface with
+VJ-compressed TCP headers.
+.TP
+.B VJUNC
+The number of TCP packets transmitted from this interface with
+VJ-uncompressed TCP headers.
+Not reported when the
+.B -r
+option is specified.
+.TP
+.B NON-VJ
+The total number of non-TCP packets transmitted from this interface.
+Not reported when the
+.B -r
+option is specified.
+.TP
+.B VJSRCH
+The number of searches for the cached header entry for a VJ header
+compressed TCP packet. Only reported when the
+.B -v
+option is specified.
+.TP
+.B VJMISS
+The number of failed searches for the cached header entry for a
+VJ header compressed TCP packet. Only reported when the
+.B -v
+option is specified.
+.TP
+.B RATIO
+The compression ratio achieved for transmitted packets by the
+packet compression scheme in use, defined as the size
+before compression divided by the compressed size.
+Only reported when the
+.B -r
+option is specified.
+.TP
+.B UBYTE
+The total number of bytes to be transmitted, before packet compression
+is applied. Only reported when the
+.B -r
+option is specified.
+.PP
+When the
+.B -z
+option is specified,
+.Nm pppstats
+instead displays the following fields, relating to the packet
+compression algorithm currently in use. If packet compression is not
+in use, these fields will all display zeroes. The fields displayed on
+the input side are:
+.TP
+.B COMPRESSED BYTE
+The number of bytes of compressed packets received.
+.TP
+.B COMPRESSED PACK
+The number of compressed packets received.
+.TP
+.B INCOMPRESSIBLE BYTE
+The number of bytes of incompressible packets (that is, those which
+were transmitted in uncompressed form) received.
+.TP
+.B INCOMPRESSIBLE PACK
+The number of incompressible packets received.
+.TP
+.B COMP RATIO
+The recent compression ratio for incoming packets, defined as the
+uncompressed size divided by the compressed size (including both
+compressible and incompressible packets).
+.PP
+The fields displayed on the output side are:
+.TP
+.B COMPRESSED BYTE
+The number of bytes of compressed packets transmitted.
+.TP
+.B COMPRESSED PACK
+The number of compressed packets transmitted.
+.TP
+.B INCOMPRESSIBLE BYTE
+The number of bytes of incompressible packets transmitted (that is,
+those which were transmitted in uncompressed form).
+.TP
+.B INCOMPRESSIBLE PACK
+The number of incompressible packets transmitted.
+.TP
+.B COMP RATIO
+The recent compression ratio for outgoing packets.
+.SH SEE ALSO
+pppd(8)
diff --git a/mdk-stage1/ppp/pppstats/pppstats.c b/mdk-stage1/ppp/pppstats/pppstats.c
new file mode 100644
index 000000000..108638b06
--- /dev/null
+++ b/mdk-stage1/ppp/pppstats/pppstats.c
@@ -0,0 +1,557 @@
+/*
+ * print PPP statistics:
+ * pppstats [-a|-d] [-v|-r|-z] [-c count] [-w wait] [interface]
+ *
+ * -a Show absolute values rather than deltas
+ * -d Show data rate (kB/s) rather than bytes
+ * -v Show more stats for VJ TCP header compression
+ * -r Show compression ratio
+ * -z Show compression statistics instead of default display
+ *
+ * History:
+ * perkins@cps.msu.edu: Added compression statistics and alternate
+ * display. 11/94
+ * Brad Parker (brad@cayman.com) 6/92
+ *
+ * from the original "slstats" by Van Jacobson
+ *
+ * Copyright (c) 1989 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef __STDC__
+#define const
+#endif
+
+#ifndef lint
+static const char rcsid[] = "$Id: pppstats.c 195720 2001-06-11 11:44:34Z gc $";
+#endif
+
+#include <stdio.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+
+#ifndef STREAMS
+#if defined(_linux_) && defined(__powerpc__) \
+ && (__GLIBC__ == 2 && __GLIBC_MINOR__ == 0)
+/* kludge alert! */
+#undef __GLIBC__
+#endif
+#include <sys/socket.h> /* *BSD, Linux, NeXT, Ultrix etc. */
+#ifndef _linux_
+#include <net/if.h>
+#include <net/ppp_defs.h>
+#include <net/if_ppp.h>
+#else
+/* Linux */
+#if __GLIBC__ >= 2
+#include <asm/types.h> /* glibc 2 conflicts with linux/types.h */
+#include <net/if.h>
+#else
+#include <linux/types.h>
+#include <linux/if.h>
+#endif
+#include <linux/ppp_defs.h>
+#include <linux/if_ppp.h>
+#endif /* _linux_ */
+
+#else /* STREAMS */
+#include <sys/stropts.h> /* SVR4, Solaris 2, SunOS 4, OSF/1, etc. */
+#include <net/ppp_defs.h>
+#include <net/pppio.h>
+
+#endif /* STREAMS */
+
+int vflag, rflag, zflag; /* select type of display */
+int aflag; /* print absolute values, not deltas */
+int dflag; /* print data rates, not bytes */
+int interval, count;
+int infinite;
+int unit;
+int s; /* socket or /dev/ppp file descriptor */
+int signalled; /* set if alarm goes off "early" */
+char *progname;
+char *interface;
+
+#if defined(SUNOS4) || defined(ULTRIX) || defined(NeXT)
+extern int optind;
+extern char *optarg;
+#endif
+
+/*
+ * If PPP_DRV_NAME is not defined, use the legacy "ppp" as the
+ * device name.
+ */
+#if !defined(PPP_DRV_NAME)
+#define PPP_DRV_NAME "ppp"
+#endif /* !defined(PPP_DRV_NAME) */
+
+static void usage __P((void));
+static void catchalarm __P((int));
+static void get_ppp_stats __P((struct ppp_stats *));
+static void get_ppp_cstats __P((struct ppp_comp_stats *));
+static void intpr __P((void));
+
+int main __P((int, char *argv[]));
+
+static void
+usage()
+{
+ fprintf(stderr, "Usage: %s [-a|-d] [-v|-r|-z] [-c count] [-w wait] [interface]\n",
+ progname);
+ exit(1);
+}
+
+/*
+ * Called if an interval expires before intpr has completed a loop.
+ * Sets a flag to not wait for the alarm.
+ */
+static void
+catchalarm(arg)
+ int arg;
+{
+ signalled = 1;
+}
+
+
+#ifndef STREAMS
+static void
+get_ppp_stats(curp)
+ struct ppp_stats *curp;
+{
+ struct ifpppstatsreq req;
+
+ memset (&req, 0, sizeof (req));
+
+#ifdef _linux_
+ req.stats_ptr = (caddr_t) &req.stats;
+#undef ifr_name
+#define ifr_name ifr__name
+#endif
+
+ strncpy(req.ifr_name, interface, sizeof(req.ifr_name));
+ if (ioctl(s, SIOCGPPPSTATS, &req) < 0) {
+ fprintf(stderr, "%s: ", progname);
+ if (errno == ENOTTY)
+ fprintf(stderr, "kernel support missing\n");
+ else
+ perror("couldn't get PPP statistics");
+ exit(1);
+ }
+ *curp = req.stats;
+}
+
+static void
+get_ppp_cstats(csp)
+ struct ppp_comp_stats *csp;
+{
+ struct ifpppcstatsreq creq;
+
+ memset (&creq, 0, sizeof (creq));
+
+#ifdef _linux_
+ creq.stats_ptr = (caddr_t) &creq.stats;
+#undef ifr_name
+#define ifr_name ifr__name
+#endif
+
+ strncpy(creq.ifr_name, interface, sizeof(creq.ifr_name));
+ if (ioctl(s, SIOCGPPPCSTATS, &creq) < 0) {
+ fprintf(stderr, "%s: ", progname);
+ if (errno == ENOTTY) {
+ fprintf(stderr, "no kernel compression support\n");
+ if (zflag)
+ exit(1);
+ rflag = 0;
+ } else {
+ perror("couldn't get PPP compression stats");
+ exit(1);
+ }
+ }
+
+#ifdef _linux_
+ if (creq.stats.c.bytes_out == 0) {
+ creq.stats.c.bytes_out = creq.stats.c.comp_bytes + creq.stats.c.inc_bytes;
+ creq.stats.c.in_count = creq.stats.c.unc_bytes;
+ }
+ if (creq.stats.c.bytes_out == 0)
+ creq.stats.c.ratio = 0.0;
+ else
+ creq.stats.c.ratio = 256.0 * creq.stats.c.in_count /
+ creq.stats.c.bytes_out;
+
+ if (creq.stats.d.bytes_out == 0) {
+ creq.stats.d.bytes_out = creq.stats.d.comp_bytes + creq.stats.d.inc_bytes;
+ creq.stats.d.in_count = creq.stats.d.unc_bytes;
+ }
+ if (creq.stats.d.bytes_out == 0)
+ creq.stats.d.ratio = 0.0;
+ else
+ creq.stats.d.ratio = 256.0 * creq.stats.d.in_count /
+ creq.stats.d.bytes_out;
+#endif
+
+ *csp = creq.stats;
+}
+
+#else /* STREAMS */
+
+int
+strioctl(fd, cmd, ptr, ilen, olen)
+ int fd, cmd, ilen, olen;
+ char *ptr;
+{
+ struct strioctl str;
+
+ str.ic_cmd = cmd;
+ str.ic_timout = 0;
+ str.ic_len = ilen;
+ str.ic_dp = ptr;
+ if (ioctl(fd, I_STR, &str) == -1)
+ return -1;
+ if (str.ic_len != olen)
+ fprintf(stderr, "strioctl: expected %d bytes, got %d for cmd %x\n",
+ olen, str.ic_len, cmd);
+ return 0;
+}
+
+static void
+get_ppp_stats(curp)
+ struct ppp_stats *curp;
+{
+ if (strioctl(s, PPPIO_GETSTAT, curp, 0, sizeof(*curp)) < 0) {
+ fprintf(stderr, "%s: ", progname);
+ if (errno == EINVAL)
+ fprintf(stderr, "kernel support missing\n");
+ else
+ perror("couldn't get PPP statistics");
+ exit(1);
+ }
+}
+
+static void
+get_ppp_cstats(csp)
+ struct ppp_comp_stats *csp;
+{
+ if (strioctl(s, PPPIO_GETCSTAT, csp, 0, sizeof(*csp)) < 0) {
+ fprintf(stderr, "%s: ", progname);
+ if (errno == ENOTTY) {
+ fprintf(stderr, "no kernel compression support\n");
+ if (zflag)
+ exit(1);
+ rflag = 0;
+ } else {
+ perror("couldn't get PPP compression statistics");
+ exit(1);
+ }
+ }
+}
+
+#endif /* STREAMS */
+
+#define MAX0(a) ((int)(a) > 0? (a): 0)
+#define V(offset) MAX0(cur.offset - old.offset)
+#define W(offset) MAX0(ccs.offset - ocs.offset)
+
+#define RATIO(c, i, u) ((c) == 0? 1.0: (u) / ((double)(c) + (i)))
+#define CRATE(x) RATIO(W(x.comp_bytes), W(x.inc_bytes), W(x.unc_bytes))
+
+#define KBPS(n) ((n) / (interval * 1000.0))
+
+/*
+ * Print a running summary of interface statistics.
+ * Repeat display every interval seconds, showing statistics
+ * collected over that interval. Assumes that interval is non-zero.
+ * First line printed is cumulative.
+ */
+static void
+intpr()
+{
+ register int line = 0;
+ sigset_t oldmask, mask;
+ char *bunit;
+ int ratef = 0;
+ struct ppp_stats cur, old;
+ struct ppp_comp_stats ccs, ocs;
+
+ memset(&old, 0, sizeof(old));
+ memset(&ocs, 0, sizeof(ocs));
+
+ while (1) {
+ get_ppp_stats(&cur);
+ if (zflag || rflag)
+ get_ppp_cstats(&ccs);
+
+ (void)signal(SIGALRM, catchalarm);
+ signalled = 0;
+ (void)alarm(interval);
+
+ if ((line % 20) == 0) {
+ if (zflag) {
+ printf("IN: COMPRESSED INCOMPRESSIBLE COMP | ");
+ printf("OUT: COMPRESSED INCOMPRESSIBLE COMP\n");
+ bunit = dflag? "KB/S": "BYTE";
+ printf(" %s PACK %s PACK RATIO | ", bunit, bunit);
+ printf(" %s PACK %s PACK RATIO", bunit, bunit);
+ } else {
+ printf("%8.8s %6.6s %6.6s",
+ "IN", "PACK", "VJCOMP");
+
+ if (!rflag)
+ printf(" %6.6s %6.6s", "VJUNC", "VJERR");
+ if (vflag)
+ printf(" %6.6s %6.6s", "VJTOSS", "NON-VJ");
+ if (rflag)
+ printf(" %6.6s %6.6s", "RATIO", "UBYTE");
+ printf(" | %8.8s %6.6s %6.6s",
+ "OUT", "PACK", "VJCOMP");
+
+ if (!rflag)
+ printf(" %6.6s %6.6s", "VJUNC", "NON-VJ");
+ if (vflag)
+ printf(" %6.6s %6.6s", "VJSRCH", "VJMISS");
+ if (rflag)
+ printf(" %6.6s %6.6s", "RATIO", "UBYTE");
+ }
+ putchar('\n');
+ }
+
+ if (zflag) {
+ if (ratef) {
+ printf("%8.3f %6u %8.3f %6u %6.2f",
+ KBPS(W(d.comp_bytes)),
+ W(d.comp_packets),
+ KBPS(W(d.inc_bytes)),
+ W(d.inc_packets),
+ ccs.d.ratio / 256.0);
+ printf(" | %8.3f %6u %8.3f %6u %6.2f",
+ KBPS(W(c.comp_bytes)),
+ W(c.comp_packets),
+ KBPS(W(c.inc_bytes)),
+ W(c.inc_packets),
+ ccs.c.ratio / 256.0);
+ } else {
+ printf("%8u %6u %8u %6u %6.2f",
+ W(d.comp_bytes),
+ W(d.comp_packets),
+ W(d.inc_bytes),
+ W(d.inc_packets),
+ ccs.d.ratio / 256.0);
+ printf(" | %8u %6u %8u %6u %6.2f",
+ W(c.comp_bytes),
+ W(c.comp_packets),
+ W(c.inc_bytes),
+ W(c.inc_packets),
+ ccs.c.ratio / 256.0);
+ }
+
+ } else {
+ if (ratef)
+ printf("%8.3f", KBPS(V(p.ppp_ibytes)));
+ else
+ printf("%8u", V(p.ppp_ibytes));
+ printf(" %6u %6u",
+ V(p.ppp_ipackets),
+ V(vj.vjs_compressedin));
+ if (!rflag)
+ printf(" %6u %6u",
+ V(vj.vjs_uncompressedin),
+ V(vj.vjs_errorin));
+ if (vflag)
+ printf(" %6u %6u",
+ V(vj.vjs_tossed),
+ V(p.ppp_ipackets) - V(vj.vjs_compressedin)
+ - V(vj.vjs_uncompressedin) - V(vj.vjs_errorin));
+ if (rflag) {
+ printf(" %6.2f ", CRATE(d));
+ if (ratef)
+ printf("%6.2f", KBPS(W(d.unc_bytes)));
+ else
+ printf("%6u", W(d.unc_bytes));
+ }
+ if (ratef)
+ printf(" | %8.3f", KBPS(V(p.ppp_obytes)));
+ else
+ printf(" | %8u", V(p.ppp_obytes));
+ printf(" %6u %6u",
+ V(p.ppp_opackets),
+ V(vj.vjs_compressed));
+ if (!rflag)
+ printf(" %6u %6u",
+ V(vj.vjs_packets) - V(vj.vjs_compressed),
+ V(p.ppp_opackets) - V(vj.vjs_packets));
+ if (vflag)
+ printf(" %6u %6u",
+ V(vj.vjs_searches),
+ V(vj.vjs_misses));
+ if (rflag) {
+ printf(" %6.2f ", CRATE(c));
+ if (ratef)
+ printf("%6.2f", KBPS(W(c.unc_bytes)));
+ else
+ printf("%6u", W(c.unc_bytes));
+ }
+
+ }
+
+ putchar('\n');
+ fflush(stdout);
+ line++;
+
+ count--;
+ if (!infinite && !count)
+ break;
+
+ sigemptyset(&mask);
+ sigaddset(&mask, SIGALRM);
+ sigprocmask(SIG_BLOCK, &mask, &oldmask);
+ if (!signalled) {
+ sigemptyset(&mask);
+ sigsuspend(&mask);
+ }
+ sigprocmask(SIG_SETMASK, &oldmask, NULL);
+ signalled = 0;
+ (void)alarm(interval);
+
+ if (!aflag) {
+ old = cur;
+ ocs = ccs;
+ ratef = dflag;
+ }
+ }
+}
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int c;
+#ifdef STREAMS
+ char *dev;
+#endif
+
+ interface = PPP_DRV_NAME "0";
+ if ((progname = strrchr(argv[0], '/')) == NULL)
+ progname = argv[0];
+ else
+ ++progname;
+
+ while ((c = getopt(argc, argv, "advrzc:w:")) != -1) {
+ switch (c) {
+ case 'a':
+ ++aflag;
+ break;
+ case 'd':
+ ++dflag;
+ break;
+ case 'v':
+ ++vflag;
+ break;
+ case 'r':
+ ++rflag;
+ break;
+ case 'z':
+ ++zflag;
+ break;
+ case 'c':
+ count = atoi(optarg);
+ if (count <= 0)
+ usage();
+ break;
+ case 'w':
+ interval = atoi(optarg);
+ if (interval <= 0)
+ usage();
+ break;
+ default:
+ usage();
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (!interval && count)
+ interval = 5;
+ if (interval && !count)
+ infinite = 1;
+ if (!interval && !count)
+ count = 1;
+ if (aflag)
+ dflag = 0;
+
+ if (argc > 1)
+ usage();
+ if (argc > 0)
+ interface = argv[0];
+
+ if (sscanf(interface, PPP_DRV_NAME "%d", &unit) != 1) {
+ fprintf(stderr, "%s: invalid interface '%s' specified\n",
+ progname, interface);
+ }
+
+#ifndef STREAMS
+ {
+ struct ifreq ifr;
+
+ s = socket(AF_INET, SOCK_DGRAM, 0);
+ if (s < 0) {
+ fprintf(stderr, "%s: ", progname);
+ perror("couldn't create IP socket");
+ exit(1);
+ }
+
+#ifdef _linux_
+#undef ifr_name
+#define ifr_name ifr_ifrn.ifrn_name
+#endif
+ strncpy(ifr.ifr_name, interface, sizeof(ifr.ifr_name));
+ if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr) < 0) {
+ fprintf(stderr, "%s: nonexistent interface '%s' specified\n",
+ progname, interface);
+ exit(1);
+ }
+ }
+
+#else /* STREAMS */
+#ifdef __osf__
+ dev = "/dev/streams/ppp";
+#else
+ dev = "/dev/" PPP_DRV_NAME;
+#endif
+ if ((s = open(dev, O_RDONLY)) < 0) {
+ fprintf(stderr, "%s: couldn't open ", progname);
+ perror(dev);
+ exit(1);
+ }
+ if (strioctl(s, PPPIO_ATTACH, &unit, sizeof(int), 0) < 0) {
+ fprintf(stderr, "%s: ppp%d is not available\n", progname, unit);
+ exit(1);
+ }
+
+#endif /* STREAMS */
+
+ intpr();
+ exit(0);
+}
diff --git a/mdk-stage1/ppp/sample/auth-down b/mdk-stage1/ppp/sample/auth-down
new file mode 100644
index 000000000..edde65db1
--- /dev/null
+++ b/mdk-stage1/ppp/sample/auth-down
@@ -0,0 +1,17 @@
+#!/bin/sh
+#
+# A program or script which is executed after the remote system
+# successfully authenticates itself. It is executed with the parameters
+# <interface-name> <peer-name> <user-name> <tty-device> <speed>
+#
+
+#
+# The environment is cleared before executing this script
+# so the path must be reset
+#
+PATH=/usr/sbin:/sbin:/usr/bin:/bin
+export PATH
+
+echo auth-down `date +'%y/%m/%d %T'` $* >> /var/log/pppstats
+
+# last line
diff --git a/mdk-stage1/ppp/sample/auth-up b/mdk-stage1/ppp/sample/auth-up
new file mode 100644
index 000000000..54722a3c0
--- /dev/null
+++ b/mdk-stage1/ppp/sample/auth-up
@@ -0,0 +1,17 @@
+#!/bin/sh
+#
+# A program or script which is executed after the remote system
+# successfully authenticates itself. It is executed with the parameters
+# <interface-name> <peer-name> <user-name> <tty-device> <speed>
+#
+
+#
+# The environment is cleared before executing this script
+# so the path must be reset
+#
+PATH=/usr/sbin:/sbin:/usr/bin:/bin
+export PATH
+
+echo auth-up `date +'%y/%m/%d %T'` $* >> /var/log/pppstats
+
+# last line
diff --git a/mdk-stage1/ppp/sample/ip-down b/mdk-stage1/ppp/sample/ip-down
new file mode 100644
index 000000000..b771fb644
--- /dev/null
+++ b/mdk-stage1/ppp/sample/ip-down
@@ -0,0 +1,22 @@
+#!/bin/sh
+#
+# This script is run by the pppd _after_ the link is brought down.
+# It should be used to delete routes, unset IP addresses etc.
+#
+# This script is called with the following arguments:
+# Arg Name Example
+# $1 Interface name ppp0
+# $2 The tty ttyS1
+# $3 The link speed 38400
+# $4 Local IP number 12.34.56.78
+# $5 Peer IP number 12.34.56.99
+#
+
+#
+# The environment is cleared before executing this script
+# so the path must be reset
+#
+PATH=/usr/sbin:/sbin:/usr/bin:/bin
+export PATH
+
+# last line
diff --git a/mdk-stage1/ppp/sample/ip-up b/mdk-stage1/ppp/sample/ip-up
new file mode 100644
index 000000000..02bb71c44
--- /dev/null
+++ b/mdk-stage1/ppp/sample/ip-up
@@ -0,0 +1,23 @@
+#!/bin/sh
+#
+# This script is run by the pppd after the link is established.
+# It should be used to add routes, set IP address, run the mailq
+# etc.
+#
+# This script is called with the following arguments:
+# Arg Name Example
+# $1 Interface name ppp0
+# $2 The tty ttyS1
+# $3 The link speed 38400
+# $4 Local IP number 12.34.56.78
+# $5 Peer IP number 12.34.56.99
+#
+
+#
+# The environment is cleared before executing this script
+# so the path must be reset
+#
+PATH=/usr/sbin:/sbin:/usr/bin:/bin
+export PATH
+
+# last line
diff --git a/mdk-stage1/ppp/sample/options b/mdk-stage1/ppp/sample/options
new file mode 100644
index 000000000..8d0a3f963
--- /dev/null
+++ b/mdk-stage1/ppp/sample/options
@@ -0,0 +1,153 @@
+# /etc/ppp/options
+
+# The name of this server. Often, the FQDN is used here.
+#name <host>
+
+# Enforce the use of the hostname as the name of the local system for
+# authentication purposes (overrides the name option).
+usehostname
+
+# If no local IP address is given, pppd will use the first IP address
+# that belongs to the local hostname. If "noipdefault" is given, this
+# is disabled and the peer will have to supply an IP address.
+noipdefault
+
+# With this option, pppd will accept the peer's idea of our local IP
+# address, even if the local IP address was specified in an option.
+#ipcp-accept-local
+
+# With this option, pppd will accept the peer's idea of its (remote) IP
+# address, even if the remote IP address was specified in an option.
+#ipcp-accept-remote
+
+# Specify which DNS Servers the incoming Win95 or WinNT Connection should use
+# Two Servers can be remotely configured
+#ms-dns 192.168.1.1
+#ms-dns 192.168.1.2
+
+# Specify which WINS Servers the incoming connection Win95 or WinNT should use
+#wins-addr 192.168.1.50
+#wins-addr 192.168.1.51
+
+# enable this on a server that already has a permanent default route
+#nodefaultroute
+
+# Run the executable or shell command specified after pppd has terminated
+# the link. This script could, for example, issue commands to the modem
+# to cause it to hang up if hardware modem control signals were not
+# available.
+# If mgetty is running, it will reset the modem anyway. So there is no need
+# to do it here.
+#disconnect "chat -- \d+++\d\c OK ath0 OK"
+
+# Increase debugging level (same as -d). The debug output is written
+# to syslog LOG_LOCAL2.
+debug
+
+# Enable debugging code in the kernel-level PPP driver. The argument n
+# is a number which is the sum of the following values: 1 to enable
+# general debug messages, 2 to request that the contents of received
+# packets be printed, and 4 to request that the contents of transmitted
+# packets be printed.
+#kdebug n
+
+# Require the peer to authenticate itself before allowing network
+# packets to be sent or received.
+# Please do not disable this setting. It is expected to be standard in
+# future releases of pppd. Use the call option (see manpage) to disable
+# authentication for specific peers.
+#auth
+
+# authentication can either be pap or chap. As most people only want to
+# use pap, you can also disable chap:
+#require-pap
+#refuse-chap
+
+# Use hardware flow control (i.e. RTS/CTS) to control the flow of data
+# on the serial port.
+crtscts
+
+# Specifies that pppd should use a UUCP-style lock on the serial device
+# to ensure exclusive access to the device.
+lock
+
+# Use the modem control lines.
+modem
+
+# async character map -- 32-bit hex; each bit is a character
+# that needs to be escaped for pppd to receive it. 0x00000001
+# represents '\x01', and 0x80000000 represents '\x1f'.
+# To allow pppd to work over a rlogin/telnet connection, ou should escape
+# XON (^Q), XOFF (^S) and ^]: (The peer should use "escape ff".)
+#asyncmap 200a0000
+asyncmap 0
+
+# Specifies that certain characters should be escaped on transmission
+# (regardless of whether the peer requests them to be escaped with its
+# async control character map). The characters to be escaped are
+# specified as a list of hex numbers separated by commas. Note that
+# almost any character can be specified for the escape option, unlike
+# the asyncmap option which only allows control characters to be
+# specified. The characters which may not be escaped are those with hex
+# values 0x20 - 0x3f or 0x5e.
+#escape 11,13,ff
+
+# Set the MRU [Maximum Receive Unit] value to <n> for negotiation. pppd
+# will ask the peer to send packets of no more than <n> bytes. The
+# minimum MRU value is 128. The default MRU value is 1500. A value of
+# 296 is recommended for slow links (40 bytes for TCP/IP header + 256
+# bytes of data).
+#mru 542
+
+# Set the MTU [Maximum Transmit Unit] value to <n>. Unless the peer
+# requests a smaller value via MRU negotiation, pppd will request that
+# the kernel networking code send data packets of no more than n bytes
+# through the PPP network interface.
+#mtu <n>
+
+# Set the interface netmask to <n>, a 32 bit netmask in "decimal dot"
+# notation (e.g. 255.255.255.0).
+#netmask 255.255.255.0
+
+# Don't fork to become a background process (otherwise pppd will do so
+# if a serial device is specified).
+nodetach
+
+# Set the assumed name of the remote system for authentication purposes
+# to <n>.
+#remotename <n>
+
+# Add an entry to this system's ARP [Address Resolution Protocol]
+# table with the IP address of the peer and the Ethernet address of this
+# system. {proxyarp,noproxyarp}
+proxyarp
+
+# Use the system password database for authenticating the peer using
+# PAP. Note: mgetty already provides this option. If this is specified
+# then dialin from users using a script under Linux to fire up ppp wont work.
+#login
+
+# If this option is given, pppd will send an LCP echo-request frame to
+# the peer every n seconds. Under Linux, the echo-request is sent when
+# no packets have been received from the peer for n seconds. Normally
+# the peer should respond to the echo-request by sending an echo-reply.
+# This option can be used with the lcp-echo-failure option to detect
+# that the peer is no longer connected.
+lcp-echo-interval 30
+
+# If this option is given, pppd will presume the peer to be dead if n
+# LCP echo-requests are sent without receiving a valid LCP echo-reply.
+# If this happens, pppd will terminate the connection. Use of this
+# option requires a non-zero value for the lcp-echo-interval parameter.
+# This option can be used to enable pppd to terminate after the physical
+# connection has been broken (e.g., the modem has hung up) in
+# situations where no hardware modem control lines are available.
+lcp-echo-failure 4
+
+# Specifies that pppd should disconnect if the link is idle for n seconds.
+idle 600
+
+# Disable the IPXCP and IPX protocols.
+noipx
+
+# ---<End of File>---
diff --git a/mdk-stage1/ppp/sample/options.ttyXX b/mdk-stage1/ppp/sample/options.ttyXX
new file mode 100644
index 000000000..d4202f534
--- /dev/null
+++ b/mdk-stage1/ppp/sample/options.ttyXX
@@ -0,0 +1,14 @@
+# If you need to set up multiple serial lines then copy this file to
+# options.<ttyname> for each tty with a modem on it.
+#
+# The options.tty file will assign an IP address to each PPP connection
+# as it comes up. They must all be distinct!
+#
+# Example:
+# options.ttyS1 for com2 under DOS.
+#
+# Edit the following line so that the first IP address
+# mentioned is the ip address of the serial port while the second
+# is the IP address of your host
+#
+hostname-s1:hostname
diff --git a/mdk-stage1/ppp/sample/pap-secrets b/mdk-stage1/ppp/sample/pap-secrets
new file mode 100644
index 000000000..098971b9f
--- /dev/null
+++ b/mdk-stage1/ppp/sample/pap-secrets
@@ -0,0 +1,28 @@
+# Secrets for authentication using PAP
+# client server secret IP addresses
+
+# OUTBOUND CONNECTIONS
+# Here you should add your userid password to connect to your providers via
+# pap. The * means that the password is to be used for ANY host you connect
+# to. Thus you do not have to worry about the foreign machine name. Just
+# replace password with your password.
+# If you have different providers with different passwords then you better
+# remove the following line.
+#hostname * password
+
+# INBOUND CONNECTIONS
+#client hostname <password> 192.168.1.1
+
+# If you add "auth login -chap +pap" to /etc/mgetty+sendfax/login.config,
+# all users in /etc/passwd can use their password for pap-authentication.
+#
+# Every regular user can use PPP and has to use passwords from /etc/passwd
+#* hostname ""
+# UserIDs that cannot use PPP at all. Check your /etc/passwd and add any
+# other accounts that should not be able to use pppd! Replace hostname
+# with your local hostname.
+#guest hostname "*" -
+#master hostname "*" -
+#root hostname "*" -
+#support hostname "*" -
+#stats hostname "*" -
diff --git a/mdk-stage1/ppp/scripts/README b/mdk-stage1/ppp/scripts/README
new file mode 100644
index 000000000..00e032ca6
--- /dev/null
+++ b/mdk-stage1/ppp/scripts/README
@@ -0,0 +1,143 @@
+This directory contains a set of scripts which have been used on Linux
+as well as Solaris 2.x systems to initiate or maintain a connection
+with PPP. The files in this directory were contributed by Al Longyear
+(longyear@netcom.com) and Adi Masputra (adi.masputra@sun.com)
+
+------------------------------------------------------------------------
+
+1. README
+
+This file. You are reading it. It is just documentation.
+
+------------------------------------------------------------------------
+
+2. ppp-on
+
+This script will initiate a connection to the PPP system. It will run
+the chat program with the connection script as a parameter. This is a
+possible security hole. However, it is simple. It is meant to replace
+the previous version of ppp-on which was not very functional.
+
+The ppp-on script has entries for the account name, password, IP
+addresses, and telephone numbers. The parameters are passed to the
+pppd process and, then in turn, to the second part of the connect
+script, as a set of environment variables.
+
+Please make sure that you put the full path name to the ppp-on-dialer
+script in the reference to it in ppp-on.
+
+------------------------------------------------------------------------
+
+3. ppp-on-dialer
+
+This is the second part to the simple calling script, ppp-on. It
+executes the chat program to connect the user with a standard UNIX
+style getty/login connection sequence.
+
+------------------------------------------------------------------------
+
+4. callback
+
+This script may be used in lieu of the ppp-on-dialer to permit the
+common modem callback sequence. You may need to make changes to the
+expected prompt string for the modem.
+
+The script works by disabling the system's detection of the DCD
+condition and working on the modem status message "NO CARRIER" which
+is generated when the modem disconnects.
+
+It is crude. It does work for my modem connection. Use as you see fit.
+
+------------------------------------------------------------------------
+
+5. redialer
+
+The redialer script is a replacement for the ppp-on-dialer script. It
+will do 'attack dialing' or 'demon dialing' of one or more telephone
+numbers. The first number which responds will be used for a
+connection.
+
+There is a limit of ten attempts and a 15 second delay between dialing
+attempts. Both values are set in the script.
+
+------------------------------------------------------------------------
+
+6. ppp-off
+
+This is a script which will terminate the active ppp connection. Use
+as either "ppp-off" to terminate ppp0, or "ppp-off <device>" to
+terminate the connection on <device>. For example, "ppp-off ppp2" will
+terminate the ppp2 connection.
+
+------------------------------------------------------------------------
+
+7. secure-card
+
+This script was written by Jim Isaacson <jcisaac@crl.com>. It is a script
+for the 'expect' programming language used with Tcl. You need to have
+expect and Tcl installed before this script may be used.
+
+This script will operate with a device marketed under the name "SecureCARD".
+This little device is mated with its controller. On the credit card size
+device, there is a sequence number which changes on a random basis. In order
+for you to connect you need to enter a fixed portion of your account name
+and the number which is displayed on this card device. The number must match
+the value at the controller in order for the account name to be used.
+
+The problem is that chat uses fixed response strings. In addition, the
+timing for running the script may prevent the use of a script that reads the
+value before it starts the dial sequence. What was needed was a script which
+asked the user at the user's console at the time that it is needed.
+
+This led to the use of expect.
+
+------------------------------------------------------------------------
+
+8. ppp-on-rsh
+
+This script will initiate a PPP connection to a remote machine using rsh.
+This is implemented by creating a master/slave pseudo-tty with the slave
+pointing to rsh, specifically with the 'pty' and 'notty' options of pppd.
+It is assumed that the remote machine contains some sort of trust
+mechanisms (such as ~/.rhosts, et al) to allow the local machine to
+connect via rsh as root.
+
+------------------------------------------------------------------------
+
+9. ppp-on-ssh
+
+This script will initiate a PPP connection to a remote machine using the
+secure shell, or ssh. I've only tested this on ssh 1.x, so those of you
+who are running ssh 2.x mahy need to modify the ssh options slightly.
+This is implemented by creating a master/slave pseudo-ttyt with the slave
+pointing to ssh, specifically with the 'pty' and 'notty' options of pppd.
+It is assumed that the remote machine can accept the ssh connection from
+the local host, in the sense that all ssh authentication mechanisms have
+been properly configured, so that a remote root user can open a ssh
+connection.
+
+------------------------------------------------------------------------
+
+10. options-rsh-loc & options-rsh-rem
+
+These options files accompany the ppp-on-rsh script mentioned above. In
+theory, you'd want to copy the options-rsh-rem to the remote machine where
+in.rshd is running. The only extra option required on the remote machine
+options file is the 'notty' option. In addition, all ASCII control characters
+[0x00 to 0x1f], plus 0xff, are escaped. This may need to be modified
+depending on the rsh (or pseudo-tty) implementation which may differ across
+platforms, for further optimizations.
+
+------------------------------------------------------------------------
+
+11. options-ssh-loc & options-ssh-rem
+
+These options files accompany the ppp-on-ssh script mentioned above. I've
+only tested this on ssh 1.x, so those of you who are running ssh 2.x need
+to modify the ssh options slightly. In theory, you'd want to copy the
+options-ssh-rem to the remote machine where sshd daemon is running. The only
+extra options required on the remote machine options file is the 'notty'
+option. In addition, all ASCII control characters [0x00 to 0x1f], plus 0xff,
+are escaped. This may need to be modified depending on the ssh (or
+pseudo-tty) implementation which may differ across platforms, for further
+optimizations.
diff --git a/mdk-stage1/ppp/scripts/callback b/mdk-stage1/ppp/scripts/callback
new file mode 100755
index 000000000..3e74e10b2
--- /dev/null
+++ b/mdk-stage1/ppp/scripts/callback
@@ -0,0 +1,77 @@
+#!/bin/sh
+###################################################################
+#
+# Script to dial the remote system, negotiate the connection, and send
+# it the id. Then wait for the modem to disconnect. Reset the modem
+# to answer mode and wait for the system to call back.
+#
+# The telephone number and modempass are used when establishing the
+# connection to the modem.
+#
+PHONE=555-1212
+MODEMPASS=modem_identifier
+#
+# Once the modem calls back, the account name and password are used for
+# a UNIX style login operation.
+#
+ACCOUNT=my_account_name
+PASSWORD=my_password
+
+###################################################################
+#
+# Step 1. Dial the modem and negotiate the initial dialog.
+# note: the modem is configured to ignore loss of DCD at this point.
+# it is important that this be performed because the loss of DCD
+# will normally prevent system from working since 'modem' is used
+# for pppd.
+#
+# The script is terminated normally when the carrier is lost.
+#
+chat -v \
+ TIMEOUT 3 \
+ ABORT '\nBUSY\r' \
+ ABORT '\nNO ANSWER\r' \
+ ABORT '\nRINGING\r\n\r\nRINGING\r' \
+ '' AT \
+ 'OK-+++\c-OK' 'AT&C0&D2S0=0H0 \
+ TIMEOUT 30 \
+ OK ATDT$TELEPHONE \
+ CONNECT '' \
+ assword: $MODEMPASS \
+ "\nNO CARRIER\r"
+
+if [ "$?" = "0" ]; then
+
+###################################################################
+#
+# Step 2. Wait for the call back from the remote. This will wait for at most
+# 30 seconds for the call back should the first attempt fail or
+# something happen with the callback logic at the remote.
+#
+# note: when the callback occurs, the DCD setting is re-enabled.
+#
+# If some voice call should happen during this period, the system will
+# answer the telephone and then hang up on them. I realize that this is
+# rude, but there is little that this script can do.
+#
+ chat -v \
+ TIMEOUT 30 \
+ ABORT '\nVOICE\r' \
+ '\nRING\r' 'AT&C1A' \
+ CONNECT '' \
+ TIMEOUT 10 \
+ ogin:--ogin: $ACCOUNT \
+ TIMEOUT 45 \
+ assword: $PASSWORD
+
+ if [ "$?" = "0" ]; then
+ exit 0
+ fi
+fi
+
+###################################################################
+#
+# The script has failed. Terminate the connection mode.
+#
+chat -v TIMEOUT 3 "" AT 'OK-+++\c-OK' 'AT&C1&D2S0=0H0' OK
+exit 1
diff --git a/mdk-stage1/ppp/scripts/chat-callback b/mdk-stage1/ppp/scripts/chat-callback
new file mode 100644
index 000000000..d014d6af3
--- /dev/null
+++ b/mdk-stage1/ppp/scripts/chat-callback
@@ -0,0 +1,98 @@
+# =====================================================================================
+# Chat script to dial our Company PPP account.
+# They uses a call-back system to identify us and to reverse
+# charge the call cost.
+# =====================================================================================
+#
+ECHO OFF
+# All the usual abort strings
+ABORT "NO CARRIER"
+ABORT "VOICE"
+ABORT "BUSY"
+ABORT "NO DIALTONE"
+ABORT "NO ANSWER"
+#
+# If calling outside allowed time we get this:
+#
+ABORT "Access denied"
+#
+# Modem initialisation stuff
+#
+TIMEOUT 5
+SAY "Initialising modem ...\n"
+'' ATE1
+'OK\r\n' ATS0=1S11=60X4&K4S42.1=1
+#
+# Now dial our ISP and wait for connection
+#
+SAY "Dialling our ISP ...\n"
+'OK\r\n' ATDT09834657
+TIMEOUT 60
+CONNECT \c
+SAY "Connected ...\n"
+#
+# This is the first stage login, we identify ourself so that the remote
+# system will agree to call us back.
+#
+TIMEOUT 30
+SAY "Sending Callback login ID ...\n"
+name:-BREAK-name: callme
+#
+# From now on, we must assume no carrier is normal as well
+# as receiving a HANGUP signal because it will be the
+# case if our ISP clears the call to call us back.
+#
+CLR_ABORT "NO CARRIER"
+HANGUP OFF
+#
+ABORT "Invalid"
+#
+# Now send password and wait to see what happens
+#
+SAY "Sending Callback password ...\n"
+word:--word: xvsgsgs
+"You will be" \c
+#
+# What can happen now is:
+# either: we get "You will be called back..." which is the successful case
+# or: we get "Invalid login" and we abort (bad login ID or password)
+# or: we get "NO CARRIER" because of an error, this will not abort
+# and we will time out after 30 seconds
+# or: we get nothing and we will time out after 30 seconds
+#
+#
+# We reach here if we got "You will be called back..."
+#
+CLR_ABORT "Invalid"
+SAY "Now waiting for Call back ...\n"
+#
+# The remote system will now hangup and we will get both "NO CARRIER"
+# and a hangup signal which are ignored. We now wait for a connection
+# for up to 120 seconds. What happens here if somebody else calls before
+# the remote system is a bit dangerous:
+#
+# If a malicious user connects and says 'name:', he will see 'PPPuser'
+# If he then says 'word:' he will see the passowrd 'blipblop'. I may not
+# know to which systems these belong to, though. It is up to you to consider
+# that case and decide wether the risk is too big or not ....
+#
+TIMEOUT 120
+"CONNECT" \c
+#
+# We have been called, re-arm ABORT on NO CARRIER and normal hangup signal
+# behaviour
+#
+HANGUP ON
+ABORT "NO CARRIER"
+#
+# Second stage login in order to start PPP
+#
+SAY "Remote system called back, logging in ...\n"
+SAY "Sending login ID ...\n"
+name:-BREAK-name: PPPuser
+SAY "Sending password ...\n"
+word:--word: blipblop
+SAY "Asking to start PPP ...\n"
+'CnetSrv' "ppp default"
+"Entering PPP mode" \c
+SAY "ISP PPP started ...\n"
diff --git a/mdk-stage1/ppp/scripts/chatchat/README b/mdk-stage1/ppp/scripts/chatchat/README
new file mode 100644
index 000000000..88a4c6939
--- /dev/null
+++ b/mdk-stage1/ppp/scripts/chatchat/README
@@ -0,0 +1,134 @@
+v 0.1 gpk@onramp.net 3/27/99
+
+I Intro
+
+ This document covers the use of the modified "chat" program and its
+adjunct "chatchat" to login using the Security Dynamics SecurID card
+on a linux system.
+
+ This set of files comprises a modified version of the chat program
+(the one distributed with ppp-2.3.5) and a new program called chatchat
+that allows you to supply data from the keyboard to the chat program.
+
+ The SecurID card generates passwords that have a lifetime of one
+minute and are used as a first layer in dial up security. The only
+software I know of for this card is for windows, so I wrote my own.
+This software allows you to type in the time-sensitive password right
+when your chat script is asked to supply the passcode by the remote
+system.
+
+
+II How It Works
+
+ This version of chat his an additional command that can be put into
+its options that says "Don't reply with this string. Open this pipe,
+read the contents, and reply with that instead." Chatchat creates a
+pipe and lets you type your passcode into it, then chat picks that up
+and sends it out just as though the passcode was hardcoded into the
+options.
+
+
+III Installation
+
+ I've provided intel binaries and source code the the modified chat
+program and the chatchat program. I'll recommend that you copy the
+chat.c program into your ppp-2.3.5/chat directory (save your original
+chat.c program first!) and re-make it using the Makefile that comes
+with chat. Copy the new chat somewhere into your path. (On my system
+chat lives in /usr/sbin/chat, so I've copied the modified one into
+/usr/sbin/chat.new and changed my dial in script to call chat.new
+instead of chat.
+
+ Second, compile chatchat.c and install it somewhere in your path:
+
+ gcc -g -o chatchat chatchat.c
+ cp chatchat /usr/sbin
+
+ Third, modify your chat script to use the chatchat program. Mine
+looks something like this:
+
+
+ --------------------
+
+#!/bin/sh
+#
+# This is part 2 of the ppp-on script. It will perform the connection
+# protocol for the desired connection.
+# use atm0 to turn down the speaker volume on my sportster x2 voice modem
+# gpk 11/2/97
+
+exec /usr/sbin/chat.new -V -v \
+ ABORT "BUSY" \
+ ABORT "NO DIAL TONE" \
+ ABORT "NO ANSWER" \
+ TIMEOUT 50 \
+ "" "atm0" \
+ OK ATDT$TELEPHONE \
+ CONNECT '' \
+ name: \\da0xxxxxx \
+ word: @/var/tmp/p \
+ compress. ''
+
+
+ -----------------------
+
+ This is a standard chat script:
+
+* abort if the modem is busy, you don't get a dial tone, no one
+ answers, or 50 seconds elapses.
+
+* use atm0 to mute the modem
+
+* dial the modem, when it connects, wait to be asked for account name
+
+* when we see "name:" prompt, delay briefly then respond with your
+ account name (fill in your account name)
+
+Now we get to the new stuff:
+
+* when we see "word:" in the password prompt, instead of responding
+ with "@/var/tmp/p", the modified chat program will open the pipe
+ /var/tmp/p, read the passcode out of there, and send it
+
+* when we see "compress." (the last word before ppp starts), reply
+ with nothing. The script ends and we start ppp.
+
+Note:
+
+* Make sure there is some whitespace between the filename and the \.
+
+
+IV Usage
+
+ To use this install the modified chat and chatchat programs, and
+modify your chat script similar to the above. Before you dial in,
+start that chatchat program giving it the same pipe as in your config
+file. In the above case:
+
+chatchat /var/tmp/p
+
+ Wait until you have one or two tick marks left on your card's
+current number, then start your dial up process that eventually calls
+chat. When chat goes to open and read the pipe, chatchat will prompt:
+
+
+type PIN into SecurID card and
+ enter resulting passcode:
+
+ At that point, type your PIN number into your Securid card, press
+the diamond, and type the resulting numbers in as your passcode. If
+you've left the -V -v options on your chat command you'll see
+everything so out, otherwise it works silently.
+
+ If you type the number wrong or run out of time, the server will
+respond with an authentication failure. In that case you will have to
+hang up and start again. I don't know how to build a conditional script
+that says either expect "compress" next, but if you see "name:" again,
+do this instead.
+
+
+V Additional Information
+
+ You can obtain additional information about chat and ppp from the
+man pages for chat and pppd, as well as the PPP-HOWTO.
+
diff --git a/mdk-stage1/ppp/scripts/chatchat/chatchat.c b/mdk-stage1/ppp/scripts/chatchat/chatchat.c
new file mode 100644
index 000000000..4534fb9e3
--- /dev/null
+++ b/mdk-stage1/ppp/scripts/chatchat/chatchat.c
@@ -0,0 +1,409 @@
+/* *************************************************************************
+* NAME: chatchat.c
+*
+* DESCRIPTION:
+*
+* This program creates a pipe for the chat process to read. The user
+* can supply information (like a password) that will be picked up
+* by chat and sent just like the regular contents of a chat script.
+*
+* Usage is:
+*
+* chatchat <filename>
+*
+* where <filename> matches the option given in the chat script.
+*
+* for instance the chat script fragment:
+*
+* ...
+* name: \\dmyname \
+* word: @/var/tmp/p \
+* ...
+* ^
+* (note: leave some whitespace after the filename)
+*
+* expect "name:", reply with a delay followed by "myname"
+* expect "word:", reply with the data read from the pipe /var/tmp/p
+*
+* the matching usage of chatchat would be:
+*
+* chatchat /var/tmp/p
+*
+* eg:
+*
+* $chatchat /var/tmp/p
+* ...
+* some other process eventually starts:
+* chat ...
+* chat parses the "@/var/tmp/p" option and opens
+* /var/tmp/p
+* (chatchat prompts:)
+*
+* type PIN into SecurID card
+* enter resulting passcode: [user inputs something]
+*
+* chat reads /var/tmp/p & gets what the
+* user typed at chatchat's "enter string" prompt
+* chat removes the pipe file
+* chat sends the user's input as a response in
+* place of "@/var/tmp/p"
+*
+* PROCESS:
+*
+* gcc -g -o chatchat chatchat.c
+*
+*
+* GLOBALS: none
+*
+* REFERENCES:
+*
+* see the man pages and documentation that come with the 'chat' program
+* (part of the ppp package). you will need to use the modified chat
+* program that accepts the '@' operator.
+*
+* LIMITATIONS:
+*
+* REVISION HISTORY:
+*
+* STR Description Author
+*
+* 23-Mar-99 initial coding gpk
+* 12-May-99 unlink the pipe after closing paulus
+*
+* TARGET: ANSI C
+* This program is in the public domain.
+*
+*
+* ************************************************************************* */
+
+
+
+
+#include <sys/time.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+
+/* MAXINPUT - the data typed into chatchat must be fewer */
+/* characters than this. */
+
+#define MAXINPUT 80
+
+
+
+
+
+
+/* *************************************************************************
+
+
+ NAME: main
+
+
+ USAGE:
+
+ int argc;
+ char * argv[];
+
+ main(argc, argv[]);
+
+ returns: int
+
+ DESCRIPTION:
+ if the pipe file name is given on the command line,
+ create the pipe, prompt the user and put whatever
+ is typed into the pipe.
+
+ returns -1 on error
+ else # characters entered
+ REFERENCES:
+
+ LIMITATIONS:
+
+ GLOBAL VARIABLES:
+
+ accessed: none
+
+ modified: none
+
+ FUNCTIONS CALLED:
+
+ REVISION HISTORY:
+
+ STR Description of Revision Author
+
+ 25-Mar-99 initial coding gpk
+
+ ************************************************************************* */
+
+int main(int argc, char * argv[])
+{
+ int retval;
+
+ int create_and_write_pipe(char * pipename);
+
+ if (argc != 2)
+ {
+ fprintf(stderr, "usage: %s pipename\n", argv[0]);
+ retval = -1;
+ }
+ else
+ {
+ retval = create_and_write_pipe(argv[1]);
+ }
+ return (retval);
+}
+
+
+
+
+/* *************************************************************************
+
+
+ NAME: create_and_write_pipe
+
+
+ USAGE:
+
+ int some_int;
+ char * pipename;
+
+ some_int = create_and_write_pipe(pipename);
+
+ returns: int
+
+ DESCRIPTION:
+ given the pipename, create the pipe, open it,
+ prompt the user for a string to put into the
+ pipe, write the string, and close the pipe
+
+ on error, print out an error message and return -1
+
+ returns -1 on error
+ else #bytes written into the pipe
+ REFERENCES:
+
+ LIMITATIONS:
+
+ GLOBAL VARIABLES:
+
+ accessed: none
+
+ modified: none
+
+ FUNCTIONS CALLED:
+
+ REVISION HISTORY:
+
+ STR Description of Revision Author
+
+ 25-Mar-99 initial coding gpk
+ 12-May-99 remove pipe after closing paulus
+
+ ************************************************************************* */
+
+int create_and_write_pipe(char * pipename)
+{
+ int retval, created, pipefd, nread, nwritten;
+ char input[MAXINPUT];
+ char errstring[180];
+
+ int create_pipe(char * pipename);
+ int write_to_pipe(int pipefd, char * input, int nchar);
+
+ created = create_pipe(pipename);
+
+ if (-1 == created)
+ {
+ sprintf(errstring, "unable to create pipe '%s'", pipename);
+ perror(errstring);
+ retval = -1;
+ }
+ else
+ {
+
+ /* note: this open won't succeed until chat has the pipe */
+ /* open and ready to read. this makes for nice timing. */
+
+ pipefd = open(pipename, O_WRONLY);
+
+ if (-1 == pipefd)
+ {
+ sprintf(errstring, "unable to open pipe '%s'", pipename);
+ perror(errstring);
+ retval = -1;
+ }
+ else
+ {
+ fprintf(stderr, "%s \n %s",
+ "type PIN into SecurID card and",
+ "enter resulting passcode:");
+ nread = read(STDIN_FILENO, (void *)input, MAXINPUT);
+
+
+ if (0 >= nread)
+ {
+ perror("unable to read from stdin");
+ retval = -1;
+ }
+ else
+ {
+ /* munch off the newline character, chat supplies */
+ /* a return when it sends the string out. */
+ input[nread -1] = 0;
+ nread--;
+ nwritten = write_to_pipe(pipefd, input, nread);
+ /* printf("wrote [%d]: '%s'\n", nwritten, input); */
+ retval = nwritten;
+ }
+ close(pipefd);
+
+ /* Now make the pipe go away. It won't actually go away
+ completely until chat closes it. */
+ if (unlink(pipename) < 0)
+ perror("Warning: couldn't remove pipe");
+ }
+ }
+ return(retval);
+}
+
+
+
+
+
+
+
+/* *************************************************************************
+
+
+ NAME: create_pipe
+
+
+ USAGE:
+
+ int some_int;
+ char * pipename;
+
+ some_int = create_pipe(pipename);
+
+ returns: int
+
+ DESCRIPTION:
+ create a pipe of the given name
+
+ if there is an error (like the pipe already exists)
+ print an error message and return
+
+ return -1 on failure else success
+
+ REFERENCES:
+
+ LIMITATIONS:
+
+ GLOBAL VARIABLES:
+
+ accessed: none
+
+ modified: none
+
+ FUNCTIONS CALLED:
+
+ REVISION HISTORY:
+
+ STR Description of Revision Author
+
+ 25-Mar-99 initial coding gpk
+
+ ************************************************************************* */
+
+int create_pipe(char * pipename)
+{
+ mode_t old_umask;
+ int created;
+
+ /* hijack the umask temporarily to get the mode I want */
+ /* on the pipe. */
+
+ old_umask = umask(000);
+
+ created = mknod(pipename, S_IFIFO | S_IRWXU | S_IWGRP | S_IWOTH,
+ (dev_t)NULL);
+
+ /* now restore umask. */
+
+ (void)umask(old_umask);
+
+ if (-1 == created)
+ {
+ perror("unable to create pipe");
+ }
+
+ return(created);
+}
+
+
+
+
+
+
+/* *************************************************************************
+
+
+ NAME: write_to_pipe
+
+
+ USAGE:
+
+ int some_int;
+ int pipefd;
+ char * input;
+ int nchar;
+
+ some_int = write_to_pipe(pipefd, input, nchar);
+
+ returns: int
+
+ DESCRIPTION:
+ write nchars of data from input to pipefd
+
+ on error print a message to stderr
+
+ return -1 on error, else # bytes written
+ REFERENCES:
+
+ LIMITATIONS:
+
+ GLOBAL VARIABLES:
+
+ accessed: none
+
+ modified: none
+
+ FUNCTIONS CALLED:
+
+ REVISION HISTORY:
+
+ STR Description of Revision Author
+
+ 25-Mar-99 initial coding gpk
+ 12-May-99 don't write count word first paulus
+
+ ************************************************************************* */
+
+int write_to_pipe(int pipefd, char * input, int nchar)
+{
+ int nwritten;
+
+ /* nwritten = write(pipefd, (void *)&nchar, sizeof(nchar)); */
+ nwritten = write(pipefd, (void *)input, nchar);
+
+ if (-1 == nwritten)
+ {
+ perror("unable to write to pipe");
+ }
+
+ return(nwritten);
+}
diff --git a/mdk-stage1/ppp/scripts/ip-down.local.add b/mdk-stage1/ppp/scripts/ip-down.local.add
new file mode 100644
index 000000000..b93590e49
--- /dev/null
+++ b/mdk-stage1/ppp/scripts/ip-down.local.add
@@ -0,0 +1,20 @@
+
+#
+# This sample code shows you one way to modify your setup to allow automatic
+# configuration of your resolv.conf for peer supplied DNS addresses when using
+# the `usepeerdns' option.
+#
+# In my case I just added this to my /etc/ppp/ip-down.local script. You may need to
+# create an executable script if one does not exist.
+#
+# Nick Walker (nickwalker@email.com)
+#
+
+if [ -n "$USEPEERDNS" -a -f /etc/ppp/resolv.conf ]; then
+ if [ -f /etc/ppp/resolv.prev ]; then
+ cp -f /etc/ppp/resolv.prev /etc/resolv.conf
+ else
+ rm -f /etc/resolv.conf
+ fi
+fi
+
diff --git a/mdk-stage1/ppp/scripts/ip-up.local.add b/mdk-stage1/ppp/scripts/ip-up.local.add
new file mode 100644
index 000000000..80172093a
--- /dev/null
+++ b/mdk-stage1/ppp/scripts/ip-up.local.add
@@ -0,0 +1,24 @@
+
+#
+# This sample code shows you one way to modify your setup to allow automatic
+# configuration of your resolv.conf for peer supplied DNS addresses when using
+# the `usepeerdns' option.
+#
+# In my case I just added this to my /etc/ppp/ip-up.local script. You may need to
+# create an executable script if one does not exist.
+#
+# Nick Walker (nickwalker@email.com)
+#
+
+if [ -n "$USEPEERDNS" -a -f /etc/ppp/resolv.conf ]; then
+ rm -f /etc/ppp/resolv.prev
+ if [ -f /etc/resolv.conf ]; then
+ cp /etc/resolv.conf /etc/ppp/resolv.prev
+ grep domain /etc/ppp/resolv.prev > /etc/resolv.conf
+ grep search /etc/ppp/resolv.prev >> /etc/resolv.conf
+ cat /etc/ppp/resolv.conf >> /etc/resolv.conf
+ else
+ cp /etc/ppp/resolv.conf /etc
+ fi
+fi
+
diff --git a/mdk-stage1/ppp/scripts/options-rsh-loc b/mdk-stage1/ppp/scripts/options-rsh-loc
new file mode 100644
index 000000000..b015b87fe
--- /dev/null
+++ b/mdk-stage1/ppp/scripts/options-rsh-loc
@@ -0,0 +1 @@
+debug asyncmap FFFFFFFF escape FF kdebug 0 noipdefault nodefaultroute noauth mtu 1460
diff --git a/mdk-stage1/ppp/scripts/options-rsh-rem b/mdk-stage1/ppp/scripts/options-rsh-rem
new file mode 100644
index 000000000..4b10bb9e9
--- /dev/null
+++ b/mdk-stage1/ppp/scripts/options-rsh-rem
@@ -0,0 +1 @@
+notty debug asyncmap FFFFFFFF escape FF kdebug 0 noipdefault nodefaultroute noauth mtu 1460
diff --git a/mdk-stage1/ppp/scripts/options-ssh-loc b/mdk-stage1/ppp/scripts/options-ssh-loc
new file mode 100644
index 000000000..add03d659
--- /dev/null
+++ b/mdk-stage1/ppp/scripts/options-ssh-loc
@@ -0,0 +1 @@
+debug asyncmap FFFFFFFF escape FF kdebug 0 noipdefault nodefaultroute noauth mtu 1400
diff --git a/mdk-stage1/ppp/scripts/options-ssh-rem b/mdk-stage1/ppp/scripts/options-ssh-rem
new file mode 100644
index 000000000..d690722c6
--- /dev/null
+++ b/mdk-stage1/ppp/scripts/options-ssh-rem
@@ -0,0 +1 @@
+notty debug asyncmap FFFFFFFF escape FF kdebug 0 noipdefault nodefaultroute noauth mtu 1400
diff --git a/mdk-stage1/ppp/scripts/ppp-off b/mdk-stage1/ppp/scripts/ppp-off
new file mode 100755
index 000000000..a22b5ea3d
--- /dev/null
+++ b/mdk-stage1/ppp/scripts/ppp-off
@@ -0,0 +1,34 @@
+#!/bin/sh
+######################################################################
+#
+# Determine the device to be terminated.
+#
+if [ "$1" = "" ]; then
+ DEVICE=ppp0
+else
+ DEVICE=$1
+fi
+
+######################################################################
+#
+# If the ppp0 pid file is present then the program is running. Stop it.
+if [ -r /var/run/$DEVICE.pid ]; then
+ kill -INT `cat /var/run/$DEVICE.pid`
+#
+# If the kill did not work then there is no process running for this
+# pid. It may also mean that the lock file will be left. You may wish
+# to delete the lock file at the same time.
+ if [ ! "$?" = "0" ]; then
+ rm -f /var/run/$DEVICE.pid
+ echo "ERROR: Removed stale pid file"
+ exit 1
+ fi
+#
+# Success. Let pppd clean up its own junk.
+ echo "PPP link to $DEVICE terminated."
+ exit 0
+fi
+#
+# The ppp process is not running for ppp0
+echo "ERROR: PPP link is not active on $DEVICE"
+exit 1
diff --git a/mdk-stage1/ppp/scripts/ppp-on b/mdk-stage1/ppp/scripts/ppp-on
new file mode 100755
index 000000000..ab79db471
--- /dev/null
+++ b/mdk-stage1/ppp/scripts/ppp-on
@@ -0,0 +1,36 @@
+#!/bin/sh
+#
+# Script to initiate a ppp connection. This is the first part of the
+# pair of scripts. This is not a secure pair of scripts as the codes
+# are visible with the 'ps' command. However, it is simple.
+#
+# These are the parameters. Change as needed.
+TELEPHONE=555-1212 # The telephone number for the connection
+ACCOUNT=george # The account name for logon (as in 'George Burns')
+PASSWORD=gracie # The password for this account (and 'Gracie Allen')
+LOCAL_IP=0.0.0.0 # Local IP address if known. Dynamic = 0.0.0.0
+REMOTE_IP=0.0.0.0 # Remote IP address if desired. Normally 0.0.0.0
+NETMASK=255.255.255.0 # The proper netmask if needed
+#
+# Export them so that they will be available at 'ppp-on-dialer' time.
+export TELEPHONE ACCOUNT PASSWORD
+#
+# This is the location of the script which dials the phone and logs
+# in. Please use the absolute file name as the $PATH variable is not
+# used on the connect option. (To do so on a 'root' account would be
+# a security hole so don't ask.)
+#
+DIALER_SCRIPT=/etc/ppp/ppp-on-dialer
+#
+# Initiate the connection
+#
+# I put most of the common options on this command. Please, don't
+# forget the 'lock' option or some programs such as mgetty will not
+# work. The asyncmap and escape will permit the PPP link to work with
+# a telnet or rlogin connection. You are welcome to make any changes
+# as desired. Don't use the 'defaultroute' option if you currently
+# have a default route to an ethernet gateway.
+#
+exec /usr/sbin/pppd debug lock modem crtscts /dev/ttyS0 38400 \
+ asyncmap 20A0000 escape FF kdebug 0 $LOCAL_IP:$REMOTE_IP \
+ noipdefault netmask $NETMASK defaultroute connect $DIALER_SCRIPT
diff --git a/mdk-stage1/ppp/scripts/ppp-on-dialer b/mdk-stage1/ppp/scripts/ppp-on-dialer
new file mode 100755
index 000000000..7d66765f1
--- /dev/null
+++ b/mdk-stage1/ppp/scripts/ppp-on-dialer
@@ -0,0 +1,17 @@
+#!/bin/sh
+#
+# This is part 2 of the ppp-on script. It will perform the connection
+# protocol for the desired connection.
+#
+exec chat -v \
+ TIMEOUT 3 \
+ ABORT '\nBUSY\r' \
+ ABORT '\nNO ANSWER\r' \
+ ABORT '\nRINGING\r\n\r\nRINGING\r' \
+ '' \rAT \
+ 'OK-+++\c-OK' ATH0 \
+ TIMEOUT 30 \
+ OK ATDT$TELEPHONE \
+ CONNECT '' \
+ ogin:--ogin: $ACCOUNT \
+ assword: $PASSWORD
diff --git a/mdk-stage1/ppp/scripts/ppp-on-rsh b/mdk-stage1/ppp/scripts/ppp-on-rsh
new file mode 100755
index 000000000..30a50dba6
--- /dev/null
+++ b/mdk-stage1/ppp/scripts/ppp-on-rsh
@@ -0,0 +1,72 @@
+#!/bin/sh
+#
+# A sample script to establish PPP session(s) via rsh
+#
+# Adi Masputra <adi.masputra@sun.com>
+# Jan 24, 2000
+#
+
+#
+# You'd definitely want to change the following addresses to suit
+# your network configuration
+#
+LOC_IP=10.0.0.1
+REM_IP=10.0.0.2
+NETMASK=255.255.0.0
+
+export LOC_IP REM_IP
+
+#
+# This is the remote peer where in.rshd is running, either
+# its hostname or IP address
+#
+PPPD_RHOST=myremotehost
+
+#
+# For this example, we assume that pppd on both local and remote
+# machines reside in the same place, /usr/local/bin/pppd
+#
+PPPD_LOC=/usr/local/bin/pppd
+
+#
+# The location of local options file (where rsh client is running).
+# Note that the sample options file included in the distribution
+# may need further customizations, depending on your needs. The 'noauth'
+# option specified in the file is there to simplify the example. In
+# reality, you'd probably want to remove such option.
+#
+PPPD_LOC_OPT=/etc/ppp/options-rsh-loc
+
+#
+# The location of remote options file (where in.rshd daemon is running).
+# Note that the sample options file included in the distribution
+# may need further customizations, depending on your needs. The 'noauth'
+# option specified in the file is there to simplify the example. In
+# reality, you'd probably want to remove such option. Also note that
+# the remote options file need to include the 'notty' option for this
+# to work
+#
+PPPD_REM_OPT=/etc/ppp/options-rsh-rem
+
+#
+# The location of rsh client on the local machine
+#
+RSH_LOC=/bin/rsh
+
+export PPPD_LOC PPPD_LOC_OPT PPPD_REM_OPT PPPD_RHOST RSH_LOC
+
+#
+# Uncomment the following to enable IPv6, note that the IPv6 support
+# needs to be enabled during compilation
+#
+# PPPD_IPV6='+ipv6 ipv6cp-use-ipaddr'
+export PPPD_IPV6
+
+#
+# And execute pppd with the pty option, specifying rsh client as the
+# slave side of the pseduo-tty master/slave pair.
+#
+exec $PPPD_LOC \
+ pty '$RSH_LOC $PPPD_RHOST $PPPD_LOC $REM_IP:$LOC_IP $PPPD_IPV6 file $PPPD_REM_OPT' \
+ $LOC_IP:$REM_IP netmask $NETMASK $PPPD_IPV6 file $PPPD_LOC_OPT
+
diff --git a/mdk-stage1/ppp/scripts/ppp-on-ssh b/mdk-stage1/ppp/scripts/ppp-on-ssh
new file mode 100755
index 000000000..0e41acac6
--- /dev/null
+++ b/mdk-stage1/ppp/scripts/ppp-on-ssh
@@ -0,0 +1,76 @@
+#!/bin/sh
+#
+# A sample script to establish PPP session(s) via SSH 1.x
+#
+# Adi Masputra <adi.masputra@sun.com>
+# Jan 24, 2000
+#
+
+#
+# You'd definitely want to change the following addresses to suit
+# your network configuration
+#
+LOC_IP=10.0.0.1
+REM_IP=10.0.0.2
+NETMASK=255.255.0.0
+
+export LOC_IP REM_IP
+
+#
+# This is the remote peer where sshd is running, either
+# its hostname or IP address
+#
+PPPD_RHOST=myremotehost
+
+#
+# For this example, we assume that pppd on both local and remote
+# machines reside in the same place, /usr/local/bin/pppd
+#
+PPPD_LOC=/usr/local/bin/pppd
+
+#
+# The location of local options file (where ssh client is running).
+# Note that the sample options file included in the distribution
+# may need further customizations, depending on your needs. The 'noauth'
+# option specified in the file is there to simplify the example, although
+# some may choose to have it there and rely on ssh authentication
+# instead.
+#
+PPPD_LOC_OPT=/etc/ppp/options-ssh-loc
+
+#
+# The location of remote options file (where sshd daemon is running)
+# Note that the sample options file included in the distribution
+# may need further customizations, depending on your needs. The 'noauth'
+# option specified in the file is there to simplify the example, although
+# some may choose to have it there and rely on ssh authentication
+# instead. Also note that the remote options file need to include the 'notty'
+# options for this to work.
+#
+PPPD_REM_OPT=/etc/ppp/options-ssh-rem
+
+#
+# The location of ssh client on the local machine
+#
+SSH_LOC=/usr/local/bin/ssh
+
+export PPPD_LOC PPPD_LOC_OPT PPPD_REM_OPT PPPD_RHOST SSH_LOC
+
+#
+# Uncomment the following to enable IPv6, note that the IPv6 support
+# needs to be enabled during compilation
+#
+# PPPD_IPV6='+ipv6 ipv6cp-use-ipaddr'
+export PPPD_IPV6
+
+#
+# And execute pppd with the pty option, specifying ssh client as the
+# slave side of the pseudo-tty master/slave pair. Note that on this example,
+# ssh has been compiled to allow NULL encryption (thus the '-c none' option),
+# but in reality, you'd probably want to specify the encryption algorithm.
+# See the man page of ssh(1) for details.
+#
+exec $PPPD_LOC \
+ pty '$SSH_LOC -c none $PPPD_RHOST $PPPD_LOC $REM_IP:$LOC_IP $PPPD_IPV6 file $PPPD_REM_OPT' \
+ $LOC_IP:$REM_IP netmask $NETMASK $PPPD_IPV6 file $PPPD_LOC_OPT
+
diff --git a/mdk-stage1/ppp/scripts/redialer b/mdk-stage1/ppp/scripts/redialer
new file mode 100755
index 000000000..5bbde4e9d
--- /dev/null
+++ b/mdk-stage1/ppp/scripts/redialer
@@ -0,0 +1,96 @@
+#!/bin/sh
+###################################################################
+#
+# These parameters control the attack dialing sequence.
+#
+# Maximum number of attempts to reach the telephone number(s)
+MAX_ATTEMPTS=10
+
+# Delay between each of the attempts. This is a parameter to sleep
+# so use "15s" for 15 seconds, "1m" for 1 minute, etc.
+SLEEP_DELAY=15s
+
+###################################################################
+#
+# This is a list of telephone numbers. Add new numbers if you wish
+# and see the function 'callall' below for the dial process.
+PHONE1=555-1212
+PHONE2=411
+
+###################################################################
+#
+# If you use the ppp-on script, then these are passed to this routine
+# automatically. There is no need to define them here. If not, then
+# you will need to set the values.
+#
+ACCOUNT=my_account_name
+PASSWORD=my_password
+
+###################################################################
+#
+# Function to initialize the modem and ensure that it is in command
+# state. This may not be needed, but it doesn't hurt.
+#
+function initialize
+{
+ chat -v TIMEOUT 3 '' AT 'OK-+++\c-OK'
+ return
+}
+
+###################################################################
+#
+# Script to dial a telephone
+#
+function callnumber
+{
+chat -v \
+ ABORT '\nBUSY\r' \
+ ABORT '\nNO ANSWER\r' \
+ ABORT '\nRINGING\r\n\r\nRINGING\r' \
+ '' ATDT$1 \
+ CONNECT '' \
+ ogin:--ogin: $ACCOUNT \
+ assword: $PASSWORD
+#
+# If the connection was successful then end the whole script with a
+# success.
+#
+ if [ "$?" = "0" ]; then
+ exit 0
+ fi
+
+ return
+}
+
+###################################################################
+#
+# Script to dial any telephone number
+#
+function callall
+{
+# echo "dialing attempt number: $1" >/dev/console
+ callnumber $PHONE1
+# callnumber $PHONE2
+}
+
+###################################################################
+#
+# Initialize the modem to ensure that it is in the command state
+#
+initialize
+if [ ! "$?" = "0" ]; then
+ exit 1
+fi
+
+#
+# Dial telephone numbers until one answers
+#
+attempt=0
+while : ; do
+ attempt=`expr $attempt + 1`
+ callall $attempt
+ if [ "$attempt" = "$MAX_ATTEMPTS" ]; then
+ exit 1
+ fi
+ sleep "$SLEEP_DELAY"
+done
diff --git a/mdk-stage1/ppp/scripts/secure-card b/mdk-stage1/ppp/scripts/secure-card
new file mode 100644
index 000000000..a32138b7d
--- /dev/null
+++ b/mdk-stage1/ppp/scripts/secure-card
@@ -0,0 +1,111 @@
+#!/usr/local/bin/expect -f
+#
+# This script was written by Jim Isaacson <jcisaac@crl.com>. It is
+# designed to work as a script to use the SecureCARD(tm) device. This
+# little device is mated with a central controller. The number displayed
+# on this card changes every so often and you need to enter the number
+# along with your user account name in order to gain access. Since chat
+# is based upon fixed strings this procedure will not work with chat.
+#
+# It is included by permission. An excellent reference for the expect
+# program used by this script is in the book:
+#
+# "Exploring Expect"
+# by Don Libes
+# Published by O'Rielly and Associates
+#
+
+send_user "hello, starting ppp\n"
+
+system "stty 19200 -echoe -echo raw < /dev/cua3 > /dev/cua3"
+
+#
+# These are the parameters for the program.
+#
+set user Pxxxxxx
+set password xxxxxxx
+set modem /dev/cua3
+set dialup <put phone number here>
+set timeout 60
+
+spawn -noecho -open [open $modem "r+"]
+
+send "AT&F\r"
+expect "OK"
+
+send "ATe0v1x4&c1q0&d2&c1s2=128s0=0DT $dialup\r"
+set timeout 15
+set counter 0
+
+set still_connecting 1
+
+expect {
+ -re ".*CONNECT.*\n" {
+ set timeout 5
+ set still_connecting 0
+ continue -expect
+ }
+ -re ".*CONNECT.*\r" {
+ set timeout 5
+ set still_connecting 0
+ continue -expect
+ }
+ -re ".*NO.*CARRIER" {
+ send_user "Failed to Connect, exiting...\n"
+ exit
+ }
+ -re ".*NO.*DIAL.*TONE" {
+ send_user "Failed to Connect, exiting...\n"
+ exit
+ }
+ -re ".*VOICE" {
+ send_user "Failed to Connect, exiting...\n"
+ exit
+ }
+ -re ".*sscode:.*\n" {
+ continue -expect
+ }
+ -re ".*sscode:" {
+ set timeout -1
+ expect_user -re "(.*)\n"
+ send "$expect_out(1,string)\r"
+ set timeout 30
+ continue -expect
+ }
+ -re ".*Next.*:" {
+ set timeout -1
+ expect_user -re "(.*)\n"
+ send "$expect_out(1,string)\r"
+ set timeout 30
+ continue -expect
+ }
+ -re "Your.*" {
+ send "\r"
+ continue -expect
+ }
+ -re ".*in:" {
+ send "$user\r"
+ continue -expect
+ }
+ -re ".*word:" {
+ send "$password\r"
+ }
+
+ timeout {
+ if { $still_connecting > 0 } {
+ continue -expect
+ }
+ set timeout 15
+ send "\r"
+ incr counter
+ if { $counter > 8 } {
+ send_user "Cannot Connect\n"
+ exit
+ } else {
+ continue -expect
+ }
+ }
+}
+
+overlay -0 $spawn_id -1 $spawn_id pppd /dev/cua3 19200 192.111.187.215: \
+ crtscts modem defaultroute debug
diff --git a/mdk-stage1/ppp/solaris/Makedefs b/mdk-stage1/ppp/solaris/Makedefs
new file mode 100644
index 000000000..81db8ab2e
--- /dev/null
+++ b/mdk-stage1/ppp/solaris/Makedefs
@@ -0,0 +1,16 @@
+#
+# defines common to several Makefiles
+#
+
+INSTALL= /usr/sbin/install
+
+BINDIR = /usr/local/bin
+MANDIR = /usr/local/man
+ETCDIR = /etc/ppp
+
+COPTS = -O -Xa
+
+# For compiling with gcc, comment out the COPTS definition above and
+# uncomment the next 2 definitions.
+#CC = gcc
+#COPTS = -O2
diff --git a/mdk-stage1/ppp/solaris/Makedefs.sol2 b/mdk-stage1/ppp/solaris/Makedefs.sol2
new file mode 100644
index 000000000..c13cb581f
--- /dev/null
+++ b/mdk-stage1/ppp/solaris/Makedefs.sol2
@@ -0,0 +1,59 @@
+#
+# Generic make definitions for Solaris 2
+#
+# $Id: Makedefs.sol2 195720 2001-06-11 11:44:34Z gc $
+#
+
+include ../solaris/Makedefs
+
+CPPFLAGS = -D_KERNEL -DSVR4 -DSOL2 -DPRIOQ -DDEBUG -I../include
+CFLAGS = $(CPPFLAGS) $(COPTS)
+
+# lint-specific variables
+LINT = lint
+LINT_OPT_32 =
+LINT_OPT_64 = -Xarch=v9 -errchk=longptr64
+
+LINT_32 =
+LINT_32 += -erroff=E_BAD_PTR_CAST_ALIGN
+LINT_32 += -erroff=E_SUPPRESSION_DIRECTIVE_UNUSED
+LINT_32 += -erroff=E_SUSPICIOUS_COMPARISON
+LINT_32 += -erroff=E_CAST_UINT_TO_SIGNED_INT
+LINT_32 += -erroff=E_PASS_UINT_TO_SIGNED_INT
+LINT_32 += -erroff=E_INVALID_ANNOTATION_NAME
+LINT_32 += -erroff=E_FUNC_ARG_UNUSED
+# This might be needed, but zlib.c and vjcompress.c will squawk
+# when not ignored
+LINT_32 += -erroff=E_CASE_FALLTHRU
+LINT_32 += -erroff=E_RET_INT_IMPLICITLY
+LINT_32 += -erroff=E_FUNC_NO_RET_VAL
+# Some STREAMS macros will be noisy too when this isn't ignored
+LINT_32 += -erroff=E_CONSTANT_CONDITION
+LINT_32 += -erroff=E_CONST_EXPR
+
+# Extra noise suppressant for 64-bit
+EXTRA_OFF =
+EXTRA_OFF += -erroff=E_CAST_INT_TO_SMALL_INT
+EXTRA_OFF += -erroff=E_CAST_INT_CONST_TO_SMALL_INT
+EXTRA_OFF += -erroff=E_CAST_TO_PTR_FROM_INT
+EXTRA_OFF += -erroff=E_ASSIGN_INT_TO_SMALL_INT
+EXTRA_OFF += -erroff=E_ASSIGN_INT_FROM_BIG_CONST
+EXTRA_OFF += -erroff=E_CONST_PROMOTED_UNSIGNED_LL
+EXTRA_OFF += -erroff=E_CONST_PROMOTED_LONG_LONG
+EXTRA_OFF += -erroff=E_CONST_TRUNCATED_BY_ASSIGN
+EXTRA_OFF += -erroff=E_PASS_INT_FROM_BIG_CONST
+EXTRA_OFF += -erroff=E_COMP_INT_WITH_LARGE_INT
+EXTRA_OFF += -erroff=E_ASSIGN_UINT_TO_SIGNED_INT
+EXTRA_OFF += -erroff=E_ASSIGN_NARROW_CONV
+EXTRA_OFF += -erroff=E_PASS_INT_TO_SMALL_INT
+EXTRA_OFF += -erroff=E_PTR_CONV_LOSES_BITS
+
+LINT_64 = $(LINT_32)
+LINT_64 += $(EXTRA_OFF)
+
+LINTFLAGS64 = -Xa -nsxmuF -errtags=yes $(LINT_OPT_64) $(LINT_64)
+LINT64 = $(LINT) -c $(LINTFLAGS64) $(CPPFLAGS)
+
+LINTFLAGS32 = -Xa -nsxmuF -errtags=yes $(LINT_OPT_32) $(LINT_32)
+LINT32 = $(LINT) -c $(LINTFLAGS32) $(CPPFLAGS)
+
diff --git a/mdk-stage1/ppp/solaris/Makefile.sol2 b/mdk-stage1/ppp/solaris/Makefile.sol2
new file mode 100644
index 000000000..d421c33a5
--- /dev/null
+++ b/mdk-stage1/ppp/solaris/Makefile.sol2
@@ -0,0 +1,66 @@
+#
+# Makefile for STREAMS modules for Solaris 2.
+#
+# $Id: Makefile.sol2 195720 2001-06-11 11:44:34Z gc $
+#
+
+include Makedefs.sol2
+
+COPTS += -xO2 -xspace -W0,-Lt
+
+COMP_OBJS = ppp_comp.o bsd-comp.o deflate.o zlib.o vjcompress.o \
+ ppp_comp_mod.o
+
+all: ppp ppp_ahdl ppp_comp
+
+ppp: ppp.o ppp_mod.o
+ ld -r -o $@ ppp.o ppp_mod.o
+ chmod +x $@
+
+ppp_ahdl: ppp_ahdlc.o ppp_ahdlc_mod.o
+ ld -r -o $@ ppp_ahdlc.o ppp_ahdlc_mod.o
+ chmod +x $@
+
+ppp_comp: $(COMP_OBJS)
+ ld -r -o $@ $(COMP_OBJS)
+ chmod +x $@
+
+bsd-comp.o: ../modules/bsd-comp.c
+ $(CC) $(CFLAGS) -c $?
+deflate.o: ../modules/deflate.c
+ $(CC) $(CFLAGS) -c $?
+ppp.o: ppp.c
+ $(CC) $(CFLAGS) -c $?
+ppp_mod.o: ppp_mod.c
+ $(CC) $(CFLAGS) -c $?
+ppp_ahdlc_mod.o: ppp_ahdlc_mod.c
+ $(CC) $(CFLAGS) -c $?
+ppp_ahdlc.o: ppp_ahdlc.c
+ $(CC) $(CFLAGS) -c $?
+ppp_comp.o: ppp_comp.c
+ $(CC) $(CFLAGS) -c $?
+ppp_comp_mod.o: ppp_comp_mod.c
+ $(CC) $(CFLAGS) -c $?
+vjcompress.o: ../modules/vjcompress.c
+ $(CC) $(CFLAGS) -c $?
+zlib.o: ../common/zlib.c
+ $(CC) $(CFLAGS) -c $?
+
+install:
+ cp ppp ppp.conf /kernel/drv
+ cp ppp_comp ppp_ahdl /kernel/strmod
+ if grep clone:ppp /etc/minor_perm; then :; else \
+ echo clone:ppp 0644 root sys >>/etc/minor_perm; fi
+ /usr/sbin/rem_drv ppp 2>/dev/null || true
+ /usr/sbin/add_drv ppp
+
+SRCS = ppp.c ppp_mod.c ppp_ahdlc.c ppp_ahdlc_mod.c \
+ ppp_comp.c ../modules/bsd-comp.c ../modules/deflate.c \
+ ../common/zlib.c ../modules/vjcompress.c ppp_comp_mod.c
+
+lint:
+ $(LINT32) $(SRCS)
+
+clean:
+ rm -f ppp ppp_comp ppp_ahdl *.o *~ core
+ rm -f *.ln
diff --git a/mdk-stage1/ppp/solaris/Makefile.sol2-64 b/mdk-stage1/ppp/solaris/Makefile.sol2-64
new file mode 100644
index 000000000..4481cdf12
--- /dev/null
+++ b/mdk-stage1/ppp/solaris/Makefile.sol2-64
@@ -0,0 +1,85 @@
+#
+# Makefile for 64-bit STREAMS modules for Solaris 2.
+#
+# $Id: Makefile.sol2-64 195720 2001-06-11 11:44:34Z gc $
+#
+
+include Makedefs.sol2
+
+# Sun's cc flag for LP64 compilation / linkage
+COPTS += -xchip=ultra -xarch=v9 -Wc,-xcode=abs32 -Wc,-Qiselect-regsym=0 -xO3 -xspace -W0,-Lt
+
+# subdirectory where 64-bit objects / binaries will be placed
+LP64DIR = sparcv9
+
+# Name of legacy Makefile (for 32-bit binaries)
+STD_MAKE = Makefile.sol2
+
+COMP_OBJS = $(LP64DIR)/ppp_comp.o $(LP64DIR)/bsd-comp.o \
+ $(LP64DIR)/deflate.o $(LP64DIR)/zlib.o $(LP64DIR)/vjcompress.o \
+ $(LP64DIR)/ppp_comp_mod.o
+
+all: std_objs $(LP64DIR) ppp ppp_ahdl ppp_comp
+
+std_objs:
+ $(MAKE) -f $(STD_MAKE) all
+
+ppp: $(LP64DIR)/ppp.o $(LP64DIR)/ppp_mod.o
+ ld -r -o $(LP64DIR)/$@ $(LP64DIR)/ppp.o $(LP64DIR)/ppp_mod.o
+ chmod +x $(LP64DIR)/$@
+
+ppp_ahdl: $(LP64DIR)/ppp_ahdlc.o $(LP64DIR)/ppp_ahdlc_mod.o
+ ld -r -o $(LP64DIR)/$@ $(LP64DIR)/ppp_ahdlc.o $(LP64DIR)/ppp_ahdlc_mod.o
+ chmod +x $(LP64DIR)/$@
+
+ppp_comp: $(COMP_OBJS)
+ ld -r -o $(LP64DIR)/$@ $(COMP_OBJS)
+ chmod +x $(LP64DIR)/$@
+
+$(LP64DIR)/bsd-comp.o: ../modules/bsd-comp.c
+ $(CC) $(CFLAGS) -c $? -o $@
+$(LP64DIR)/deflate.o: ../modules/deflate.c
+ $(CC) $(CFLAGS) -c $? -o $@
+$(LP64DIR)/ppp.o: ppp.c
+ $(CC) $(CFLAGS) -c $? -o $@
+$(LP64DIR)/ppp_mod.o: ppp_mod.c
+ $(CC) $(CFLAGS) -c $? -o $@
+$(LP64DIR)/ppp_ahdlc_mod.o: ppp_ahdlc_mod.c
+ $(CC) $(CFLAGS) -c $? -o $@
+$(LP64DIR)/ppp_ahdlc.o: ppp_ahdlc.c
+ $(CC) $(CFLAGS) -c $? -o $@
+$(LP64DIR)/ppp_comp.o: ppp_comp.c
+ $(CC) $(CFLAGS) -c $? -o $@
+$(LP64DIR)/ppp_comp_mod.o: ppp_comp_mod.c
+ $(CC) $(CFLAGS) -c $? -o $@
+$(LP64DIR)/vjcompress.o: ../modules/vjcompress.c
+ $(CC) $(CFLAGS) -c $? -o $@
+$(LP64DIR)/zlib.o: ../common/zlib.c
+ $(CC) $(CFLAGS) -c $? -o $@
+
+$(LP64DIR):
+ mkdir -m 755 -p $@
+
+install:
+ cp ppp ppp.conf /kernel/drv
+ cp ppp_comp ppp_ahdl /kernel/strmod
+ cp $(LP64DIR)/ppp /kernel/drv/$(LP64DIR)
+ cp $(LP64DIR)/ppp_comp $(LP64DIR)/ppp_ahdl /kernel/strmod/$(LP64DIR)
+ if grep clone:ppp /etc/minor_perm; then :; else \
+ echo clone:ppp 0644 root sys >>/etc/minor_perm; fi
+ /usr/sbin/rem_drv ppp 2>/dev/null || true
+ /usr/sbin/add_drv ppp
+
+SRCS = ppp.c ppp_mod.c ppp_ahdlc.c ppp_ahdlc_mod.c \
+ ppp_comp.c ../modules/bsd-comp.c ../modules/deflate.c \
+ ../common/zlib.c ../modules/vjcompress.c ppp_comp_mod.c
+
+lint:
+ $(LINT64) $(SRCS)
+
+lint-32:
+ $(LINT32) $(SRCS)
+
+clean:
+ $(MAKE) -f $(STD_MAKE) clean
+ rm -f $(LP64DIR)/ppp $(LP64DIR)/ppp_comp $(LP64DIR)/ppp_ahdl $(LP64DIR)/*.o $(LP64DIR)/*~ $(LP64DIR)/core
diff --git a/mdk-stage1/ppp/solaris/Makefile.top b/mdk-stage1/ppp/solaris/Makefile.top
new file mode 100644
index 000000000..2236866bc
--- /dev/null
+++ b/mdk-stage1/ppp/solaris/Makefile.top
@@ -0,0 +1,50 @@
+#
+# ppp top level makefile for SVR4 and Solaris 2
+#
+# $Id: Makefile.top 195720 2001-06-11 11:44:34Z gc $
+#
+
+include solaris/Makedefs
+
+all:
+ cd chat; $(MAKE) all
+ cd pppd; $(MAKE) all
+ cd pppstats; $(MAKE) all
+ cd pppdump; $(MAKE) all
+ cd solaris; $(MAKE) all
+
+install: $(BINDIR) $(MANDIR)/man8 install-progs install-etcppp
+
+install-progs:
+ cd chat; $(MAKE) install
+ cd pppd; $(MAKE) install
+ cd pppstats; $(MAKE) install
+ cd pppdump; $(MAKE) install
+ cd solaris; $(MAKE) install
+
+install-etcppp: $(ETCDIR) $(ETCDIR)/options $(ETCDIR)/pap-secrets \
+ $(ETCDIR)/chap-secrets
+
+$(ETCDIR)/options:
+ cp etc.ppp/options $@
+ chmod go-w $@
+$(ETCDIR)/pap-secrets:
+ $(INSTALL) -f $(ETCDIR) -m 600 etc.ppp/pap-secrets
+$(ETCDIR)/chap-secrets:
+ $(INSTALL) -f $(ETCDIR) -m 600 etc.ppp/chap-secrets
+
+$(BINDIR):
+ mkdir -m 755 -p $@
+$(MANDIR)/man8:
+ mkdir -m 755 -p $@
+$(ETCDIR):
+ mkdir -m 755 -p $@
+
+clean:
+ rm -f *~
+ cd chat; $(MAKE) clean
+ cd pppd; $(MAKE) clean
+ cd pppstats; $(MAKE) clean
+ cd pppdump; $(MAKE) clean
+ cd solaris; $(MAKE) clean
+
diff --git a/mdk-stage1/ppp/solaris/ppp.c b/mdk-stage1/ppp/solaris/ppp.c
new file mode 100644
index 000000000..f6d8c93df
--- /dev/null
+++ b/mdk-stage1/ppp/solaris/ppp.c
@@ -0,0 +1,2486 @@
+/*
+ * ppp.c - STREAMS multiplexing pseudo-device driver for PPP.
+ *
+ * Copyright (c) 1994 The Australian National University.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation is hereby granted, provided that the above copyright
+ * notice appears in all copies. This software is provided without any
+ * warranty, express or implied. The Australian National University
+ * makes no representations about the suitability of this software for
+ * any purpose.
+ *
+ * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
+ * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
+ * THE AUSTRALIAN NATIONAL UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
+ * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
+ * OR MODIFICATIONS.
+ *
+ * $Id: ppp.c 195720 2001-06-11 11:44:34Z gc $
+ */
+
+/*
+ * This file is used under Solaris 2, SVR4, SunOS 4, and Digital UNIX.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/stream.h>
+#include <sys/stropts.h>
+#include <sys/errno.h>
+#ifdef __osf__
+#include <sys/ioctl.h>
+#include <sys/cmn_err.h>
+#define queclass(mp) ((mp)->b_band & QPCTL)
+#else
+#include <sys/ioccom.h>
+#endif
+#include <sys/time.h>
+#ifdef SVR4
+#include <sys/cmn_err.h>
+#include <sys/conf.h>
+#include <sys/dlpi.h>
+#include <sys/ddi.h>
+#ifdef SOL2
+#include <sys/ksynch.h>
+#include <sys/kstat.h>
+#include <sys/sunddi.h>
+#include <sys/ethernet.h>
+#else
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#endif /* SOL2 */
+#else /* not SVR4 */
+#include <sys/user.h>
+#endif /* SVR4 */
+#include <net/ppp_defs.h>
+#include <net/pppio.h>
+#include "ppp_mod.h"
+
+/*
+ * Modifications marked with #ifdef PRIOQ are for priority queueing of
+ * interactive traffic, and are due to Marko Zec <zec@japa.tel.fer.hr>.
+ */
+#ifdef PRIOQ
+#endif /* PRIOQ */
+
+#include <netinet/in.h> /* leave this outside of PRIOQ for htons */
+
+#ifdef __STDC__
+#define __P(x) x
+#else
+#define __P(x) ()
+#endif
+
+/*
+ * The IP module may use this SAP value for IP packets.
+ */
+#ifndef ETHERTYPE_IP
+#define ETHERTYPE_IP 0x800
+#endif
+
+#if !defined(ETHERTYPE_IPV6)
+#define ETHERTYPE_IPV6 0x86dd
+#endif /* !defined(ETHERTYPE_IPV6) */
+
+#if !defined(ETHERTYPE_ALLSAP) && defined(SOL2)
+#define ETHERTYPE_ALLSAP 0
+#endif /* !defined(ETHERTYPE_ALLSAP) && defined(SOL2) */
+
+#if !defined(PPP_ALLSAP) && defined(SOL2)
+#define PPP_ALLSAP PPP_ALLSTATIONS
+#endif /* !defined(PPP_ALLSAP) && defined(SOL2) */
+
+extern time_t time;
+
+#ifdef SOL2
+/*
+ * We use this reader-writer lock to ensure that the lower streams
+ * stay connected to the upper streams while the lower-side put and
+ * service procedures are running. Essentially it is an existence
+ * lock for the upper stream associated with each lower stream.
+ */
+krwlock_t ppp_lower_lock;
+#define LOCK_LOWER_W rw_enter(&ppp_lower_lock, RW_WRITER)
+#define LOCK_LOWER_R rw_enter(&ppp_lower_lock, RW_READER)
+#define TRYLOCK_LOWER_R rw_tryenter(&ppp_lower_lock, RW_READER)
+#define UNLOCK_LOWER rw_exit(&ppp_lower_lock)
+
+#define MT_ENTER(x) mutex_enter(x)
+#define MT_EXIT(x) mutex_exit(x)
+
+/*
+ * Notes on multithreaded implementation for Solaris 2:
+ *
+ * We use an inner perimeter around each queue pair and an outer
+ * perimeter around the whole driver. The inner perimeter is
+ * entered exclusively for all entry points (open, close, put,
+ * service). The outer perimeter is entered exclusively for open
+ * and close and shared for put and service. This is all done for
+ * us by the streams framework.
+ *
+ * I used to think that the perimeters were entered for the lower
+ * streams' put and service routines as well as for the upper streams'.
+ * Because of problems experienced by people, and after reading the
+ * documentation more closely, I now don't think that is true. So we
+ * now use ppp_lower_lock to give us an existence guarantee on the
+ * upper stream controlling each lower stream.
+ *
+ * Shared entry to the outer perimeter protects the existence of all
+ * the upper streams and their upperstr_t structures, and guarantees
+ * that the following fields of any upperstr_t won't change:
+ * nextmn, next, nextppa. It guarantees that the lowerq field of an
+ * upperstr_t won't go from non-zero to zero, that the global `ppas'
+ * won't change and that the no lower stream will get unlinked.
+ *
+ * Shared (reader) access to ppa_lower_lock guarantees that no lower
+ * stream will be unlinked and that the lowerq field of all upperstr_t
+ * structures won't change.
+ */
+
+#else /* SOL2 */
+#define LOCK_LOWER_W 0
+#define LOCK_LOWER_R 0
+#define TRYLOCK_LOWER_R 1
+#define UNLOCK_LOWER 0
+#define MT_ENTER(x) 0
+#define MT_EXIT(x) 0
+
+#endif /* SOL2 */
+
+/*
+ * Private information; one per upper stream.
+ */
+typedef struct upperstr {
+ minor_t mn; /* minor device number */
+ struct upperstr *nextmn; /* next minor device */
+ queue_t *q; /* read q associated with this upper stream */
+ int flags; /* flag bits, see below */
+ int state; /* current DLPI state */
+ int sap; /* service access point */
+ int req_sap; /* which SAP the DLPI client requested */
+ struct upperstr *ppa; /* control stream for our ppa */
+ struct upperstr *next; /* next stream for this ppa */
+ uint ioc_id; /* last ioctl ID for this stream */
+ enum NPmode npmode; /* what to do with packets on this SAP */
+ unsigned char rblocked; /* flow control has blocked upper read strm */
+ /* N.B. rblocked is only changed by control stream's put/srv procs */
+ /*
+ * There is exactly one control stream for each PPA.
+ * The following fields are only used for control streams.
+ */
+ int ppa_id;
+ queue_t *lowerq; /* write queue attached below this PPA */
+ struct upperstr *nextppa; /* next control stream */
+ int mru;
+ int mtu;
+ struct pppstat stats; /* statistics */
+ time_t last_sent; /* time last NP packet sent */
+ time_t last_recv; /* time last NP packet rcvd */
+#ifdef SOL2
+ kmutex_t stats_lock; /* lock for stats updates */
+ kstat_t *kstats; /* stats for netstat */
+#endif /* SOL2 */
+#ifdef LACHTCP
+ int ifflags;
+ char ifname[IFNAMSIZ];
+ struct ifstats ifstats;
+#endif /* LACHTCP */
+} upperstr_t;
+
+/* Values for flags */
+#define US_PRIV 1 /* stream was opened by superuser */
+#define US_CONTROL 2 /* stream is a control stream */
+#define US_BLOCKED 4 /* flow ctrl has blocked lower write stream */
+#define US_LASTMOD 8 /* no PPP modules below us */
+#define US_DBGLOG 0x10 /* log various occurrences */
+#define US_RBLOCKED 0x20 /* flow ctrl has blocked upper read stream */
+
+#if defined(SOL2)
+#if DL_CURRENT_VERSION >= 2
+#define US_PROMISC 0x40 /* stream is promiscuous */
+#endif /* DL_CURRENT_VERSION >= 2 */
+#define US_RAWDATA 0x80 /* raw M_DATA, no DLPI header */
+#endif /* defined(SOL2) */
+
+#ifdef PRIOQ
+static u_char max_band=0;
+static u_char def_band=0;
+
+#define IPPORT_DEFAULT 65535
+
+/*
+ * Port priority table
+ * Highest priority ports are listed first, lowest are listed last.
+ * ICMP & packets using unlisted ports will be treated as "default".
+ * If IPPORT_DEFAULT is not listed here, "default" packets will be
+ * assigned lowest priority.
+ * Each line should be terminated with "0".
+ * Line containing only "0" marks the end of the list.
+ */
+
+static u_short prioq_table[]= {
+ 113, 53, 0,
+ 22, 23, 513, 517, 518, 0,
+ 514, 21, 79, 111, 0,
+ 25, 109, 110, 0,
+ IPPORT_DEFAULT, 0,
+ 20, 70, 80, 8001, 8008, 8080, 0, /* 8001,8008,8080 - common proxy ports */
+0 };
+
+#endif /* PRIOQ */
+
+
+static upperstr_t *minor_devs = NULL;
+static upperstr_t *ppas = NULL;
+
+#ifdef SVR4
+static int pppopen __P((queue_t *, dev_t *, int, int, cred_t *));
+static int pppclose __P((queue_t *, int, cred_t *));
+#else
+static int pppopen __P((queue_t *, int, int, int));
+static int pppclose __P((queue_t *, int));
+#endif /* SVR4 */
+static int pppurput __P((queue_t *, mblk_t *));
+static int pppuwput __P((queue_t *, mblk_t *));
+static int pppursrv __P((queue_t *));
+static int pppuwsrv __P((queue_t *));
+static int ppplrput __P((queue_t *, mblk_t *));
+static int ppplwput __P((queue_t *, mblk_t *));
+static int ppplrsrv __P((queue_t *));
+static int ppplwsrv __P((queue_t *));
+#ifndef NO_DLPI
+static void dlpi_request __P((queue_t *, mblk_t *, upperstr_t *));
+static void dlpi_error __P((queue_t *, upperstr_t *, int, int, int));
+static void dlpi_ok __P((queue_t *, int));
+#endif
+static int send_data __P((mblk_t *, upperstr_t *));
+static void new_ppa __P((queue_t *, mblk_t *));
+static void attach_ppa __P((queue_t *, mblk_t *));
+static void detach_ppa __P((queue_t *, mblk_t *));
+static void detach_lower __P((queue_t *, mblk_t *));
+static void debug_dump __P((queue_t *, mblk_t *));
+static upperstr_t *find_dest __P((upperstr_t *, int));
+#if defined(SOL2)
+static upperstr_t *find_promisc __P((upperstr_t *, int));
+static mblk_t *prepend_ether __P((upperstr_t *, mblk_t *, int));
+static mblk_t *prepend_udind __P((upperstr_t *, mblk_t *, int));
+static void promisc_sendup __P((upperstr_t *, mblk_t *, int, int));
+#endif /* defined(SOL2) */
+static int putctl2 __P((queue_t *, int, int, int));
+static int putctl4 __P((queue_t *, int, int, int));
+static int pass_packet __P((upperstr_t *ppa, mblk_t *mp, int outbound));
+#ifdef FILTER_PACKETS
+static int ip_hard_filter __P((upperstr_t *ppa, mblk_t *mp, int outbound));
+#endif /* FILTER_PACKETS */
+
+#define PPP_ID 0xb1a6
+static struct module_info ppp_info = {
+#ifdef PRIOQ
+ PPP_ID, "ppp", 0, 512, 512, 384
+#else
+ PPP_ID, "ppp", 0, 512, 512, 128
+#endif /* PRIOQ */
+};
+
+static struct qinit pppurint = {
+ pppurput, pppursrv, pppopen, pppclose, NULL, &ppp_info, NULL
+};
+
+static struct qinit pppuwint = {
+ pppuwput, pppuwsrv, NULL, NULL, NULL, &ppp_info, NULL
+};
+
+static struct qinit ppplrint = {
+ ppplrput, ppplrsrv, NULL, NULL, NULL, &ppp_info, NULL
+};
+
+static struct qinit ppplwint = {
+ ppplwput, ppplwsrv, NULL, NULL, NULL, &ppp_info, NULL
+};
+
+#ifdef LACHTCP
+extern struct ifstats *ifstats;
+int pppdevflag = 0;
+#endif
+
+struct streamtab pppinfo = {
+ &pppurint, &pppuwint,
+ &ppplrint, &ppplwint
+};
+
+int ppp_count;
+
+/*
+ * How we maintain statistics.
+ */
+#ifdef SOL2
+#define INCR_IPACKETS(ppa) \
+ if (ppa->kstats != 0) { \
+ KSTAT_NAMED_PTR(ppa->kstats)[0].value.ul++; \
+ }
+#define INCR_IERRORS(ppa) \
+ if (ppa->kstats != 0) { \
+ KSTAT_NAMED_PTR(ppa->kstats)[1].value.ul++; \
+ }
+#define INCR_OPACKETS(ppa) \
+ if (ppa->kstats != 0) { \
+ KSTAT_NAMED_PTR(ppa->kstats)[2].value.ul++; \
+ }
+#define INCR_OERRORS(ppa) \
+ if (ppa->kstats != 0) { \
+ KSTAT_NAMED_PTR(ppa->kstats)[3].value.ul++; \
+ }
+#endif
+
+#ifdef LACHTCP
+#define INCR_IPACKETS(ppa) ppa->ifstats.ifs_ipackets++;
+#define INCR_IERRORS(ppa) ppa->ifstats.ifs_ierrors++;
+#define INCR_OPACKETS(ppa) ppa->ifstats.ifs_opackets++;
+#define INCR_OERRORS(ppa) ppa->ifstats.ifs_oerrors++;
+#endif
+
+/*
+ * STREAMS driver entry points.
+ */
+static int
+#ifdef SVR4
+pppopen(q, devp, oflag, sflag, credp)
+ queue_t *q;
+ dev_t *devp;
+ int oflag, sflag;
+ cred_t *credp;
+#else
+pppopen(q, dev, oflag, sflag)
+ queue_t *q;
+ int dev; /* really dev_t */
+ int oflag, sflag;
+#endif
+{
+ upperstr_t *up;
+ upperstr_t **prevp;
+ minor_t mn;
+#ifdef PRIOQ
+ u_short *ptr;
+ u_char new_band;
+#endif /* PRIOQ */
+
+ if (q->q_ptr)
+ DRV_OPEN_OK(dev); /* device is already open */
+
+#ifdef PRIOQ
+ /* Calculate max_bband & def_band from definitions in prioq.h
+ This colud be done at some more approtiate time (less often)
+ but this way it works well so I'll just leave it here */
+
+ max_band = 1;
+ def_band = 0;
+ ptr = prioq_table;
+ while (*ptr) {
+ new_band = 1;
+ while (*ptr)
+ if (*ptr++ == IPPORT_DEFAULT) {
+ new_band = 0;
+ def_band = max_band;
+ }
+ max_band += new_band;
+ ptr++;
+ }
+ if (def_band)
+ def_band = max_band - def_band;
+ --max_band;
+#endif /* PRIOQ */
+
+ if (sflag == CLONEOPEN) {
+ mn = 0;
+ for (prevp = &minor_devs; (up = *prevp) != 0; prevp = &up->nextmn) {
+ if (up->mn != mn)
+ break;
+ ++mn;
+ }
+ } else {
+#ifdef SVR4
+ mn = getminor(*devp);
+#else
+ mn = minor(dev);
+#endif
+ for (prevp = &minor_devs; (up = *prevp) != 0; prevp = &up->nextmn) {
+ if (up->mn >= mn)
+ break;
+ }
+ if (up->mn == mn) {
+ /* this can't happen */
+ q->q_ptr = WR(q)->q_ptr = (caddr_t) up;
+ DRV_OPEN_OK(dev);
+ }
+ }
+
+ /*
+ * Construct a new minor node.
+ */
+ up = (upperstr_t *) ALLOC_SLEEP(sizeof(upperstr_t));
+ bzero((caddr_t) up, sizeof(upperstr_t));
+ if (up == 0) {
+ DPRINT("pppopen: out of kernel memory\n");
+ OPEN_ERROR(ENXIO);
+ }
+ up->nextmn = *prevp;
+ *prevp = up;
+ up->mn = mn;
+#ifdef SVR4
+ *devp = makedevice(getmajor(*devp), mn);
+#endif
+ up->q = q;
+ if (NOTSUSER() == 0)
+ up->flags |= US_PRIV;
+#ifndef NO_DLPI
+ up->state = DL_UNATTACHED;
+#endif
+#ifdef LACHTCP
+ up->ifflags = IFF_UP | IFF_POINTOPOINT;
+#endif
+ up->sap = -1;
+ up->last_sent = up->last_recv = time;
+ up->npmode = NPMODE_DROP;
+ q->q_ptr = (caddr_t) up;
+ WR(q)->q_ptr = (caddr_t) up;
+ noenable(WR(q));
+#ifdef SOL2
+ mutex_init(&up->stats_lock, NULL, MUTEX_DRIVER, NULL);
+#endif
+ ++ppp_count;
+
+ qprocson(q);
+ DRV_OPEN_OK(makedev(major(dev), mn));
+}
+
+static int
+#ifdef SVR4
+pppclose(q, flag, credp)
+ queue_t *q;
+ int flag;
+ cred_t *credp;
+#else
+pppclose(q, flag)
+ queue_t *q;
+ int flag;
+#endif
+{
+ upperstr_t *up, **upp;
+ upperstr_t *as, *asnext;
+ upperstr_t **prevp;
+
+ qprocsoff(q);
+
+ up = (upperstr_t *) q->q_ptr;
+ if (up == 0) {
+ DPRINT("pppclose: q_ptr = 0\n");
+ return 0;
+ }
+ if (up->flags & US_DBGLOG)
+ DPRINT2("ppp/%d: close, flags=%x\n", up->mn, up->flags);
+ if (up->flags & US_CONTROL) {
+#ifdef LACHTCP
+ struct ifstats *ifp, *pifp;
+#endif
+ if (up->lowerq != 0) {
+ /* Gack! the lower stream should have be unlinked earlier! */
+ DPRINT1("ppp%d: lower stream still connected on close?\n",
+ up->mn);
+ LOCK_LOWER_W;
+ up->lowerq->q_ptr = 0;
+ RD(up->lowerq)->q_ptr = 0;
+ up->lowerq = 0;
+ UNLOCK_LOWER;
+ }
+
+ /*
+ * This stream represents a PPA:
+ * For all streams attached to the PPA, clear their
+ * references to this PPA.
+ * Then remove this PPA from the list of PPAs.
+ */
+ for (as = up->next; as != 0; as = asnext) {
+ asnext = as->next;
+ as->next = 0;
+ as->ppa = 0;
+ if (as->flags & US_BLOCKED) {
+ as->flags &= ~US_BLOCKED;
+ flushq(WR(as->q), FLUSHDATA);
+ }
+ }
+ for (upp = &ppas; *upp != 0; upp = &(*upp)->nextppa)
+ if (*upp == up) {
+ *upp = up->nextppa;
+ break;
+ }
+#ifdef LACHTCP
+ /* Remove the statistics from the active list. */
+ for (ifp = ifstats, pifp = 0; ifp; ifp = ifp->ifs_next) {
+ if (ifp == &up->ifstats) {
+ if (pifp)
+ pifp->ifs_next = ifp->ifs_next;
+ else
+ ifstats = ifp->ifs_next;
+ break;
+ }
+ pifp = ifp;
+ }
+#endif
+ } else {
+ /*
+ * If this stream is attached to a PPA,
+ * remove it from the PPA's list.
+ */
+ if ((as = up->ppa) != 0) {
+ for (; as->next != 0; as = as->next)
+ if (as->next == up) {
+ as->next = up->next;
+ break;
+ }
+ }
+ }
+
+#ifdef SOL2
+ if (up->kstats)
+ kstat_delete(up->kstats);
+ mutex_destroy(&up->stats_lock);
+#endif
+
+ q->q_ptr = NULL;
+ WR(q)->q_ptr = NULL;
+
+ for (prevp = &minor_devs; *prevp != 0; prevp = &(*prevp)->nextmn) {
+ if (*prevp == up) {
+ *prevp = up->nextmn;
+ break;
+ }
+ }
+ FREE(up, sizeof(upperstr_t));
+ --ppp_count;
+
+ return 0;
+}
+
+/*
+ * A message from on high. We do one of three things:
+ * - qreply()
+ * - put the message on the lower write stream
+ * - queue it for our service routine
+ */
+static int
+pppuwput(q, mp)
+ queue_t *q;
+ mblk_t *mp;
+{
+ upperstr_t *us, *ppa, *nps;
+ struct iocblk *iop;
+ struct linkblk *lb;
+#ifdef LACHTCP
+ struct ifreq *ifr;
+ int i;
+#endif
+ queue_t *lq;
+ int error, n, sap;
+ mblk_t *mq;
+ struct ppp_idle *pip;
+#ifdef PRIOQ
+ queue_t *tlq;
+#endif /* PRIOQ */
+#ifdef NO_DLPI
+ upperstr_t *os;
+#endif
+
+ us = (upperstr_t *) q->q_ptr;
+ if (us == 0) {
+ DPRINT("pppuwput: q_ptr = 0!\n");
+ return 0;
+ }
+ if (mp == 0) {
+ DPRINT1("pppuwput/%d: mp = 0!\n", us->mn);
+ return 0;
+ }
+ if (mp->b_datap == 0) {
+ DPRINT1("pppuwput/%d: mp->b_datap = 0!\n", us->mn);
+ return 0;
+ }
+ switch (mp->b_datap->db_type) {
+#ifndef NO_DLPI
+ case M_PCPROTO:
+ case M_PROTO:
+ dlpi_request(q, mp, us);
+ break;
+#endif /* NO_DLPI */
+
+ case M_DATA:
+ if (us->flags & US_DBGLOG)
+ DPRINT3("ppp/%d: uwput M_DATA len=%d flags=%x\n",
+ us->mn, msgdsize(mp), us->flags);
+ if (us->ppa == 0 || msgdsize(mp) > us->ppa->mtu + PPP_HDRLEN
+#ifndef NO_DLPI
+ || (us->flags & US_CONTROL) == 0
+#endif /* NO_DLPI */
+ ) {
+ DPRINT1("pppuwput: junk data len=%d\n", msgdsize(mp));
+ freemsg(mp);
+ break;
+ }
+#ifdef NO_DLPI
+ if ((us->flags & US_CONTROL) == 0 && !pass_packet(us, mp, 1))
+ break;
+#endif
+ if (!send_data(mp, us))
+ putq(q, mp);
+ break;
+
+ case M_IOCTL:
+ iop = (struct iocblk *) mp->b_rptr;
+ error = EINVAL;
+ if (us->flags & US_DBGLOG)
+ DPRINT3("ppp/%d: ioctl %x count=%d\n",
+ us->mn, iop->ioc_cmd, iop->ioc_count);
+ switch (iop->ioc_cmd) {
+#if defined(SOL2)
+ case DLIOCRAW: /* raw M_DATA mode */
+ us->flags |= US_RAWDATA;
+ error = 0;
+ break;
+#endif /* defined(SOL2) */
+ case I_LINK:
+ if ((us->flags & US_CONTROL) == 0 || us->lowerq != 0)
+ break;
+ if (mp->b_cont == 0) {
+ DPRINT1("pppuwput/%d: ioctl I_LINK b_cont = 0!\n", us->mn);
+ break;
+ }
+ lb = (struct linkblk *) mp->b_cont->b_rptr;
+ lq = lb->l_qbot;
+ if (lq == 0) {
+ DPRINT1("pppuwput/%d: ioctl I_LINK l_qbot = 0!\n", us->mn);
+ break;
+ }
+ LOCK_LOWER_W;
+ us->lowerq = lq;
+ lq->q_ptr = (caddr_t) q;
+ RD(lq)->q_ptr = (caddr_t) us->q;
+ UNLOCK_LOWER;
+ iop->ioc_count = 0;
+ error = 0;
+ us->flags &= ~US_LASTMOD;
+ /* Unblock upper streams which now feed this lower stream. */
+ qenable(q);
+ /* Send useful information down to the modules which
+ are now linked below us. */
+ putctl2(lq, M_CTL, PPPCTL_UNIT, us->ppa_id);
+ putctl4(lq, M_CTL, PPPCTL_MRU, us->mru);
+ putctl4(lq, M_CTL, PPPCTL_MTU, us->mtu);
+#ifdef PRIOQ
+ /* Lower tty driver's queue hiwat/lowat from default 4096/128
+ to 256/128 since we don't want queueing of data on
+ output to physical device */
+
+ freezestr(lq);
+ for (tlq = lq; tlq->q_next != NULL; tlq = tlq->q_next)
+ ;
+ strqset(tlq, QHIWAT, 0, 256);
+ strqset(tlq, QLOWAT, 0, 128);
+ unfreezestr(lq);
+#endif /* PRIOQ */
+ break;
+
+ case I_UNLINK:
+ if (mp->b_cont == 0) {
+ DPRINT1("pppuwput/%d: ioctl I_UNLINK b_cont = 0!\n", us->mn);
+ break;
+ }
+ lb = (struct linkblk *) mp->b_cont->b_rptr;
+#if DEBUG
+ if (us->lowerq != lb->l_qbot) {
+ DPRINT2("ppp unlink: lowerq=%x qbot=%x\n",
+ us->lowerq, lb->l_qbot);
+ break;
+ }
+#endif
+ iop->ioc_count = 0;
+ qwriter(q, mp, detach_lower, PERIM_OUTER);
+ error = -1;
+ break;
+
+ case PPPIO_NEWPPA:
+ if (us->flags & US_CONTROL)
+ break;
+ if ((us->flags & US_PRIV) == 0) {
+ error = EPERM;
+ break;
+ }
+ /* Arrange to return an int */
+ if ((mq = mp->b_cont) == 0
+ || mq->b_datap->db_lim - mq->b_rptr < sizeof(int)) {
+ mq = allocb(sizeof(int), BPRI_HI);
+ if (mq == 0) {
+ error = ENOSR;
+ break;
+ }
+ if (mp->b_cont != 0)
+ freemsg(mp->b_cont);
+ mp->b_cont = mq;
+ mq->b_cont = 0;
+ }
+ iop->ioc_count = sizeof(int);
+ mq->b_wptr = mq->b_rptr + sizeof(int);
+ qwriter(q, mp, new_ppa, PERIM_OUTER);
+ error = -1;
+ break;
+
+ case PPPIO_ATTACH:
+ /* like dlpi_attach, for programs which can't write to
+ the stream (like pppstats) */
+ if (iop->ioc_count != sizeof(int) || us->ppa != 0)
+ break;
+ if (mp->b_cont == 0) {
+ DPRINT1("pppuwput/%d: ioctl PPPIO_ATTACH b_cont = 0!\n", us->mn);
+ break;
+ }
+ n = *(int *)mp->b_cont->b_rptr;
+ for (ppa = ppas; ppa != 0; ppa = ppa->nextppa)
+ if (ppa->ppa_id == n)
+ break;
+ if (ppa == 0)
+ break;
+ us->ppa = ppa;
+ iop->ioc_count = 0;
+ qwriter(q, mp, attach_ppa, PERIM_OUTER);
+ error = -1;
+ break;
+
+#ifdef NO_DLPI
+ case PPPIO_BIND:
+ /* Attach to a given SAP. */
+ if (iop->ioc_count != sizeof(int) || us->ppa == 0)
+ break;
+ if (mp->b_cont == 0) {
+ DPRINT1("pppuwput/%d: ioctl PPPIO_BIND b_cont = 0!\n", us->mn);
+ break;
+ }
+ n = *(int *)mp->b_cont->b_rptr;
+ /* n must be a valid PPP network protocol number. */
+ if (n < 0x21 || n > 0x3fff || (n & 0x101) != 1)
+ break;
+ /* check that no other stream is bound to this sap already. */
+ for (os = us->ppa; os != 0; os = os->next)
+ if (os->sap == n)
+ break;
+ if (os != 0)
+ break;
+ us->sap = n;
+ iop->ioc_count = 0;
+ error = 0;
+ break;
+#endif /* NO_DLPI */
+
+ case PPPIO_MRU:
+ if (iop->ioc_count != sizeof(int) || (us->flags & US_CONTROL) == 0)
+ break;
+ if (mp->b_cont == 0) {
+ DPRINT1("pppuwput/%d: ioctl PPPIO_MRU b_cont = 0!\n", us->mn);
+ break;
+ }
+ n = *(int *)mp->b_cont->b_rptr;
+ if (n <= 0 || n > PPP_MAXMRU)
+ break;
+ if (n < PPP_MRU)
+ n = PPP_MRU;
+ us->mru = n;
+ if (us->lowerq)
+ putctl4(us->lowerq, M_CTL, PPPCTL_MRU, n);
+ error = 0;
+ iop->ioc_count = 0;
+ break;
+
+ case PPPIO_MTU:
+ if (iop->ioc_count != sizeof(int) || (us->flags & US_CONTROL) == 0)
+ break;
+ if (mp->b_cont == 0) {
+ DPRINT1("pppuwput/%d: ioctl PPPIO_MTU b_cont = 0!\n", us->mn);
+ break;
+ }
+ n = *(int *)mp->b_cont->b_rptr;
+ if (n <= 0 || n > PPP_MAXMTU)
+ break;
+ us->mtu = n;
+#ifdef LACHTCP
+ /* The MTU reported in netstat, not used as IP max packet size! */
+ us->ifstats.ifs_mtu = n;
+#endif
+ if (us->lowerq)
+ putctl4(us->lowerq, M_CTL, PPPCTL_MTU, n);
+ error = 0;
+ iop->ioc_count = 0;
+ break;
+
+ case PPPIO_LASTMOD:
+ us->flags |= US_LASTMOD;
+ error = 0;
+ break;
+
+ case PPPIO_DEBUG:
+ if (iop->ioc_count != sizeof(int))
+ break;
+ if (mp->b_cont == 0) {
+ DPRINT1("pppuwput/%d: ioctl PPPIO_DEBUG b_cont = 0!\n", us->mn);
+ break;
+ }
+ n = *(int *)mp->b_cont->b_rptr;
+ if (n == PPPDBG_DUMP + PPPDBG_DRIVER) {
+ qwriter(q, NULL, debug_dump, PERIM_OUTER);
+ iop->ioc_count = 0;
+ error = -1;
+ } else if (n == PPPDBG_LOG + PPPDBG_DRIVER) {
+ DPRINT1("ppp/%d: debug log enabled\n", us->mn);
+ us->flags |= US_DBGLOG;
+ iop->ioc_count = 0;
+ error = 0;
+ } else {
+ if (us->ppa == 0 || us->ppa->lowerq == 0)
+ break;
+ putnext(us->ppa->lowerq, mp);
+ error = -1;
+ }
+ break;
+
+ case PPPIO_NPMODE:
+ if (iop->ioc_count != 2 * sizeof(int))
+ break;
+ if ((us->flags & US_CONTROL) == 0)
+ break;
+ if (mp->b_cont == 0) {
+ DPRINT1("pppuwput/%d: ioctl PPPIO_NPMODE b_cont = 0!\n", us->mn);
+ break;
+ }
+ sap = ((int *)mp->b_cont->b_rptr)[0];
+ for (nps = us->next; nps != 0; nps = nps->next) {
+ if (us->flags & US_DBGLOG)
+ DPRINT2("us = 0x%x, us->next->sap = 0x%x\n", nps, nps->sap);
+ if (nps->sap == sap)
+ break;
+ }
+ if (nps == 0) {
+ if (us->flags & US_DBGLOG)
+ DPRINT2("ppp/%d: no stream for sap %x\n", us->mn, sap);
+ break;
+ }
+ /* XXX possibly should use qwriter here */
+ nps->npmode = (enum NPmode) ((int *)mp->b_cont->b_rptr)[1];
+ if (nps->npmode != NPMODE_QUEUE && (nps->flags & US_BLOCKED) != 0)
+ qenable(WR(nps->q));
+ iop->ioc_count = 0;
+ error = 0;
+ break;
+
+ case PPPIO_GIDLE:
+ if ((ppa = us->ppa) == 0)
+ break;
+ mq = allocb(sizeof(struct ppp_idle), BPRI_HI);
+ if (mq == 0) {
+ error = ENOSR;
+ break;
+ }
+ if (mp->b_cont != 0)
+ freemsg(mp->b_cont);
+ mp->b_cont = mq;
+ mq->b_cont = 0;
+ pip = (struct ppp_idle *) mq->b_wptr;
+ pip->xmit_idle = time - ppa->last_sent;
+ pip->recv_idle = time - ppa->last_recv;
+ mq->b_wptr += sizeof(struct ppp_idle);
+ iop->ioc_count = sizeof(struct ppp_idle);
+ error = 0;
+ break;
+
+#ifdef LACHTCP
+ case SIOCSIFNAME:
+ /* Sent from IP down to us. Attach the ifstats structure. */
+ if (iop->ioc_count != sizeof(struct ifreq) || us->ppa == 0)
+ break;
+ ifr = (struct ifreq *)mp->b_cont->b_rptr;
+ /* Find the unit number in the interface name. */
+ for (i = 0; i < IFNAMSIZ; i++) {
+ if (ifr->ifr_name[i] == 0 ||
+ (ifr->ifr_name[i] >= '0' &&
+ ifr->ifr_name[i] <= '9'))
+ break;
+ else
+ us->ifname[i] = ifr->ifr_name[i];
+ }
+ us->ifname[i] = 0;
+
+ /* Convert the unit number to binary. */
+ for (n = 0; i < IFNAMSIZ; i++) {
+ if (ifr->ifr_name[i] == 0) {
+ break;
+ }
+ else {
+ n = n * 10 + ifr->ifr_name[i] - '0';
+ }
+ }
+
+ /* Verify the ppa. */
+ if (us->ppa->ppa_id != n)
+ break;
+ ppa = us->ppa;
+
+ /* Set up the netstat block. */
+ strncpy (ppa->ifname, us->ifname, IFNAMSIZ);
+
+ ppa->ifstats.ifs_name = ppa->ifname;
+ ppa->ifstats.ifs_unit = n;
+ ppa->ifstats.ifs_active = us->state != DL_UNBOUND;
+ ppa->ifstats.ifs_mtu = ppa->mtu;
+
+ /* Link in statistics used by netstat. */
+ ppa->ifstats.ifs_next = ifstats;
+ ifstats = &ppa->ifstats;
+
+ iop->ioc_count = 0;
+ error = 0;
+ break;
+
+ case SIOCGIFFLAGS:
+ if (!(us->flags & US_CONTROL)) {
+ if (us->ppa)
+ us = us->ppa;
+ else
+ break;
+ }
+ ((struct iocblk_in *)iop)->ioc_ifflags = us->ifflags;
+ error = 0;
+ break;
+
+ case SIOCSIFFLAGS:
+ if (!(us->flags & US_CONTROL)) {
+ if (us->ppa)
+ us = us->ppa;
+ else
+ break;
+ }
+ us->ifflags = ((struct iocblk_in *)iop)->ioc_ifflags;
+ error = 0;
+ break;
+
+ case SIOCSIFADDR:
+ if (!(us->flags & US_CONTROL)) {
+ if (us->ppa)
+ us = us->ppa;
+ else
+ break;
+ }
+ us->ifflags |= IFF_RUNNING;
+ ((struct iocblk_in *)iop)->ioc_ifflags |= IFF_RUNNING;
+ error = 0;
+ break;
+
+ case SIOCSIFMTU:
+ /*
+ * Vanilla SVR4 systems don't handle SIOCSIFMTU, rather
+ * they take the MTU from the DL_INFO_ACK we sent in response
+ * to their DL_INFO_REQ. Fortunately, they will update the
+ * MTU if we send an unsolicited DL_INFO_ACK up.
+ */
+ if ((mq = allocb(sizeof(dl_info_req_t), BPRI_HI)) == 0)
+ break; /* should do bufcall */
+ ((union DL_primitives *)mq->b_rptr)->dl_primitive = DL_INFO_REQ;
+ mq->b_wptr = mq->b_rptr + sizeof(dl_info_req_t);
+ dlpi_request(q, mq, us);
+ error = 0;
+ break;
+
+ case SIOCGIFNETMASK:
+ case SIOCSIFNETMASK:
+ case SIOCGIFADDR:
+ case SIOCGIFDSTADDR:
+ case SIOCSIFDSTADDR:
+ case SIOCGIFMETRIC:
+ error = 0;
+ break;
+#endif /* LACHTCP */
+
+ default:
+ if (us->ppa == 0 || us->ppa->lowerq == 0)
+ break;
+ us->ioc_id = iop->ioc_id;
+ error = -1;
+ switch (iop->ioc_cmd) {
+ case PPPIO_GETSTAT:
+ case PPPIO_GETCSTAT:
+ if (us->flags & US_LASTMOD) {
+ error = EINVAL;
+ break;
+ }
+ putnext(us->ppa->lowerq, mp);
+ break;
+ default:
+ if (us->flags & US_PRIV)
+ putnext(us->ppa->lowerq, mp);
+ else {
+ DPRINT1("ppp ioctl %x rejected\n", iop->ioc_cmd);
+ error = EPERM;
+ }
+ break;
+ }
+ break;
+ }
+
+ if (error > 0) {
+ iop->ioc_error = error;
+ mp->b_datap->db_type = M_IOCNAK;
+ qreply(q, mp);
+ } else if (error == 0) {
+ mp->b_datap->db_type = M_IOCACK;
+ qreply(q, mp);
+ }
+ break;
+
+ case M_FLUSH:
+ if (us->flags & US_DBGLOG)
+ DPRINT2("ppp/%d: flush %x\n", us->mn, *mp->b_rptr);
+ if (*mp->b_rptr & FLUSHW)
+ flushq(q, FLUSHDATA);
+ if (*mp->b_rptr & FLUSHR) {
+ *mp->b_rptr &= ~FLUSHW;
+ qreply(q, mp);
+ } else
+ freemsg(mp);
+ break;
+
+ default:
+ freemsg(mp);
+ break;
+ }
+ return 0;
+}
+
+#ifndef NO_DLPI
+static void
+dlpi_request(q, mp, us)
+ queue_t *q;
+ mblk_t *mp;
+ upperstr_t *us;
+{
+ union DL_primitives *d = (union DL_primitives *) mp->b_rptr;
+ int size = mp->b_wptr - mp->b_rptr;
+ mblk_t *reply, *np;
+ upperstr_t *ppa, *os;
+ int sap, len;
+ dl_info_ack_t *info;
+ dl_bind_ack_t *ackp;
+#if DL_CURRENT_VERSION >= 2
+ dl_phys_addr_ack_t *paddrack;
+ static struct ether_addr eaddr = {0};
+#endif
+
+ if (us->flags & US_DBGLOG)
+ DPRINT3("ppp/%d: dlpi prim %x len=%d\n", us->mn,
+ d->dl_primitive, size);
+ switch (d->dl_primitive) {
+ case DL_INFO_REQ:
+ if (size < sizeof(dl_info_req_t))
+ goto badprim;
+ if ((reply = allocb(sizeof(dl_info_ack_t), BPRI_HI)) == 0)
+ break; /* should do bufcall */
+ reply->b_datap->db_type = M_PCPROTO;
+ info = (dl_info_ack_t *) reply->b_wptr;
+ reply->b_wptr += sizeof(dl_info_ack_t);
+ bzero((caddr_t) info, sizeof(dl_info_ack_t));
+ info->dl_primitive = DL_INFO_ACK;
+ info->dl_max_sdu = us->ppa? us->ppa->mtu: PPP_MAXMTU;
+ info->dl_min_sdu = 1;
+ info->dl_addr_length = sizeof(uint);
+ info->dl_mac_type = DL_ETHER; /* a bigger lie */
+ info->dl_current_state = us->state;
+ info->dl_service_mode = DL_CLDLS;
+ info->dl_provider_style = DL_STYLE2;
+#if DL_CURRENT_VERSION >= 2
+ info->dl_sap_length = sizeof(uint);
+ info->dl_version = DL_CURRENT_VERSION;
+#endif
+ qreply(q, reply);
+ break;
+
+ case DL_ATTACH_REQ:
+ if (size < sizeof(dl_attach_req_t))
+ goto badprim;
+ if (us->state != DL_UNATTACHED || us->ppa != 0) {
+ dlpi_error(q, us, DL_ATTACH_REQ, DL_OUTSTATE, 0);
+ break;
+ }
+ for (ppa = ppas; ppa != 0; ppa = ppa->nextppa)
+ if (ppa->ppa_id == d->attach_req.dl_ppa)
+ break;
+ if (ppa == 0) {
+ dlpi_error(q, us, DL_ATTACH_REQ, DL_BADPPA, 0);
+ break;
+ }
+ us->ppa = ppa;
+ qwriter(q, mp, attach_ppa, PERIM_OUTER);
+ return;
+
+ case DL_DETACH_REQ:
+ if (size < sizeof(dl_detach_req_t))
+ goto badprim;
+ if (us->state != DL_UNBOUND || us->ppa == 0) {
+ dlpi_error(q, us, DL_DETACH_REQ, DL_OUTSTATE, 0);
+ break;
+ }
+ qwriter(q, mp, detach_ppa, PERIM_OUTER);
+ return;
+
+ case DL_BIND_REQ:
+ if (size < sizeof(dl_bind_req_t))
+ goto badprim;
+ if (us->state != DL_UNBOUND || us->ppa == 0) {
+ dlpi_error(q, us, DL_BIND_REQ, DL_OUTSTATE, 0);
+ break;
+ }
+#if 0
+ /* apparently this test fails (unnecessarily?) on some systems */
+ if (d->bind_req.dl_service_mode != DL_CLDLS) {
+ dlpi_error(q, us, DL_BIND_REQ, DL_UNSUPPORTED, 0);
+ break;
+ }
+#endif
+
+ /* saps must be valid PPP network protocol numbers,
+ except that we accept ETHERTYPE_IP in place of PPP_IP. */
+ sap = d->bind_req.dl_sap;
+ us->req_sap = sap;
+
+#if defined(SOL2)
+ if (us->flags & US_DBGLOG)
+ DPRINT2("DL_BIND_REQ: ip gives sap = 0x%x, us = 0x%x", sap, us);
+
+ if (sap == ETHERTYPE_IP) /* normal IFF_IPV4 */
+ sap = PPP_IP;
+ else if (sap == ETHERTYPE_IPV6) /* when IFF_IPV6 is set */
+ sap = PPP_IPV6;
+ else if (sap == ETHERTYPE_ALLSAP) /* snoop gives sap of 0 */
+ sap = PPP_ALLSAP;
+ else {
+ DPRINT2("DL_BIND_REQ: unrecognized sap = 0x%x, us = 0x%x", sap, us);
+ dlpi_error(q, us, DL_BIND_REQ, DL_BADADDR, 0);
+ break;
+ }
+#else
+ if (sap == ETHERTYPE_IP)
+ sap = PPP_IP;
+ if (sap < 0x21 || sap > 0x3fff || (sap & 0x101) != 1) {
+ dlpi_error(q, us, DL_BIND_REQ, DL_BADADDR, 0);
+ break;
+ }
+#endif /* defined(SOL2) */
+
+ /* check that no other stream is bound to this sap already. */
+ for (os = us->ppa; os != 0; os = os->next)
+ if (os->sap == sap)
+ break;
+ if (os != 0) {
+ dlpi_error(q, us, DL_BIND_REQ, DL_NOADDR, 0);
+ break;
+ }
+
+ us->sap = sap;
+ us->state = DL_IDLE;
+
+ if ((reply = allocb(sizeof(dl_bind_ack_t) + sizeof(uint),
+ BPRI_HI)) == 0)
+ break; /* should do bufcall */
+ ackp = (dl_bind_ack_t *) reply->b_wptr;
+ reply->b_wptr += sizeof(dl_bind_ack_t) + sizeof(uint);
+ reply->b_datap->db_type = M_PCPROTO;
+ bzero((caddr_t) ackp, sizeof(dl_bind_ack_t));
+ ackp->dl_primitive = DL_BIND_ACK;
+ ackp->dl_sap = sap;
+ ackp->dl_addr_length = sizeof(uint);
+ ackp->dl_addr_offset = sizeof(dl_bind_ack_t);
+ *(uint *)(ackp+1) = sap;
+ qreply(q, reply);
+ break;
+
+ case DL_UNBIND_REQ:
+ if (size < sizeof(dl_unbind_req_t))
+ goto badprim;
+ if (us->state != DL_IDLE) {
+ dlpi_error(q, us, DL_UNBIND_REQ, DL_OUTSTATE, 0);
+ break;
+ }
+ us->sap = -1;
+ us->state = DL_UNBOUND;
+#ifdef LACHTCP
+ us->ppa->ifstats.ifs_active = 0;
+#endif
+ dlpi_ok(q, DL_UNBIND_REQ);
+ break;
+
+ case DL_UNITDATA_REQ:
+ if (size < sizeof(dl_unitdata_req_t))
+ goto badprim;
+ if (us->state != DL_IDLE) {
+ dlpi_error(q, us, DL_UNITDATA_REQ, DL_OUTSTATE, 0);
+ break;
+ }
+ if ((ppa = us->ppa) == 0) {
+ cmn_err(CE_CONT, "ppp: in state dl_idle but ppa == 0?\n");
+ break;
+ }
+ len = mp->b_cont == 0? 0: msgdsize(mp->b_cont);
+ if (len > ppa->mtu) {
+ DPRINT2("dlpi data too large (%d > %d)\n", len, ppa->mtu);
+ break;
+ }
+
+#if defined(SOL2)
+ /*
+ * Should there be any promiscuous stream(s), send the data
+ * up for each promiscuous stream that we recognize.
+ */
+ if (mp->b_cont)
+ promisc_sendup(ppa, mp->b_cont, us->sap, 0);
+#endif /* defined(SOL2) */
+
+ mp->b_band = 0;
+#ifdef PRIOQ
+ /* Extract s_port & d_port from IP-packet, the code is a bit
+ dirty here, but so am I, too... */
+ if (mp->b_datap->db_type == M_PROTO && us->sap == PPP_IP
+ && mp->b_cont != 0) {
+ u_char *bb, *tlh;
+ int iphlen, len;
+ u_short *ptr;
+ u_char band_unset, cur_band, syn;
+ u_short s_port, d_port;
+
+ bb = mp->b_cont->b_rptr; /* bb points to IP-header*/
+ len = mp->b_cont->b_wptr - mp->b_cont->b_rptr;
+ syn = 0;
+ s_port = IPPORT_DEFAULT;
+ d_port = IPPORT_DEFAULT;
+ if (len >= 20) { /* 20 = minimum length of IP header */
+ iphlen = (bb[0] & 0x0f) * 4;
+ tlh = bb + iphlen;
+ len -= iphlen;
+ switch (bb[9]) {
+ case IPPROTO_TCP:
+ if (len >= 20) { /* min length of TCP header */
+ s_port = (tlh[0] << 8) + tlh[1];
+ d_port = (tlh[2] << 8) + tlh[3];
+ syn = tlh[13] & 0x02;
+ }
+ break;
+ case IPPROTO_UDP:
+ if (len >= 8) { /* min length of UDP header */
+ s_port = (tlh[0] << 8) + tlh[1];
+ d_port = (tlh[2] << 8) + tlh[3];
+ }
+ break;
+ }
+ }
+
+ /*
+ * Now calculate b_band for this packet from the
+ * port-priority table.
+ */
+ ptr = prioq_table;
+ cur_band = max_band;
+ band_unset = 1;
+ while (*ptr) {
+ while (*ptr && band_unset)
+ if (s_port == *ptr || d_port == *ptr++) {
+ mp->b_band = cur_band;
+ band_unset = 0;
+ break;
+ }
+ ptr++;
+ cur_band--;
+ }
+ if (band_unset)
+ mp->b_band = def_band;
+ /* It may be usable to urge SYN packets a bit */
+ if (syn)
+ mp->b_band++;
+ }
+#endif /* PRIOQ */
+ /* this assumes PPP_HDRLEN <= sizeof(dl_unitdata_req_t) */
+ if (mp->b_datap->db_ref > 1) {
+ np = allocb(PPP_HDRLEN, BPRI_HI);
+ if (np == 0)
+ break; /* gak! */
+ np->b_cont = mp->b_cont;
+ mp->b_cont = 0;
+ freeb(mp);
+ mp = np;
+ } else
+ mp->b_datap->db_type = M_DATA;
+ /* XXX should use dl_dest_addr_offset/length here,
+ but we would have to translate ETHERTYPE_IP -> PPP_IP */
+ mp->b_wptr = mp->b_rptr + PPP_HDRLEN;
+ mp->b_rptr[0] = PPP_ALLSTATIONS;
+ mp->b_rptr[1] = PPP_UI;
+ mp->b_rptr[2] = us->sap >> 8;
+ mp->b_rptr[3] = us->sap;
+ if (pass_packet(us, mp, 1)) {
+ if (!send_data(mp, us))
+ putq(q, mp);
+ }
+ return;
+
+#if DL_CURRENT_VERSION >= 2
+ case DL_PHYS_ADDR_REQ:
+ if (size < sizeof(dl_phys_addr_req_t))
+ goto badprim;
+
+ /*
+ * Don't check state because ifconfig sends this one down too
+ */
+
+ if ((reply = allocb(sizeof(dl_phys_addr_ack_t)+ETHERADDRL,
+ BPRI_HI)) == 0)
+ break; /* should do bufcall */
+ reply->b_datap->db_type = M_PCPROTO;
+ paddrack = (dl_phys_addr_ack_t *) reply->b_wptr;
+ reply->b_wptr += sizeof(dl_phys_addr_ack_t);
+ bzero((caddr_t) paddrack, sizeof(dl_phys_addr_ack_t)+ETHERADDRL);
+ paddrack->dl_primitive = DL_PHYS_ADDR_ACK;
+ paddrack->dl_addr_length = ETHERADDRL;
+ paddrack->dl_addr_offset = sizeof(dl_phys_addr_ack_t);
+ bcopy(&eaddr, reply->b_wptr, ETHERADDRL);
+ reply->b_wptr += ETHERADDRL;
+ qreply(q, reply);
+ break;
+
+#if defined(SOL2)
+ case DL_PROMISCON_REQ:
+ if (size < sizeof(dl_promiscon_req_t))
+ goto badprim;
+ us->flags |= US_PROMISC;
+ dlpi_ok(q, DL_PROMISCON_REQ);
+ break;
+
+ case DL_PROMISCOFF_REQ:
+ if (size < sizeof(dl_promiscoff_req_t))
+ goto badprim;
+ us->flags &= ~US_PROMISC;
+ dlpi_ok(q, DL_PROMISCOFF_REQ);
+ break;
+#else
+ case DL_PROMISCON_REQ: /* fall thru */
+ case DL_PROMISCOFF_REQ: /* fall thru */
+#endif /* defined(SOL2) */
+#endif /* DL_CURRENT_VERSION >= 2 */
+
+#if DL_CURRENT_VERSION >= 2
+ case DL_SET_PHYS_ADDR_REQ:
+ case DL_SUBS_BIND_REQ:
+ case DL_SUBS_UNBIND_REQ:
+ case DL_ENABMULTI_REQ:
+ case DL_DISABMULTI_REQ:
+ case DL_XID_REQ:
+ case DL_TEST_REQ:
+ case DL_REPLY_UPDATE_REQ:
+ case DL_REPLY_REQ:
+ case DL_DATA_ACK_REQ:
+#endif
+ case DL_CONNECT_REQ:
+ case DL_TOKEN_REQ:
+ dlpi_error(q, us, d->dl_primitive, DL_NOTSUPPORTED, 0);
+ break;
+
+ case DL_CONNECT_RES:
+ case DL_DISCONNECT_REQ:
+ case DL_RESET_REQ:
+ case DL_RESET_RES:
+ dlpi_error(q, us, d->dl_primitive, DL_OUTSTATE, 0);
+ break;
+
+ case DL_UDQOS_REQ:
+ dlpi_error(q, us, d->dl_primitive, DL_BADQOSTYPE, 0);
+ break;
+
+#if DL_CURRENT_VERSION >= 2
+ case DL_TEST_RES:
+ case DL_XID_RES:
+ break;
+#endif
+
+ default:
+ cmn_err(CE_CONT, "ppp: unknown dlpi prim 0x%x\n", d->dl_primitive);
+ /* fall through */
+ badprim:
+ dlpi_error(q, us, d->dl_primitive, DL_BADPRIM, 0);
+ break;
+ }
+ freemsg(mp);
+}
+
+static void
+dlpi_error(q, us, prim, err, uerr)
+ queue_t *q;
+ upperstr_t *us;
+ int prim, err, uerr;
+{
+ mblk_t *reply;
+ dl_error_ack_t *errp;
+
+ if (us->flags & US_DBGLOG)
+ DPRINT3("ppp/%d: dlpi error, prim=%x, err=%x\n", us->mn, prim, err);
+ reply = allocb(sizeof(dl_error_ack_t), BPRI_HI);
+ if (reply == 0)
+ return; /* XXX should do bufcall */
+ reply->b_datap->db_type = M_PCPROTO;
+ errp = (dl_error_ack_t *) reply->b_wptr;
+ reply->b_wptr += sizeof(dl_error_ack_t);
+ errp->dl_primitive = DL_ERROR_ACK;
+ errp->dl_error_primitive = prim;
+ errp->dl_errno = err;
+ errp->dl_unix_errno = uerr;
+ qreply(q, reply);
+}
+
+static void
+dlpi_ok(q, prim)
+ queue_t *q;
+ int prim;
+{
+ mblk_t *reply;
+ dl_ok_ack_t *okp;
+
+ reply = allocb(sizeof(dl_ok_ack_t), BPRI_HI);
+ if (reply == 0)
+ return; /* XXX should do bufcall */
+ reply->b_datap->db_type = M_PCPROTO;
+ okp = (dl_ok_ack_t *) reply->b_wptr;
+ reply->b_wptr += sizeof(dl_ok_ack_t);
+ okp->dl_primitive = DL_OK_ACK;
+ okp->dl_correct_primitive = prim;
+ qreply(q, reply);
+}
+#endif /* NO_DLPI */
+
+static int
+pass_packet(us, mp, outbound)
+ upperstr_t *us;
+ mblk_t *mp;
+ int outbound;
+{
+ int pass;
+ upperstr_t *ppa;
+
+ if ((ppa = us->ppa) == 0) {
+ freemsg(mp);
+ return 0;
+ }
+
+#ifdef FILTER_PACKETS
+ pass = ip_hard_filter(us, mp, outbound);
+#else
+ /*
+ * Here is where we might, in future, decide whether to pass
+ * or drop the packet, and whether it counts as link activity.
+ */
+ pass = 1;
+#endif /* FILTER_PACKETS */
+
+ if (pass < 0) {
+ /* pass only if link already up, and don't update time */
+ if (ppa->lowerq == 0) {
+ freemsg(mp);
+ return 0;
+ }
+ pass = 1;
+ } else if (pass) {
+ if (outbound)
+ ppa->last_sent = time;
+ else
+ ppa->last_recv = time;
+ }
+
+ return pass;
+}
+
+/*
+ * We have some data to send down to the lower stream (or up the
+ * control stream, if we don't have a lower stream attached).
+ * Returns 1 if the message was dealt with, 0 if it wasn't able
+ * to be sent on and should therefore be queued up.
+ */
+static int
+send_data(mp, us)
+ mblk_t *mp;
+ upperstr_t *us;
+{
+ upperstr_t *ppa;
+
+ if ((us->flags & US_BLOCKED) || us->npmode == NPMODE_QUEUE)
+ return 0;
+ ppa = us->ppa;
+ if (ppa == 0 || us->npmode == NPMODE_DROP || us->npmode == NPMODE_ERROR) {
+ if (us->flags & US_DBGLOG)
+ DPRINT2("ppp/%d: dropping pkt (npmode=%d)\n", us->mn, us->npmode);
+ freemsg(mp);
+ return 1;
+ }
+ if (ppa->lowerq == 0) {
+ /* try to send it up the control stream */
+ if (bcanputnext(ppa->q, mp->b_band)) {
+ /*
+ * The message seems to get corrupted for some reason if
+ * we just send the message up as it is, so we send a copy.
+ */
+ mblk_t *np = copymsg(mp);
+ freemsg(mp);
+ if (np != 0)
+ putnext(ppa->q, np);
+ return 1;
+ }
+ } else {
+ if (bcanputnext(ppa->lowerq, mp->b_band)) {
+ MT_ENTER(&ppa->stats_lock);
+ ppa->stats.ppp_opackets++;
+ ppa->stats.ppp_obytes += msgdsize(mp);
+#ifdef INCR_OPACKETS
+ INCR_OPACKETS(ppa);
+#endif
+ MT_EXIT(&ppa->stats_lock);
+ /*
+ * The lower queue is only ever detached while holding an
+ * exclusive lock on the whole driver. So we can be confident
+ * that the lower queue is still there.
+ */
+ putnext(ppa->lowerq, mp);
+ return 1;
+ }
+ }
+ us->flags |= US_BLOCKED;
+ return 0;
+}
+
+/*
+ * Allocate a new PPA id and link this stream into the list of PPAs.
+ * This procedure is called with an exclusive lock on all queues in
+ * this driver.
+ */
+static void
+new_ppa(q, mp)
+ queue_t *q;
+ mblk_t *mp;
+{
+ upperstr_t *us, *up, **usp;
+ int ppa_id;
+
+ us = (upperstr_t *) q->q_ptr;
+ if (us == 0) {
+ DPRINT("new_ppa: q_ptr = 0!\n");
+ return;
+ }
+
+ usp = &ppas;
+ ppa_id = 0;
+ while ((up = *usp) != 0 && ppa_id == up->ppa_id) {
+ ++ppa_id;
+ usp = &up->nextppa;
+ }
+ us->ppa_id = ppa_id;
+ us->ppa = us;
+ us->next = 0;
+ us->nextppa = *usp;
+ *usp = us;
+ us->flags |= US_CONTROL;
+ us->npmode = NPMODE_PASS;
+
+ us->mtu = PPP_MTU;
+ us->mru = PPP_MRU;
+
+#ifdef SOL2
+ /*
+ * Create a kstats record for our statistics, so netstat -i works.
+ */
+ if (us->kstats == 0) {
+ char unit[32];
+
+ sprintf(unit, "ppp%d", us->ppa->ppa_id);
+ us->kstats = kstat_create("ppp", us->ppa->ppa_id, unit,
+ "net", KSTAT_TYPE_NAMED, 4, 0);
+ if (us->kstats != 0) {
+ kstat_named_t *kn = KSTAT_NAMED_PTR(us->kstats);
+
+ strcpy(kn[0].name, "ipackets");
+ kn[0].data_type = KSTAT_DATA_ULONG;
+ strcpy(kn[1].name, "ierrors");
+ kn[1].data_type = KSTAT_DATA_ULONG;
+ strcpy(kn[2].name, "opackets");
+ kn[2].data_type = KSTAT_DATA_ULONG;
+ strcpy(kn[3].name, "oerrors");
+ kn[3].data_type = KSTAT_DATA_ULONG;
+ kstat_install(us->kstats);
+ }
+ }
+#endif /* SOL2 */
+
+ *(int *)mp->b_cont->b_rptr = ppa_id;
+ mp->b_datap->db_type = M_IOCACK;
+ qreply(q, mp);
+}
+
+static void
+attach_ppa(q, mp)
+ queue_t *q;
+ mblk_t *mp;
+{
+ upperstr_t *us, *t;
+
+ us = (upperstr_t *) q->q_ptr;
+ if (us == 0) {
+ DPRINT("attach_ppa: q_ptr = 0!\n");
+ return;
+ }
+
+#ifndef NO_DLPI
+ us->state = DL_UNBOUND;
+#endif
+ for (t = us->ppa; t->next != 0; t = t->next)
+ ;
+ t->next = us;
+ us->next = 0;
+ if (mp->b_datap->db_type == M_IOCTL) {
+ mp->b_datap->db_type = M_IOCACK;
+ qreply(q, mp);
+ } else {
+#ifndef NO_DLPI
+ dlpi_ok(q, DL_ATTACH_REQ);
+#endif
+ }
+}
+
+static void
+detach_ppa(q, mp)
+ queue_t *q;
+ mblk_t *mp;
+{
+ upperstr_t *us, *t;
+
+ us = (upperstr_t *) q->q_ptr;
+ if (us == 0) {
+ DPRINT("detach_ppa: q_ptr = 0!\n");
+ return;
+ }
+
+ for (t = us->ppa; t->next != 0; t = t->next)
+ if (t->next == us) {
+ t->next = us->next;
+ break;
+ }
+ us->next = 0;
+ us->ppa = 0;
+#ifndef NO_DLPI
+ us->state = DL_UNATTACHED;
+ dlpi_ok(q, DL_DETACH_REQ);
+#endif
+}
+
+/*
+ * We call this with qwriter in order to give the upper queue procedures
+ * the guarantee that the lower queue is not going to go away while
+ * they are executing.
+ */
+static void
+detach_lower(q, mp)
+ queue_t *q;
+ mblk_t *mp;
+{
+ upperstr_t *us;
+
+ us = (upperstr_t *) q->q_ptr;
+ if (us == 0) {
+ DPRINT("detach_lower: q_ptr = 0!\n");
+ return;
+ }
+
+ LOCK_LOWER_W;
+ us->lowerq->q_ptr = 0;
+ RD(us->lowerq)->q_ptr = 0;
+ us->lowerq = 0;
+ UNLOCK_LOWER;
+
+ /* Unblock streams which now feed back up the control stream. */
+ qenable(us->q);
+
+ mp->b_datap->db_type = M_IOCACK;
+ qreply(q, mp);
+}
+
+static int
+pppuwsrv(q)
+ queue_t *q;
+{
+ upperstr_t *us, *as;
+ mblk_t *mp;
+
+ us = (upperstr_t *) q->q_ptr;
+ if (us == 0) {
+ DPRINT("pppuwsrv: q_ptr = 0!\n");
+ return 0;
+ }
+
+ /*
+ * If this is a control stream, then this service procedure
+ * probably got enabled because of flow control in the lower
+ * stream being enabled (or because of the lower stream going
+ * away). Therefore we enable the service procedure of all
+ * attached upper streams.
+ */
+ if (us->flags & US_CONTROL) {
+ for (as = us->next; as != 0; as = as->next)
+ qenable(WR(as->q));
+ }
+
+ /* Try to send on any data queued here. */
+ us->flags &= ~US_BLOCKED;
+ while ((mp = getq(q)) != 0) {
+ if (!send_data(mp, us)) {
+ putbq(q, mp);
+ break;
+ }
+ }
+
+ return 0;
+}
+
+/* should never get called... */
+static int
+ppplwput(q, mp)
+ queue_t *q;
+ mblk_t *mp;
+{
+ putnext(q, mp);
+ return 0;
+}
+
+static int
+ppplwsrv(q)
+ queue_t *q;
+{
+ queue_t *uq;
+
+ /*
+ * Flow control has back-enabled this stream:
+ * enable the upper write service procedure for
+ * the upper control stream for this lower stream.
+ */
+ LOCK_LOWER_R;
+ uq = (queue_t *) q->q_ptr;
+ if (uq != 0)
+ qenable(uq);
+ UNLOCK_LOWER;
+ return 0;
+}
+
+/*
+ * This should only get called for control streams.
+ */
+static int
+pppurput(q, mp)
+ queue_t *q;
+ mblk_t *mp;
+{
+ upperstr_t *ppa, *us;
+ int proto, len;
+ struct iocblk *iop;
+
+ ppa = (upperstr_t *) q->q_ptr;
+ if (ppa == 0) {
+ DPRINT("pppurput: q_ptr = 0!\n");
+ return 0;
+ }
+
+ switch (mp->b_datap->db_type) {
+ case M_CTL:
+ MT_ENTER(&ppa->stats_lock);
+ switch (*mp->b_rptr) {
+ case PPPCTL_IERROR:
+#ifdef INCR_IERRORS
+ INCR_IERRORS(ppa);
+#endif
+ ppa->stats.ppp_ierrors++;
+ break;
+ case PPPCTL_OERROR:
+#ifdef INCR_OERRORS
+ INCR_OERRORS(ppa);
+#endif
+ ppa->stats.ppp_oerrors++;
+ break;
+ }
+ MT_EXIT(&ppa->stats_lock);
+ freemsg(mp);
+ break;
+
+ case M_IOCACK:
+ case M_IOCNAK:
+ /*
+ * Attempt to match up the response with the stream
+ * that the request came from.
+ */
+ iop = (struct iocblk *) mp->b_rptr;
+ for (us = ppa; us != 0; us = us->next)
+ if (us->ioc_id == iop->ioc_id)
+ break;
+ if (us == 0)
+ freemsg(mp);
+ else
+ putnext(us->q, mp);
+ break;
+
+ case M_HANGUP:
+ /*
+ * The serial device has hung up. We don't want to send
+ * the M_HANGUP message up to pppd because that will stop
+ * us from using the control stream any more. Instead we
+ * send a zero-length message as an end-of-file indication.
+ */
+ freemsg(mp);
+ mp = allocb(1, BPRI_HI);
+ if (mp == 0) {
+ DPRINT1("ppp/%d: couldn't allocate eof message!\n", ppa->mn);
+ break;
+ }
+ putnext(ppa->q, mp);
+ break;
+
+ default:
+ if (mp->b_datap->db_type == M_DATA) {
+ len = msgdsize(mp);
+ if (mp->b_wptr - mp->b_rptr < PPP_HDRLEN) {
+ PULLUP(mp, PPP_HDRLEN);
+ if (mp == 0) {
+ DPRINT1("ppp_urput: msgpullup failed (len=%d)\n", len);
+ break;
+ }
+ }
+ MT_ENTER(&ppa->stats_lock);
+ ppa->stats.ppp_ipackets++;
+ ppa->stats.ppp_ibytes += len;
+#ifdef INCR_IPACKETS
+ INCR_IPACKETS(ppa);
+#endif
+ MT_EXIT(&ppa->stats_lock);
+
+ proto = PPP_PROTOCOL(mp->b_rptr);
+
+#if defined(SOL2)
+ /*
+ * Should there be any promiscuous stream(s), send the data
+ * up for each promiscuous stream that we recognize.
+ */
+ promisc_sendup(ppa, mp, proto, 1);
+#endif /* defined(SOL2) */
+
+ if (proto < 0x8000 && (us = find_dest(ppa, proto)) != 0) {
+ /*
+ * A data packet for some network protocol.
+ * Queue it on the upper stream for that protocol.
+ * XXX could we just putnext it? (would require thought)
+ * The rblocked flag is there to ensure that we keep
+ * messages in order for each network protocol.
+ */
+ if (!pass_packet(us, mp, 0))
+ break;
+ if (!us->rblocked && !canput(us->q))
+ us->rblocked = 1;
+ if (!us->rblocked)
+ putq(us->q, mp);
+ else
+ putq(q, mp);
+ break;
+ }
+ }
+ /*
+ * A control frame, a frame for an unknown protocol,
+ * or some other message type.
+ * Send it up to pppd via the control stream.
+ */
+ if (queclass(mp) == QPCTL || canputnext(ppa->q))
+ putnext(ppa->q, mp);
+ else
+ putq(q, mp);
+ break;
+ }
+
+ return 0;
+}
+
+static int
+pppursrv(q)
+ queue_t *q;
+{
+ upperstr_t *us, *as;
+ mblk_t *mp, *hdr;
+#ifndef NO_DLPI
+ dl_unitdata_ind_t *ud;
+#endif
+ int proto;
+
+ us = (upperstr_t *) q->q_ptr;
+ if (us == 0) {
+ DPRINT("pppursrv: q_ptr = 0!\n");
+ return 0;
+ }
+
+ if (us->flags & US_CONTROL) {
+ /*
+ * A control stream.
+ * If there is no lower queue attached, run the write service
+ * routines of other upper streams attached to this PPA.
+ */
+ if (us->lowerq == 0) {
+ as = us;
+ do {
+ if (as->flags & US_BLOCKED)
+ qenable(WR(as->q));
+ as = as->next;
+ } while (as != 0);
+ }
+
+ /*
+ * Messages get queued on this stream's read queue if they
+ * can't be queued on the read queue of the attached stream
+ * that they are destined for. This is for flow control -
+ * when this queue fills up, the lower read put procedure will
+ * queue messages there and the flow control will propagate
+ * down from there.
+ */
+ while ((mp = getq(q)) != 0) {
+ proto = PPP_PROTOCOL(mp->b_rptr);
+ if (proto < 0x8000 && (as = find_dest(us, proto)) != 0) {
+ if (!canput(as->q))
+ break;
+ putq(as->q, mp);
+ } else {
+ if (!canputnext(q))
+ break;
+ putnext(q, mp);
+ }
+ }
+ if (mp) {
+ putbq(q, mp);
+ } else {
+ /* can now put stuff directly on network protocol streams again */
+ for (as = us->next; as != 0; as = as->next)
+ as->rblocked = 0;
+ }
+
+ /*
+ * If this stream has a lower stream attached,
+ * enable the read queue's service routine.
+ * XXX we should really only do this if the queue length
+ * has dropped below the low-water mark.
+ */
+ if (us->lowerq != 0)
+ qenable(RD(us->lowerq));
+
+ } else {
+ /*
+ * A network protocol stream. Put a DLPI header on each
+ * packet and send it on.
+ * (Actually, it seems that the IP module will happily
+ * accept M_DATA messages without the DL_UNITDATA_IND header.)
+ */
+ while ((mp = getq(q)) != 0) {
+ if (!canputnext(q)) {
+ putbq(q, mp);
+ break;
+ }
+#ifndef NO_DLPI
+ proto = PPP_PROTOCOL(mp->b_rptr);
+ mp->b_rptr += PPP_HDRLEN;
+ hdr = allocb(sizeof(dl_unitdata_ind_t) + 2 * sizeof(uint),
+ BPRI_MED);
+ if (hdr == 0) {
+ /* XXX should put it back and use bufcall */
+ freemsg(mp);
+ continue;
+ }
+ hdr->b_datap->db_type = M_PROTO;
+ ud = (dl_unitdata_ind_t *) hdr->b_wptr;
+ hdr->b_wptr += sizeof(dl_unitdata_ind_t) + 2 * sizeof(uint);
+ hdr->b_cont = mp;
+ ud->dl_primitive = DL_UNITDATA_IND;
+ ud->dl_dest_addr_length = sizeof(uint);
+ ud->dl_dest_addr_offset = sizeof(dl_unitdata_ind_t);
+ ud->dl_src_addr_length = sizeof(uint);
+ ud->dl_src_addr_offset = ud->dl_dest_addr_offset + sizeof(uint);
+#if DL_CURRENT_VERSION >= 2
+ ud->dl_group_address = 0;
+#endif
+ /* Send the DLPI client the data with the SAP they requested,
+ (e.g. ETHERTYPE_IP) rather than the PPP protocol number
+ (e.g. PPP_IP) */
+ ((uint *)(ud + 1))[0] = us->req_sap; /* dest SAP */
+ ((uint *)(ud + 1))[1] = us->req_sap; /* src SAP */
+ putnext(q, hdr);
+#else /* NO_DLPI */
+ putnext(q, mp);
+#endif /* NO_DLPI */
+ }
+ /*
+ * Now that we have consumed some packets from this queue,
+ * enable the control stream's read service routine so that we
+ * can process any packets for us that might have got queued
+ * there for flow control reasons.
+ */
+ if (us->ppa)
+ qenable(us->ppa->q);
+ }
+
+ return 0;
+}
+
+static upperstr_t *
+find_dest(ppa, proto)
+ upperstr_t *ppa;
+ int proto;
+{
+ upperstr_t *us;
+
+ for (us = ppa->next; us != 0; us = us->next)
+ if (proto == us->sap)
+ break;
+ return us;
+}
+
+#if defined (SOL2)
+/*
+ * Test upstream promiscuous conditions. As of now, only pass IPv4 and
+ * Ipv6 packets upstream (let PPP packets be decoded elsewhere).
+ */
+static upperstr_t *
+find_promisc(us, proto)
+ upperstr_t *us;
+ int proto;
+{
+
+ if ((proto != PPP_IP) && (proto != PPP_IPV6))
+ return (upperstr_t *)0;
+
+ for ( ; us; us = us->next) {
+ if ((us->flags & US_PROMISC) && (us->state == DL_IDLE))
+ return us;
+ }
+
+ return (upperstr_t *)0;
+}
+
+/*
+ * Prepend an empty Ethernet header to msg for snoop, et al.
+ */
+static mblk_t *
+prepend_ether(us, mp, proto)
+ upperstr_t *us;
+ mblk_t *mp;
+ int proto;
+{
+ mblk_t *eh;
+ int type;
+
+ if ((eh = allocb(sizeof(struct ether_header), BPRI_HI)) == 0) {
+ freemsg(mp);
+ return (mblk_t *)0;
+ }
+
+ if (proto == PPP_IP)
+ type = ETHERTYPE_IP;
+ else if (proto == PPP_IPV6)
+ type = ETHERTYPE_IPV6;
+ else
+ type = proto; /* What else? Let decoder decide */
+
+ eh->b_wptr += sizeof(struct ether_header);
+ bzero((caddr_t)eh->b_rptr, sizeof(struct ether_header));
+ ((struct ether_header *)eh->b_rptr)->ether_type = htons((short)type);
+ eh->b_cont = mp;
+ return (eh);
+}
+
+/*
+ * Prepend DL_UNITDATA_IND mblk to msg
+ */
+static mblk_t *
+prepend_udind(us, mp, proto)
+ upperstr_t *us;
+ mblk_t *mp;
+ int proto;
+{
+ dl_unitdata_ind_t *dlu;
+ mblk_t *dh;
+ size_t size;
+
+ size = sizeof(dl_unitdata_ind_t);
+ if ((dh = allocb(size, BPRI_MED)) == 0) {
+ freemsg(mp);
+ return (mblk_t *)0;
+ }
+
+ dh->b_datap->db_type = M_PROTO;
+ dh->b_wptr = dh->b_datap->db_lim;
+ dh->b_rptr = dh->b_wptr - size;
+
+ dlu = (dl_unitdata_ind_t *)dh->b_rptr;
+ dlu->dl_primitive = DL_UNITDATA_IND;
+ dlu->dl_dest_addr_length = 0;
+ dlu->dl_dest_addr_offset = sizeof(dl_unitdata_ind_t);
+ dlu->dl_src_addr_length = 0;
+ dlu->dl_src_addr_offset = sizeof(dl_unitdata_ind_t);
+ dlu->dl_group_address = 0;
+
+ dh->b_cont = mp;
+ return (dh);
+}
+
+/*
+ * For any recognized promiscuous streams, send data upstream
+ */
+static void
+promisc_sendup(ppa, mp, proto, skip)
+ upperstr_t *ppa;
+ mblk_t *mp;
+ int proto, skip;
+{
+ mblk_t *dup_mp, *dup_dup_mp;
+ upperstr_t *prus, *nprus;
+
+ if ((prus = find_promisc(ppa, proto)) != 0) {
+ if (dup_mp = dupmsg(mp)) {
+
+ if (skip)
+ dup_mp->b_rptr += PPP_HDRLEN;
+
+ for ( ; nprus = find_promisc(prus->next, proto);
+ prus = nprus) {
+
+ if (dup_dup_mp = dupmsg(dup_mp)) {
+ if (canputnext(prus->q)) {
+ if (prus->flags & US_RAWDATA) {
+ dup_dup_mp = prepend_ether(prus, dup_dup_mp, proto);
+ putnext(prus->q, dup_dup_mp);
+ } else {
+ dup_dup_mp = prepend_udind(prus, dup_dup_mp, proto);
+ putnext(prus->q, dup_dup_mp);
+ }
+ } else {
+ DPRINT("ppp_urput: data to promisc q dropped\n");
+ freemsg(dup_dup_mp);
+ }
+ }
+ }
+
+ if (canputnext(prus->q)) {
+ if (prus->flags & US_RAWDATA) {
+ dup_mp = prepend_ether(prus, dup_mp, proto);
+ putnext(prus->q, dup_mp);
+ } else {
+ dup_mp = prepend_udind(prus, dup_mp, proto);
+ putnext(prus->q, dup_mp);
+ }
+ } else {
+ DPRINT("ppp_urput: data to promisc q dropped\n");
+ freemsg(dup_mp);
+ }
+ }
+ }
+}
+#endif /* defined(SOL2) */
+
+/*
+ * We simply put the message on to the associated upper control stream
+ * (either here or in ppplrsrv). That way we enter the perimeters
+ * before looking through the list of attached streams to decide which
+ * stream it should go up.
+ */
+static int
+ppplrput(q, mp)
+ queue_t *q;
+ mblk_t *mp;
+{
+ queue_t *uq;
+ struct iocblk *iop;
+
+ switch (mp->b_datap->db_type) {
+ case M_IOCTL:
+ iop = (struct iocblk *) mp->b_rptr;
+ iop->ioc_error = EINVAL;
+ mp->b_datap->db_type = M_IOCNAK;
+ qreply(q, mp);
+ return 0;
+ case M_FLUSH:
+ if (*mp->b_rptr & FLUSHR)
+ flushq(q, FLUSHDATA);
+ if (*mp->b_rptr & FLUSHW) {
+ *mp->b_rptr &= ~FLUSHR;
+ qreply(q, mp);
+ } else
+ freemsg(mp);
+ return 0;
+ }
+
+ /*
+ * If we can't get the lower lock straight away, queue this one
+ * rather than blocking, to avoid the possibility of deadlock.
+ */
+ if (!TRYLOCK_LOWER_R) {
+ putq(q, mp);
+ return 0;
+ }
+
+ /*
+ * Check that we're still connected to the driver.
+ */
+ uq = (queue_t *) q->q_ptr;
+ if (uq == 0) {
+ UNLOCK_LOWER;
+ DPRINT1("ppplrput: q = %x, uq = 0??\n", q);
+ freemsg(mp);
+ return 0;
+ }
+
+ /*
+ * Try to forward the message to the put routine for the upper
+ * control stream for this lower stream.
+ * If there are already messages queued here, queue this one so
+ * they don't get out of order.
+ */
+ if (queclass(mp) == QPCTL || (qsize(q) == 0 && canput(uq)))
+ put(uq, mp);
+ else
+ putq(q, mp);
+
+ UNLOCK_LOWER;
+ return 0;
+}
+
+static int
+ppplrsrv(q)
+ queue_t *q;
+{
+ mblk_t *mp;
+ queue_t *uq;
+
+ /*
+ * Packets get queued here for flow control reasons
+ * or if the lrput routine couldn't get the lower lock
+ * without blocking.
+ */
+ LOCK_LOWER_R;
+ uq = (queue_t *) q->q_ptr;
+ if (uq == 0) {
+ UNLOCK_LOWER;
+ flushq(q, FLUSHALL);
+ DPRINT1("ppplrsrv: q = %x, uq = 0??\n", q);
+ return 0;
+ }
+ while ((mp = getq(q)) != 0) {
+ if (queclass(mp) == QPCTL || canput(uq))
+ put(uq, mp);
+ else {
+ putbq(q, mp);
+ break;
+ }
+ }
+ UNLOCK_LOWER;
+ return 0;
+}
+
+static int
+putctl2(q, type, code, val)
+ queue_t *q;
+ int type, code, val;
+{
+ mblk_t *mp;
+
+ mp = allocb(2, BPRI_HI);
+ if (mp == 0)
+ return 0;
+ mp->b_datap->db_type = type;
+ mp->b_wptr[0] = code;
+ mp->b_wptr[1] = val;
+ mp->b_wptr += 2;
+ putnext(q, mp);
+ return 1;
+}
+
+static int
+putctl4(q, type, code, val)
+ queue_t *q;
+ int type, code, val;
+{
+ mblk_t *mp;
+
+ mp = allocb(4, BPRI_HI);
+ if (mp == 0)
+ return 0;
+ mp->b_datap->db_type = type;
+ mp->b_wptr[0] = code;
+ ((short *)mp->b_wptr)[1] = val;
+ mp->b_wptr += 4;
+ putnext(q, mp);
+ return 1;
+}
+
+static void
+debug_dump(q, mp)
+ queue_t *q;
+ mblk_t *mp;
+{
+ upperstr_t *us;
+ queue_t *uq, *lq;
+
+ DPRINT("ppp upper streams:\n");
+ for (us = minor_devs; us != 0; us = us->nextmn) {
+ uq = us->q;
+ DPRINT3(" %d: q=%x rlev=%d",
+ us->mn, uq, (uq? qsize(uq): 0));
+ DPRINT3(" wlev=%d flags=0x%b", (uq? qsize(WR(uq)): 0),
+ us->flags, "\020\1priv\2control\3blocked\4last");
+ DPRINT3(" state=%x sap=%x req_sap=%x", us->state, us->sap,
+ us->req_sap);
+ if (us->ppa == 0)
+ DPRINT(" ppa=?\n");
+ else
+ DPRINT1(" ppa=%d\n", us->ppa->ppa_id);
+ if (us->flags & US_CONTROL) {
+ lq = us->lowerq;
+ DPRINT3(" control for %d lq=%x rlev=%d",
+ us->ppa_id, lq, (lq? qsize(RD(lq)): 0));
+ DPRINT3(" wlev=%d mru=%d mtu=%d\n",
+ (lq? qsize(lq): 0), us->mru, us->mtu);
+ }
+ }
+ mp->b_datap->db_type = M_IOCACK;
+ qreply(q, mp);
+}
+
+#ifdef FILTER_PACKETS
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/udp.h>
+#include <netinet/tcp.h>
+
+#define MAX_IPHDR 128 /* max TCP/IP header size */
+
+
+/* The following table contains a hard-coded list of protocol/port pairs.
+ * Any matching packets are either discarded unconditionally, or,
+ * if ok_if_link_up is non-zero when a connection does not currently exist
+ * (i.e., they go through if the connection is present, but never initiate
+ * a dial-out).
+ * This idea came from a post by dm@garage.uun.org (David Mazieres)
+ */
+static struct pktfilt_tab {
+ int proto;
+ u_short port;
+ u_short ok_if_link_up;
+} pktfilt_tab[] = {
+ { IPPROTO_UDP, 520, 1 }, /* RIP, ok to pass if link is up */
+ { IPPROTO_UDP, 123, 1 }, /* NTP, don't keep up the link for it */
+ { -1, 0, 0 } /* terminator entry has port == -1 */
+};
+
+
+static int
+ip_hard_filter(us, mp, outbound)
+ upperstr_t *us;
+ mblk_t *mp;
+ int outbound;
+{
+ struct ip *ip;
+ struct pktfilt_tab *pft;
+ mblk_t *temp_mp;
+ int proto;
+ int len, hlen;
+
+
+ /* Note, the PPP header has already been pulled up in all cases */
+ proto = PPP_PROTOCOL(mp->b_rptr);
+ if (us->flags & US_DBGLOG)
+ DPRINT3("ppp/%d: filter, proto=0x%x, out=%d\n", us->mn, proto, outbound);
+
+ switch (proto)
+ {
+ case PPP_IP:
+ if ((mp->b_wptr - mp->b_rptr) == PPP_HDRLEN && mp->b_cont != 0) {
+ temp_mp = mp->b_cont;
+ len = msgdsize(temp_mp);
+ hlen = (len < MAX_IPHDR) ? len : MAX_IPHDR;
+ PULLUP(temp_mp, hlen);
+ if (temp_mp == 0) {
+ DPRINT2("ppp/%d: filter, pullup next failed, len=%d\n",
+ us->mn, hlen);
+ mp->b_cont = 0; /* PULLUP() freed the rest */
+ freemsg(mp);
+ return 0;
+ }
+ ip = (struct ip *)mp->b_cont->b_rptr;
+ }
+ else {
+ len = msgdsize(mp);
+ hlen = (len < (PPP_HDRLEN+MAX_IPHDR)) ? len : (PPP_HDRLEN+MAX_IPHDR);
+ PULLUP(mp, hlen);
+ if (mp == 0) {
+ DPRINT2("ppp/%d: filter, pullup failed, len=%d\n",
+ us->mn, hlen);
+ return 0;
+ }
+ ip = (struct ip *)(mp->b_rptr + PPP_HDRLEN);
+ }
+
+ /* For IP traffic, certain packets (e.g., RIP) may be either
+ * 1. ignored - dropped completely
+ * 2. will not initiate a connection, but
+ * will be passed if a connection is currently up.
+ */
+ for (pft=pktfilt_tab; pft->proto != -1; pft++) {
+ if (ip->ip_p == pft->proto) {
+ switch(pft->proto) {
+ case IPPROTO_UDP:
+ if (((struct udphdr *) &((int *)ip)[ip->ip_hl])->uh_dport
+ == htons(pft->port)) goto endfor;
+ break;
+ case IPPROTO_TCP:
+ if (((struct tcphdr *) &((int *)ip)[ip->ip_hl])->th_dport
+ == htons(pft->port)) goto endfor;
+ break;
+ }
+ }
+ }
+ endfor:
+ if (pft->proto != -1) {
+ if (us->flags & US_DBGLOG)
+ DPRINT3("ppp/%d: found IP pkt, proto=0x%x (%d)\n",
+ us->mn, pft->proto, pft->port);
+ /* Discard if not connected, or if not pass_with_link_up */
+ /* else, if link is up let go by, but don't update time */
+ return pft->ok_if_link_up? -1: 0;
+ }
+ break;
+ } /* end switch (proto) */
+
+ return 1;
+}
+#endif /* FILTER_PACKETS */
+
diff --git a/mdk-stage1/ppp/solaris/ppp.conf b/mdk-stage1/ppp/solaris/ppp.conf
new file mode 100644
index 000000000..e443a7aac
--- /dev/null
+++ b/mdk-stage1/ppp/solaris/ppp.conf
@@ -0,0 +1 @@
+name="ppp" parent="pseudo" instance=0;
diff --git a/mdk-stage1/ppp/solaris/ppp_ahdlc.c b/mdk-stage1/ppp/solaris/ppp_ahdlc.c
new file mode 100644
index 000000000..e3c4baa28
--- /dev/null
+++ b/mdk-stage1/ppp/solaris/ppp_ahdlc.c
@@ -0,0 +1,878 @@
+/*
+ * ppp_ahdlc.c - STREAMS module for doing PPP asynchronous HDLC.
+ *
+ * Re-written by Adi Masputra <adi.masputra@sun.com>, based on
+ * the original ppp_ahdlc.c
+ *
+ * Copyright (c) 2000 by Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation is hereby granted, provided that the above copyright
+ * notice appears in all copies.
+ *
+ * SUN MAKES NO REPRESENTATION OR WARRANTIES ABOUT THE SUITABILITY OF
+ * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
+ * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES
+ *
+ * Copyright (c) 1994 The Australian National University.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation is hereby granted, provided that the above copyright
+ * notice appears in all copies. This software is provided without any
+ * warranty, express or implied. The Australian National University
+ * makes no representations about the suitability of this software for
+ * any purpose.
+ *
+ * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
+ * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
+ * THE AUSTRALIAN NATIONAL UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
+ * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
+ * OR MODIFICATIONS.
+ *
+ * $Id: ppp_ahdlc.c 195720 2001-06-11 11:44:34Z gc $
+ */
+
+/*
+ * This file is used under Solaris 2, SVR4, SunOS 4, and Digital UNIX.
+ */
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/stream.h>
+#include <sys/errno.h>
+
+#ifdef SVR4
+#include <sys/conf.h>
+#include <sys/kmem.h>
+#include <sys/cmn_err.h>
+#include <sys/ddi.h>
+#else
+#include <sys/user.h>
+#ifdef __osf__
+#include <sys/cmn_err.h>
+#endif
+#endif /* SVR4 */
+
+#include <net/ppp_defs.h>
+#include <net/pppio.h>
+#include "ppp_mod.h"
+
+/*
+ * Right now, mutex is only enabled for Solaris 2.x
+ */
+#if defined(SOL2)
+#define USE_MUTEX
+#endif /* SOL2 */
+
+/*
+ * intpointer_t and uintpointer_t are signed and unsigned integer types
+ * large enough to hold any data pointer; that is, data pointers can be
+ * assigned into or from these integer types without losing precision.
+ * On recent Solaris releases, these types are defined in sys/int_types.h,
+ * but not on SunOS 4.x or the earlier Solaris versions.
+ */
+#if defined(_LP64) || defined(_I32LPx)
+typedef long intpointer_t;
+typedef unsigned long uintpointer_t;
+#else
+typedef int intpointer_t;
+typedef unsigned int uintpointer_t;
+#endif
+
+MOD_OPEN_DECL(ahdlc_open);
+MOD_CLOSE_DECL(ahdlc_close);
+static int ahdlc_wput __P((queue_t *, mblk_t *));
+static int ahdlc_rput __P((queue_t *, mblk_t *));
+static void ahdlc_encode __P((queue_t *, mblk_t *));
+static void ahdlc_decode __P((queue_t *, mblk_t *));
+static int msg_byte __P((mblk_t *, unsigned int));
+
+#if defined(SOL2)
+/*
+ * Don't send HDLC start flag is last transmit is within 1.5 seconds -
+ * FLAG_TIME is defined is microseconds
+ */
+#define FLAG_TIME 1500
+#define ABS(x) (x >= 0 ? x : (-x))
+#endif /* SOL2 */
+
+/*
+ * Extract byte i of message mp
+ */
+#define MSG_BYTE(mp, i) ((i) < (mp)->b_wptr - (mp)->b_rptr? (mp)->b_rptr[i]: \
+ msg_byte((mp), (i)))
+
+/*
+ * Is this LCP packet one we have to transmit using LCP defaults?
+ */
+#define LCP_USE_DFLT(mp) (1 <= (code = MSG_BYTE((mp), 4)) && code <= 7)
+
+/*
+ * Standard STREAMS declarations
+ */
+static struct module_info minfo = {
+ 0x7d23, "ppp_ahdl", 0, INFPSZ, 32768, 512
+};
+
+static struct qinit rinit = {
+ ahdlc_rput, NULL, ahdlc_open, ahdlc_close, NULL, &minfo, NULL
+};
+
+static struct qinit winit = {
+ ahdlc_wput, NULL, NULL, NULL, NULL, &minfo, NULL
+};
+
+#if defined(SVR4) && !defined(SOL2)
+int phdldevflag = 0;
+#define ppp_ahdlcinfo phdlinfo
+#endif /* defined(SVR4) && !defined(SOL2) */
+
+struct streamtab ppp_ahdlcinfo = {
+ &rinit, /* ptr to st_rdinit */
+ &winit, /* ptr to st_wrinit */
+ NULL, /* ptr to st_muxrinit */
+ NULL, /* ptr to st_muxwinit */
+#if defined(SUNOS4)
+ NULL /* ptr to ptr to st_modlist */
+#endif /* SUNOS4 */
+};
+
+#if defined(SUNOS4)
+int ppp_ahdlc_count = 0; /* open counter */
+#endif /* SUNOS4 */
+
+/*
+ * Per-stream state structure
+ */
+typedef struct ahdlc_state {
+#if defined(USE_MUTEX)
+ kmutex_t lock; /* lock for this structure */
+#endif /* USE_MUTEX */
+ int flags; /* link flags */
+ mblk_t *rx_buf; /* ptr to receive buffer */
+ int rx_buf_size; /* receive buffer size */
+ ushort_t infcs; /* calculated rx HDLC FCS */
+ u_int32_t xaccm[8]; /* 256-bit xmit ACCM */
+ u_int32_t raccm; /* 32-bit rcv ACCM */
+ int mtu; /* interface MTU */
+ int mru; /* link MRU */
+ int unit; /* current PPP unit number */
+ struct pppstat stats; /* statistic structure */
+#if defined(SOL2)
+ clock_t flag_time; /* time in usec between flags */
+ clock_t lbolt; /* last updated lbolt */
+#endif /* SOL2 */
+} ahdlc_state_t;
+
+/*
+ * Values for flags
+ */
+#define ESCAPED 0x100 /* last saw escape char on input */
+#define IFLUSH 0x200 /* flushing input due to error */
+
+/*
+ * RCV_B7_1, etc., defined in net/pppio.h, are stored in flags also.
+ */
+#define RCV_FLAGS (RCV_B7_1|RCV_B7_0|RCV_ODDP|RCV_EVNP)
+
+/*
+ * FCS lookup table as calculated by genfcstab.
+ */
+static u_short fcstab[256] = {
+ 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
+ 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
+ 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
+ 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
+ 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
+ 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
+ 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
+ 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
+ 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
+ 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
+ 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
+ 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
+ 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
+ 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
+ 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
+ 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
+ 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
+ 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
+ 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
+ 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
+ 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
+ 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
+ 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
+ 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
+ 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
+ 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
+ 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
+ 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
+ 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
+ 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
+ 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
+ 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
+};
+
+static u_int32_t paritytab[8] =
+{
+ 0x96696996, 0x69969669, 0x69969669, 0x96696996,
+ 0x69969669, 0x96696996, 0x96696996, 0x69969669
+};
+
+/*
+ * STREAMS module open (entry) point
+ */
+MOD_OPEN(ahdlc_open)
+{
+ ahdlc_state_t *state;
+
+ /*
+ * Return if it's already opened
+ */
+ if (q->q_ptr) {
+ return 0;
+ }
+
+ /*
+ * This can only be opened as a module
+ */
+ if (sflag != MODOPEN) {
+ return 0;
+ }
+
+ state = (ahdlc_state_t *) ALLOC_NOSLEEP(sizeof(ahdlc_state_t));
+ if (state == 0)
+ OPEN_ERROR(ENOSR);
+ bzero((caddr_t) state, sizeof(ahdlc_state_t));
+
+ q->q_ptr = (caddr_t) state;
+ WR(q)->q_ptr = (caddr_t) state;
+
+#if defined(USE_MUTEX)
+ mutex_init(&state->lock, NULL, MUTEX_DEFAULT, NULL);
+ mutex_enter(&state->lock);
+#endif /* USE_MUTEX */
+
+ state->xaccm[0] = ~0; /* escape 0x00 through 0x1f */
+ state->xaccm[3] = 0x60000000; /* escape 0x7d and 0x7e */
+ state->mru = PPP_MRU; /* default of 1500 bytes */
+#if defined(SOL2)
+ state->flag_time = drv_usectohz(FLAG_TIME);
+#endif /* SOL2 */
+
+#if defined(USE_MUTEX)
+ mutex_exit(&state->lock);
+#endif /* USE_MUTEX */
+
+#if defined(SUNOS4)
+ ppp_ahdlc_count++;
+#endif /* SUNOS4 */
+
+ qprocson(q);
+
+ return 0;
+}
+
+/*
+ * STREAMS module close (exit) point
+ */
+MOD_CLOSE(ahdlc_close)
+{
+ ahdlc_state_t *state;
+
+ qprocsoff(q);
+
+ state = (ahdlc_state_t *) q->q_ptr;
+
+ if (state == 0) {
+ DPRINT("state == 0 in ahdlc_close\n");
+ return 0;
+ }
+
+#if defined(USE_MUTEX)
+ mutex_enter(&state->lock);
+#endif /* USE_MUTEX */
+
+ if (state->rx_buf != 0) {
+ freemsg(state->rx_buf);
+ state->rx_buf = 0;
+ }
+
+#if defined(USE_MUTEX)
+ mutex_exit(&state->lock);
+ mutex_destroy(&state->lock);
+#endif /* USE_MUTEX */
+
+ FREE(q->q_ptr, sizeof(ahdlc_state_t));
+ q->q_ptr = NULL;
+ OTHERQ(q)->q_ptr = NULL;
+
+#if defined(SUNOS4)
+ if (ppp_ahdlc_count)
+ ppp_ahdlc_count--;
+#endif /* SUNOS4 */
+
+ return 0;
+}
+
+/*
+ * Write side put routine
+ */
+static int
+ahdlc_wput(q, mp)
+ queue_t *q;
+ mblk_t *mp;
+{
+ ahdlc_state_t *state;
+ struct iocblk *iop;
+ int error;
+ mblk_t *np;
+ struct ppp_stats *psp;
+
+ state = (ahdlc_state_t *) q->q_ptr;
+ if (state == 0) {
+ DPRINT("state == 0 in ahdlc_wput\n");
+ freemsg(mp);
+ return 0;
+ }
+
+ switch (mp->b_datap->db_type) {
+ case M_DATA:
+ /*
+ * A data packet - do character-stuffing and FCS, and
+ * send it onwards.
+ */
+ ahdlc_encode(q, mp);
+ freemsg(mp);
+ break;
+
+ case M_IOCTL:
+ iop = (struct iocblk *) mp->b_rptr;
+ error = EINVAL;
+ switch (iop->ioc_cmd) {
+ case PPPIO_XACCM:
+ if ((iop->ioc_count < sizeof(u_int32_t)) ||
+ (iop->ioc_count > sizeof(ext_accm))) {
+ break;
+ }
+ if (mp->b_cont == 0) {
+ DPRINT1("ahdlc_wput/%d: PPPIO_XACCM b_cont = 0!\n", state->unit);
+ break;
+ }
+#if defined(USE_MUTEX)
+ mutex_enter(&state->lock);
+#endif /* USE_MUTEX */
+ bcopy((caddr_t)mp->b_cont->b_rptr, (caddr_t)state->xaccm,
+ iop->ioc_count);
+ state->xaccm[2] &= ~0x40000000; /* don't escape 0x5e */
+ state->xaccm[3] |= 0x60000000; /* do escape 0x7d, 0x7e */
+#if defined(USE_MUTEX)
+ mutex_exit(&state->lock);
+#endif /* USE_MUTEX */
+ iop->ioc_count = 0;
+ error = 0;
+ break;
+
+ case PPPIO_RACCM:
+ if (iop->ioc_count != sizeof(u_int32_t))
+ break;
+ if (mp->b_cont == 0) {
+ DPRINT1("ahdlc_wput/%d: PPPIO_RACCM b_cont = 0!\n", state->unit);
+ break;
+ }
+#if defined(USE_MUTEX)
+ mutex_enter(&state->lock);
+#endif /* USE_MUTEX */
+ bcopy((caddr_t)mp->b_cont->b_rptr, (caddr_t)&state->raccm,
+ sizeof(u_int32_t));
+#if defined(USE_MUTEX)
+ mutex_exit(&state->lock);
+#endif /* USE_MUTEX */
+ iop->ioc_count = 0;
+ error = 0;
+ break;
+
+ case PPPIO_GCLEAN:
+ np = allocb(sizeof(int), BPRI_HI);
+ if (np == 0) {
+ error = ENOSR;
+ break;
+ }
+ if (mp->b_cont != 0)
+ freemsg(mp->b_cont);
+ mp->b_cont = np;
+#if defined(USE_MUTEX)
+ mutex_enter(&state->lock);
+#endif /* USE_MUTEX */
+ *(int *)np->b_wptr = state->flags & RCV_FLAGS;
+#if defined(USE_MUTEX)
+ mutex_exit(&state->lock);
+#endif /* USE_MUTEX */
+ np->b_wptr += sizeof(int);
+ iop->ioc_count = sizeof(int);
+ error = 0;
+ break;
+
+ case PPPIO_GETSTAT:
+ np = allocb(sizeof(struct ppp_stats), BPRI_HI);
+ if (np == 0) {
+ error = ENOSR;
+ break;
+ }
+ if (mp->b_cont != 0)
+ freemsg(mp->b_cont);
+ mp->b_cont = np;
+ psp = (struct ppp_stats *) np->b_wptr;
+ np->b_wptr += sizeof(struct ppp_stats);
+ bzero((caddr_t)psp, sizeof(struct ppp_stats));
+ psp->p = state->stats;
+ iop->ioc_count = sizeof(struct ppp_stats);
+ error = 0;
+ break;
+
+ case PPPIO_LASTMOD:
+ /* we knew this anyway */
+ error = 0;
+ break;
+
+ default:
+ error = -1;
+ break;
+ }
+
+ if (error < 0)
+ putnext(q, mp);
+ else if (error == 0) {
+ mp->b_datap->db_type = M_IOCACK;
+ qreply(q, mp);
+ } else {
+ mp->b_datap->db_type = M_IOCNAK;
+ iop->ioc_count = 0;
+ iop->ioc_error = error;
+ qreply(q, mp);
+ }
+ break;
+
+ case M_CTL:
+ switch (*mp->b_rptr) {
+ case PPPCTL_MTU:
+#if defined(USE_MUTEX)
+ mutex_enter(&state->lock);
+#endif /* USE_MUTEX */
+ state->mtu = ((unsigned short *)mp->b_rptr)[1];
+#if defined(USE_MUTEX)
+ mutex_exit(&state->lock);
+#endif /* USE_MUTEX */
+ freemsg(mp);
+ break;
+ case PPPCTL_MRU:
+#if defined(USE_MUTEX)
+ mutex_enter(&state->lock);
+#endif /* USE_MUTEX */
+ state->mru = ((unsigned short *)mp->b_rptr)[1];
+#if defined(USE_MUTEX)
+ mutex_exit(&state->lock);
+#endif /* USE_MUTEX */
+ freemsg(mp);
+ break;
+ case PPPCTL_UNIT:
+#if defined(USE_MUTEX)
+ mutex_enter(&state->lock);
+#endif /* USE_MUTEX */
+ state->unit = mp->b_rptr[1];
+#if defined(USE_MUTEX)
+ mutex_exit(&state->lock);
+#endif /* USE_MUTEX */
+ break;
+ default:
+ putnext(q, mp);
+ }
+ break;
+
+ default:
+ putnext(q, mp);
+ }
+
+ return 0;
+}
+
+/*
+ * Read side put routine
+ */
+static int
+ahdlc_rput(q, mp)
+ queue_t *q;
+ mblk_t *mp;
+{
+ ahdlc_state_t *state;
+
+ state = (ahdlc_state_t *) q->q_ptr;
+ if (state == 0) {
+ DPRINT("state == 0 in ahdlc_rput\n");
+ freemsg(mp);
+ return 0;
+ }
+
+ switch (mp->b_datap->db_type) {
+ case M_DATA:
+ ahdlc_decode(q, mp);
+ freemsg(mp);
+ break;
+
+ case M_HANGUP:
+#if defined(USE_MUTEX)
+ mutex_enter(&state->lock);
+#endif /* USE_MUTEX */
+ if (state->rx_buf != 0) {
+ /* XXX would like to send this up for debugging */
+ freemsg(state->rx_buf);
+ state->rx_buf = 0;
+ }
+ state->flags = IFLUSH;
+#if defined(USE_MUTEX)
+ mutex_exit(&state->lock);
+#endif /* USE_MUTEX */
+ putnext(q, mp);
+ break;
+
+ default:
+ putnext(q, mp);
+ }
+ return 0;
+}
+
+/*
+ * Extract bit c from map m, to determine if c needs to be escaped
+ */
+#define IN_TX_MAP(c, m) ((m)[(c) >> 5] & (1 << ((c) & 0x1f)))
+
+static void
+ahdlc_encode(q, mp)
+ queue_t *q;
+ mblk_t *mp;
+{
+ ahdlc_state_t *state;
+ u_int32_t *xaccm, loc_xaccm[8];
+ ushort_t fcs;
+ size_t outmp_len;
+ mblk_t *outmp, *tmp;
+ uchar_t *dp, fcs_val;
+ int is_lcp, code;
+#if defined(SOL2)
+ clock_t lbolt;
+#endif /* SOL2 */
+
+ if (msgdsize(mp) < 4) {
+ return;
+ }
+
+ state = (ahdlc_state_t *)q->q_ptr;
+#if defined(USE_MUTEX)
+ mutex_enter(&state->lock);
+#endif /* USE_MUTEX */
+
+ /*
+ * Allocate an output buffer large enough to handle a case where all
+ * characters need to be escaped
+ */
+ outmp_len = (msgdsize(mp) << 1) + /* input block x 2 */
+ (sizeof(fcs) << 2) + /* HDLC FCS x 4 */
+ (sizeof(uchar_t) << 1); /* HDLC flags x 2 */
+
+ outmp = allocb(outmp_len, BPRI_MED);
+ if (outmp == NULL) {
+ state->stats.ppp_oerrors++;
+#if defined(USE_MUTEX)
+ mutex_exit(&state->lock);
+#endif /* USE_MUTEX */
+ putctl1(RD(q)->q_next, M_CTL, PPPCTL_OERROR);
+ return;
+ }
+
+#if defined(SOL2)
+ /*
+ * Check if our last transmit happenned within flag_time, using
+ * the system's LBOLT value in clock ticks
+ */
+ if (drv_getparm(LBOLT, &lbolt) != -1) {
+ if (ABS((clock_t)lbolt - state->lbolt) > state->flag_time) {
+ *outmp->b_wptr++ = PPP_FLAG;
+ }
+ state->lbolt = lbolt;
+ } else {
+ *outmp->b_wptr++ = PPP_FLAG;
+ }
+#else
+ /*
+ * If the driver below still has a message to process, skip the
+ * HDLC flag, otherwise, put one in the beginning
+ */
+ if (qsize(q->q_next) == 0) {
+ *outmp->b_wptr++ = PPP_FLAG;
+ }
+#endif
+
+ /*
+ * All control characters must be escaped for LCP packets with code
+ * values between 1 (Conf-Req) and 7 (Code-Rej).
+ */
+ is_lcp = ((MSG_BYTE(mp, 0) == PPP_ALLSTATIONS) &&
+ (MSG_BYTE(mp, 1) == PPP_UI) &&
+ (MSG_BYTE(mp, 2) == (PPP_LCP >> 8)) &&
+ (MSG_BYTE(mp, 3) == (PPP_LCP & 0xff)) &&
+ LCP_USE_DFLT(mp));
+
+ xaccm = state->xaccm;
+ if (is_lcp) {
+ bcopy((caddr_t)state->xaccm, (caddr_t)loc_xaccm, sizeof(loc_xaccm));
+ loc_xaccm[0] = ~0; /* force escape on 0x00 through 0x1f */
+ xaccm = loc_xaccm;
+ }
+
+ fcs = PPP_INITFCS; /* Initial FCS is 0xffff */
+
+ /*
+ * Process this block and the rest (if any) attached to the this one
+ */
+ for (tmp = mp; tmp; tmp = tmp->b_cont) {
+ if (tmp->b_datap->db_type == M_DATA) {
+ for (dp = tmp->b_rptr; dp < tmp->b_wptr; dp++) {
+ fcs = PPP_FCS(fcs, *dp);
+ if (IN_TX_MAP(*dp, xaccm)) {
+ *outmp->b_wptr++ = PPP_ESCAPE;
+ *outmp->b_wptr++ = *dp ^ PPP_TRANS;
+ } else {
+ *outmp->b_wptr++ = *dp;
+ }
+ }
+ } else {
+ continue; /* skip if db_type is something other than M_DATA */
+ }
+ }
+
+ /*
+ * Append the HDLC FCS, making sure that escaping is done on any
+ * necessary bytes
+ */
+ fcs_val = (fcs ^ 0xffff) & 0xff;
+ if (IN_TX_MAP(fcs_val, xaccm)) {
+ *outmp->b_wptr++ = PPP_ESCAPE;
+ *outmp->b_wptr++ = fcs_val ^ PPP_TRANS;
+ } else {
+ *outmp->b_wptr++ = fcs_val;
+ }
+
+ fcs_val = ((fcs ^ 0xffff) >> 8) & 0xff;
+ if (IN_TX_MAP(fcs_val, xaccm)) {
+ *outmp->b_wptr++ = PPP_ESCAPE;
+ *outmp->b_wptr++ = fcs_val ^ PPP_TRANS;
+ } else {
+ *outmp->b_wptr++ = fcs_val;
+ }
+
+ /*
+ * And finally, append the HDLC flag, and send it away
+ */
+ *outmp->b_wptr++ = PPP_FLAG;
+
+ state->stats.ppp_obytes += msgdsize(outmp);
+ state->stats.ppp_opackets++;
+
+#if defined(USE_MUTEX)
+ mutex_exit(&state->lock);
+#endif /* USE_MUTEX */
+
+ putnext(q, outmp);
+ return;
+}
+
+/*
+ * Checks the 32-bit receive ACCM to see if the byte needs un-escaping
+ */
+#define IN_RX_MAP(c, m) ((((unsigned int) (uchar_t) (c)) < 0x20) && \
+ (m) & (1 << (c)))
+
+
+/*
+ * Process received characters.
+ */
+static void
+ahdlc_decode(q, mp)
+ queue_t *q;
+ mblk_t *mp;
+{
+ ahdlc_state_t *state;
+ mblk_t *om;
+ uchar_t *dp;
+ ushort_t fcs;
+#if defined(SOL2)
+ mblk_t *zmp;
+#endif /* SOL2 */
+
+#if defined(SOL2)
+ /*
+ * In case the driver (or something below) doesn't send
+ * data upstream in one message block, concatenate everything
+ */
+ if (!((mp->b_wptr - mp->b_rptr == msgdsize(mp)) &&
+ ((intpointer_t)mp->b_rptr % sizeof(intpointer_t) == 0))) {
+
+ zmp = msgpullup(mp, -1);
+ freemsg(mp);
+ mp = zmp;
+ if (mp == 0)
+ return;
+ }
+#endif /* SOL2 */
+
+ state = (ahdlc_state_t *) q->q_ptr;
+
+#if defined(USE_MUTEX)
+ mutex_enter(&state->lock);
+#endif /* USE_MUTEX */
+
+ state->stats.ppp_ibytes += msgdsize(mp);
+
+ for (dp = mp->b_rptr; dp < mp->b_wptr; dp++) {
+
+ /*
+ * This should detect the lack of 8-bit communication channel
+ * which is necessary for PPP to work. In addition, it also
+ * checks on the parity.
+ */
+ if (*dp & 0x80)
+ state->flags |= RCV_B7_1;
+ else
+ state->flags |= RCV_B7_0;
+
+ if (paritytab[*dp >> 5] & (1 << (*dp & 0x1f)))
+ state->flags |= RCV_ODDP;
+ else
+ state->flags |= RCV_EVNP;
+
+ /*
+ * So we have a HDLC flag ...
+ */
+ if (*dp == PPP_FLAG) {
+
+ /*
+ * If we think that it marks the beginning of the frame,
+ * then continue to process the next octects
+ */
+ if ((state->flags & IFLUSH) ||
+ (state->rx_buf == 0) ||
+ (msgdsize(state->rx_buf) == 0)) {
+
+ state->flags &= ~IFLUSH;
+ continue;
+ }
+
+ /*
+ * We get here because the above condition isn't true,
+ * in which case the HDLC flag was there to mark the end
+ * of the frame (or so we think)
+ */
+ om = state->rx_buf;
+
+ if (state->infcs == PPP_GOODFCS) {
+ state->stats.ppp_ipackets++;
+ adjmsg(om, -PPP_FCSLEN);
+ putnext(q, om);
+ } else {
+ DPRINT2("ppp%d: bad fcs (len=%d)\n",
+ state->unit, msgdsize(state->rx_buf));
+ freemsg(state->rx_buf);
+ state->flags &= ~(IFLUSH | ESCAPED);
+ state->stats.ppp_ierrors++;
+ putctl1(q->q_next, M_CTL, PPPCTL_IERROR);
+ }
+
+ state->rx_buf = 0;
+ continue;
+ }
+
+ if (state->flags & IFLUSH) {
+ continue;
+ }
+
+ /*
+ * Allocate a receive buffer, large enough to store a frame (after
+ * un-escaping) of at least 1500 octets. If MRU is negotiated to
+ * be more than the default, then allocate that much. In addition,
+ * we add an extra 32-bytes for a fudge factor
+ */
+ if (state->rx_buf == 0) {
+ state->rx_buf_size = (state->mru < PPP_MRU ? PPP_MRU : state->mru);
+ state->rx_buf_size += (sizeof(u_int32_t) << 3);
+ state->rx_buf = allocb(state->rx_buf_size, BPRI_MED);
+
+ /*
+ * If allocation fails, try again on the next frame
+ */
+ if (state->rx_buf == 0) {
+ state->flags |= IFLUSH;
+ continue;
+ }
+ state->flags &= ~(IFLUSH | ESCAPED);
+ state->infcs = PPP_INITFCS;
+ }
+
+ if (*dp == PPP_ESCAPE) {
+ state->flags |= ESCAPED;
+ continue;
+ }
+
+ /*
+ * Make sure we un-escape the necessary characters, as well as the
+ * ones in our receive async control character map
+ */
+ if (state->flags & ESCAPED) {
+ *dp ^= PPP_TRANS;
+ state->flags &= ~ESCAPED;
+ } else if (IN_RX_MAP(*dp, state->raccm))
+ continue;
+
+ /*
+ * Unless the peer lied to us about the negotiated MRU, we should
+ * never get a frame which is too long. If it happens, toss it away
+ * and grab the next incoming one
+ */
+ if (msgdsize(state->rx_buf) < state->rx_buf_size) {
+ state->infcs = PPP_FCS(state->infcs, *dp);
+ *state->rx_buf->b_wptr++ = *dp;
+ } else {
+ DPRINT2("ppp%d: frame too long (%d)\n",
+ state->unit, msgdsize(state->rx_buf));
+ freemsg(state->rx_buf);
+ state->rx_buf = 0;
+ state->flags |= IFLUSH;
+ }
+ }
+
+#if defined(USE_MUTEX)
+ mutex_exit(&state->lock);
+#endif /* USE_MUTEX */
+}
+
+static int
+msg_byte(mp, i)
+ mblk_t *mp;
+ unsigned int i;
+{
+ while (mp != 0 && i >= mp->b_wptr - mp->b_rptr)
+ mp = mp->b_cont;
+ if (mp == 0)
+ return -1;
+ return mp->b_rptr[i];
+}
diff --git a/mdk-stage1/ppp/solaris/ppp_ahdlc_mod.c b/mdk-stage1/ppp/solaris/ppp_ahdlc_mod.c
new file mode 100644
index 000000000..f81be8abb
--- /dev/null
+++ b/mdk-stage1/ppp/solaris/ppp_ahdlc_mod.c
@@ -0,0 +1,49 @@
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/conf.h>
+#include <sys/modctl.h>
+#include <sys/sunddi.h>
+
+extern struct streamtab ppp_ahdlcinfo;
+
+static struct fmodsw fsw = {
+ "ppp_ahdl",
+ &ppp_ahdlcinfo,
+ D_NEW | D_MP | D_MTQPAIR
+};
+
+extern struct mod_ops mod_strmodops;
+
+static struct modlstrmod modlstrmod = {
+ &mod_strmodops,
+ "PPP async HDLC module",
+ &fsw
+};
+
+static struct modlinkage modlinkage = {
+ MODREV_1,
+ (void *) &modlstrmod,
+ NULL
+};
+
+/*
+ * Entry points for modloading.
+ */
+int
+_init(void)
+{
+ return mod_install(&modlinkage);
+}
+
+int
+_fini(void)
+{
+ return mod_remove(&modlinkage);
+}
+
+int
+_info(mip)
+ struct modinfo *mip;
+{
+ return mod_info(&modlinkage, mip);
+}
diff --git a/mdk-stage1/ppp/solaris/ppp_comp.c b/mdk-stage1/ppp/solaris/ppp_comp.c
new file mode 100644
index 000000000..941e9d8c5
--- /dev/null
+++ b/mdk-stage1/ppp/solaris/ppp_comp.c
@@ -0,0 +1,1126 @@
+/*
+ * ppp_comp.c - STREAMS module for kernel-level compression and CCP support.
+ *
+ * Copyright (c) 1994 The Australian National University.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation is hereby granted, provided that the above copyright
+ * notice appears in all copies. This software is provided without any
+ * warranty, express or implied. The Australian National University
+ * makes no representations about the suitability of this software for
+ * any purpose.
+ *
+ * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
+ * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
+ * THE AUSTRALIAN NATIONAL UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
+ * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
+ * OR MODIFICATIONS.
+ *
+ * $Id: ppp_comp.c 195720 2001-06-11 11:44:34Z gc $
+ */
+
+/*
+ * This file is used under SVR4, Solaris 2, SunOS 4, and Digital UNIX.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/errno.h>
+#include <sys/stream.h>
+
+#ifdef SVR4
+#include <sys/conf.h>
+#include <sys/cmn_err.h>
+#include <sys/ddi.h>
+#else
+#include <sys/user.h>
+#ifdef __osf__
+#include <sys/cmn_err.h>
+#endif
+#endif /* SVR4 */
+
+#include <net/ppp_defs.h>
+#include <net/pppio.h>
+#include "ppp_mod.h"
+
+#ifdef __osf__
+#include <sys/mbuf.h>
+#include <sys/protosw.h>
+#endif
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <net/vjcompress.h>
+
+#define PACKETPTR mblk_t *
+#include <net/ppp-comp.h>
+
+MOD_OPEN_DECL(ppp_comp_open);
+MOD_CLOSE_DECL(ppp_comp_close);
+static int ppp_comp_rput __P((queue_t *, mblk_t *));
+static int ppp_comp_rsrv __P((queue_t *));
+static int ppp_comp_wput __P((queue_t *, mblk_t *));
+static int ppp_comp_wsrv __P((queue_t *));
+static void ppp_comp_ccp __P((queue_t *, mblk_t *, int));
+static int msg_byte __P((mblk_t *, unsigned int));
+
+/* Extract byte i of message mp. */
+#define MSG_BYTE(mp, i) ((i) < (mp)->b_wptr - (mp)->b_rptr? (mp)->b_rptr[i]: \
+ msg_byte((mp), (i)))
+
+/* Is this LCP packet one we have to transmit using LCP defaults? */
+#define LCP_USE_DFLT(mp) (1 <= (code = MSG_BYTE((mp), 4)) && code <= 7)
+
+#define PPP_COMP_ID 0xbadf
+static struct module_info minfo = {
+#ifdef PRIOQ
+ PPP_COMP_ID, "ppp_comp", 0, INFPSZ, 16512, 16384,
+#else
+ PPP_COMP_ID, "ppp_comp", 0, INFPSZ, 16384, 4096,
+#endif
+};
+
+static struct qinit r_init = {
+ ppp_comp_rput, ppp_comp_rsrv, ppp_comp_open, ppp_comp_close,
+ NULL, &minfo, NULL
+};
+
+static struct qinit w_init = {
+ ppp_comp_wput, ppp_comp_wsrv, NULL, NULL, NULL, &minfo, NULL
+};
+
+#if defined(SVR4) && !defined(SOL2)
+int pcmpdevflag = 0;
+#define ppp_compinfo pcmpinfo
+#endif
+struct streamtab ppp_compinfo = {
+ &r_init, &w_init, NULL, NULL
+};
+
+int ppp_comp_count; /* number of module instances in use */
+
+#ifdef __osf__
+
+static void ppp_comp_alloc __P((comp_state_t *));
+typedef struct memreq {
+ unsigned char comp_opts[20];
+ int cmd;
+ int thread_status;
+ char *returned_mem;
+} memreq_t;
+
+#endif
+
+typedef struct comp_state {
+ int flags;
+ int mru;
+ int mtu;
+ int unit;
+ struct compressor *xcomp;
+ void *xstate;
+ struct compressor *rcomp;
+ void *rstate;
+ struct vjcompress vj_comp;
+ int vj_last_ierrors;
+ struct pppstat stats;
+#ifdef __osf__
+ memreq_t memreq;
+ thread_t thread;
+#endif
+} comp_state_t;
+
+
+#ifdef __osf__
+extern task_t first_task;
+#endif
+
+/* Bits in flags are as defined in pppio.h. */
+#define CCP_ERR (CCP_ERROR | CCP_FATALERROR)
+#define LAST_MOD 0x1000000 /* no ppp modules below us */
+#define DBGLOG 0x2000000 /* log debugging stuff */
+
+#define MAX_IPHDR 128 /* max TCP/IP header size */
+#define MAX_VJHDR 20 /* max VJ compressed header size (?) */
+
+#undef MIN /* just in case */
+#define MIN(a, b) ((a) < (b)? (a): (b))
+
+/*
+ * List of compressors we know about.
+ */
+
+#if DO_BSD_COMPRESS
+extern struct compressor ppp_bsd_compress;
+#endif
+#if DO_DEFLATE
+extern struct compressor ppp_deflate, ppp_deflate_draft;
+#endif
+
+struct compressor *ppp_compressors[] = {
+#if DO_BSD_COMPRESS
+ &ppp_bsd_compress,
+#endif
+#if DO_DEFLATE
+ &ppp_deflate,
+ &ppp_deflate_draft,
+#endif
+ NULL
+};
+
+/*
+ * STREAMS module entry points.
+ */
+MOD_OPEN(ppp_comp_open)
+{
+ comp_state_t *cp;
+#ifdef __osf__
+ thread_t thread;
+#endif
+
+ if (q->q_ptr == NULL) {
+ cp = (comp_state_t *) ALLOC_SLEEP(sizeof(comp_state_t));
+ if (cp == NULL)
+ OPEN_ERROR(ENOSR);
+ bzero((caddr_t)cp, sizeof(comp_state_t));
+ WR(q)->q_ptr = q->q_ptr = (caddr_t) cp;
+ cp->mru = PPP_MRU;
+ cp->mtu = PPP_MTU;
+ cp->xstate = NULL;
+ cp->rstate = NULL;
+ vj_compress_init(&cp->vj_comp, -1);
+#ifdef __osf__
+ if (!(thread = kernel_thread_w_arg(first_task, ppp_comp_alloc, (void *)cp)))
+ OPEN_ERROR(ENOSR);
+ cp->thread = thread;
+#endif
+ ++ppp_comp_count;
+ qprocson(q);
+ }
+ return 0;
+}
+
+MOD_CLOSE(ppp_comp_close)
+{
+ comp_state_t *cp;
+
+ qprocsoff(q);
+ cp = (comp_state_t *) q->q_ptr;
+ if (cp != NULL) {
+ if (cp->xstate != NULL)
+ (*cp->xcomp->comp_free)(cp->xstate);
+ if (cp->rstate != NULL)
+ (*cp->rcomp->decomp_free)(cp->rstate);
+#ifdef __osf__
+ if (!cp->thread)
+ printf("ppp_comp_close: NULL thread!\n");
+ else
+ thread_terminate(cp->thread);
+#endif
+ FREE(cp, sizeof(comp_state_t));
+ q->q_ptr = NULL;
+ OTHERQ(q)->q_ptr = NULL;
+ --ppp_comp_count;
+ }
+ return 0;
+}
+
+#ifdef __osf__
+
+/* thread for calling back to a compressor's memory allocator
+ * Needed for Digital UNIX since it's VM can't handle requests
+ * for large amounts of memory without blocking. The thread
+ * provides a context in which we can call a memory allocator
+ * that may block.
+ */
+static void
+ppp_comp_alloc(comp_state_t *cp)
+{
+ int len, cmd;
+ unsigned char *compressor_options;
+ thread_t thread;
+ void *(*comp_allocator)();
+
+
+#if defined(MAJOR_VERSION) && (MAJOR_VERSION <= 2)
+
+ /* In 2.x and earlier the argument gets passed
+ * in the thread structure itself. Yuck.
+ */
+ thread = current_thread();
+ cp = thread->reply_port;
+ thread->reply_port = PORT_NULL;
+
+#endif
+
+ for (;;) {
+ assert_wait((vm_offset_t)&cp->memreq.thread_status, TRUE);
+ thread_block();
+
+ if (thread_should_halt(current_thread()))
+ thread_halt_self();
+ cmd = cp->memreq.cmd;
+ compressor_options = &cp->memreq.comp_opts[0];
+ len = compressor_options[1];
+ if (cmd == PPPIO_XCOMP) {
+ cp->memreq.returned_mem = cp->xcomp->comp_alloc(compressor_options, len);
+ if (!cp->memreq.returned_mem) {
+ cp->memreq.thread_status = ENOSR;
+ } else {
+ cp->memreq.thread_status = 0;
+ }
+ } else {
+ cp->memreq.returned_mem = cp->rcomp->decomp_alloc(compressor_options, len);
+ if (!cp->memreq.returned_mem) {
+ cp->memreq.thread_status = ENOSR;
+ } else {
+ cp->memreq.thread_status = 0;
+ }
+ }
+ }
+}
+
+#endif /* __osf__ */
+
+/* here's the deal with memory allocation under Digital UNIX.
+ * Some other may also benefit from this...
+ * We can't ask for huge chunks of memory in a context where
+ * the caller can't be put to sleep (like, here.) The alloc
+ * is likely to fail. Instead we do this: the first time we
+ * get called, kick off a thread to do the allocation. Return
+ * immediately to the caller with EAGAIN, as an indication that
+ * they should send down the ioctl again. By the time the
+ * second call comes in it's likely that the memory allocation
+ * thread will have returned with the requested memory. We will
+ * continue to return EAGAIN however until the thread has completed.
+ * When it has, we return zero (and the memory) if the allocator
+ * was successful and ENOSR otherwise.
+ *
+ * Callers of the RCOMP and XCOMP ioctls are encouraged (but not
+ * required) to loop for some number of iterations with a small
+ * delay in the loop body (for instance a 1/10-th second "sleep"
+ * via select.)
+ */
+static int
+ppp_comp_wput(q, mp)
+ queue_t *q;
+ mblk_t *mp;
+{
+ struct iocblk *iop;
+ comp_state_t *cp;
+ int error, len, n;
+ int flags, mask;
+ mblk_t *np;
+ struct compressor **comp;
+ struct ppp_stats *psp;
+ struct ppp_comp_stats *csp;
+ unsigned char *opt_data;
+ int nxslots, nrslots;
+
+ cp = (comp_state_t *) q->q_ptr;
+ if (cp == 0) {
+ DPRINT("cp == 0 in ppp_comp_wput\n");
+ freemsg(mp);
+ return 0;
+ }
+
+ switch (mp->b_datap->db_type) {
+
+ case M_DATA:
+ putq(q, mp);
+ break;
+
+ case M_IOCTL:
+ iop = (struct iocblk *) mp->b_rptr;
+ error = EINVAL;
+ switch (iop->ioc_cmd) {
+
+ case PPPIO_CFLAGS:
+ /* set/get CCP state */
+ if (iop->ioc_count != 2 * sizeof(int))
+ break;
+ if (mp->b_cont == 0) {
+ DPRINT1("ppp_comp_wput/%d: PPPIO_CFLAGS b_cont = 0!\n", cp->unit);
+ break;
+ }
+ flags = ((int *) mp->b_cont->b_rptr)[0];
+ mask = ((int *) mp->b_cont->b_rptr)[1];
+ cp->flags = (cp->flags & ~mask) | (flags & mask);
+ if ((mask & CCP_ISOPEN) && (flags & CCP_ISOPEN) == 0) {
+ if (cp->xstate != NULL) {
+ (*cp->xcomp->comp_free)(cp->xstate);
+ cp->xstate = NULL;
+ }
+ if (cp->rstate != NULL) {
+ (*cp->rcomp->decomp_free)(cp->rstate);
+ cp->rstate = NULL;
+ }
+ cp->flags &= ~CCP_ISUP;
+ }
+ error = 0;
+ iop->ioc_count = sizeof(int);
+ ((int *) mp->b_cont->b_rptr)[0] = cp->flags;
+ mp->b_cont->b_wptr = mp->b_cont->b_rptr + sizeof(int);
+ break;
+
+ case PPPIO_VJINIT:
+ /*
+ * Initialize VJ compressor/decompressor
+ */
+ if (iop->ioc_count != 2)
+ break;
+ if (mp->b_cont == 0) {
+ DPRINT1("ppp_comp_wput/%d: PPPIO_VJINIT b_cont = 0!\n", cp->unit);
+ break;
+ }
+ nxslots = mp->b_cont->b_rptr[0] + 1;
+ nrslots = mp->b_cont->b_rptr[1] + 1;
+ if (nxslots > MAX_STATES || nrslots > MAX_STATES)
+ break;
+ vj_compress_init(&cp->vj_comp, nxslots);
+ cp->vj_last_ierrors = cp->stats.ppp_ierrors;
+ error = 0;
+ iop->ioc_count = 0;
+ break;
+
+ case PPPIO_XCOMP:
+ case PPPIO_RCOMP:
+ if (iop->ioc_count <= 0)
+ break;
+ if (mp->b_cont == 0) {
+ DPRINT1("ppp_comp_wput/%d: PPPIO_[XR]COMP b_cont = 0!\n", cp->unit);
+ break;
+ }
+ opt_data = mp->b_cont->b_rptr;
+ len = mp->b_cont->b_wptr - opt_data;
+ if (len > iop->ioc_count)
+ len = iop->ioc_count;
+ if (opt_data[1] < 2 || opt_data[1] > len)
+ break;
+ for (comp = ppp_compressors; *comp != NULL; ++comp)
+ if ((*comp)->compress_proto == opt_data[0]) {
+ /* here's the handler! */
+ error = 0;
+#ifndef __osf__
+ if (iop->ioc_cmd == PPPIO_XCOMP) {
+ /* A previous call may have fetched memory for a compressor
+ * that's now being retired or reset. Free it using it's
+ * mechanism for freeing stuff.
+ */
+ if (cp->xstate != NULL) {
+ (*cp->xcomp->comp_free)(cp->xstate);
+ cp->xstate = NULL;
+ }
+ cp->xcomp = *comp;
+ cp->xstate = (*comp)->comp_alloc(opt_data, len);
+ if (cp->xstate == NULL)
+ error = ENOSR;
+ } else {
+ if (cp->rstate != NULL) {
+ (*cp->rcomp->decomp_free)(cp->rstate);
+ cp->rstate = NULL;
+ }
+ cp->rcomp = *comp;
+ cp->rstate = (*comp)->decomp_alloc(opt_data, len);
+ if (cp->rstate == NULL)
+ error = ENOSR;
+ }
+#else
+ if ((error = cp->memreq.thread_status) != EAGAIN)
+ if (iop->ioc_cmd == PPPIO_XCOMP) {
+ if (cp->xstate) {
+ (*cp->xcomp->comp_free)(cp->xstate);
+ cp->xstate = 0;
+ }
+ /* sanity check for compressor options
+ */
+ if (sizeof (cp->memreq.comp_opts) < len) {
+ printf("can't handle options for compressor %d (%d)\n", opt_data[0],
+ opt_data[1]);
+ cp->memreq.thread_status = ENOSR;
+ cp->memreq.returned_mem = 0;
+ }
+ /* fill in request for the thread and kick it off
+ */
+ if (cp->memreq.thread_status == 0 && !cp->memreq.returned_mem) {
+ bcopy(opt_data, cp->memreq.comp_opts, len);
+ cp->memreq.cmd = PPPIO_XCOMP;
+ cp->xcomp = *comp;
+ error = cp->memreq.thread_status = EAGAIN;
+ thread_wakeup((vm_offset_t)&cp->memreq.thread_status);
+ } else {
+ cp->xstate = cp->memreq.returned_mem;
+ cp->memreq.returned_mem = 0;
+ cp->memreq.thread_status = 0;
+ }
+ } else {
+ if (cp->rstate) {
+ (*cp->rcomp->decomp_free)(cp->rstate);
+ cp->rstate = NULL;
+ }
+ if (sizeof (cp->memreq.comp_opts) < len) {
+ printf("can't handle options for compressor %d (%d)\n", opt_data[0],
+ opt_data[1]);
+ cp->memreq.thread_status = ENOSR;
+ cp->memreq.returned_mem = 0;
+ }
+ if (cp->memreq.thread_status == 0 && !cp->memreq.returned_mem) {
+ bcopy(opt_data, cp->memreq.comp_opts, len);
+ cp->memreq.cmd = PPPIO_RCOMP;
+ cp->rcomp = *comp;
+ error = cp->memreq.thread_status = EAGAIN;
+ thread_wakeup((vm_offset_t)&cp->memreq.thread_status);
+ } else {
+ cp->rstate = cp->memreq.returned_mem;
+ cp->memreq.returned_mem = 0;
+ cp->memreq.thread_status = 0;
+ }
+ }
+#endif
+ break;
+ }
+ iop->ioc_count = 0;
+ break;
+
+ case PPPIO_GETSTAT:
+ if ((cp->flags & LAST_MOD) == 0) {
+ error = -1; /* let the ppp_ahdl module handle it */
+ break;
+ }
+ np = allocb(sizeof(struct ppp_stats), BPRI_HI);
+ if (np == 0) {
+ error = ENOSR;
+ break;
+ }
+ if (mp->b_cont != 0)
+ freemsg(mp->b_cont);
+ mp->b_cont = np;
+ psp = (struct ppp_stats *) np->b_wptr;
+ np->b_wptr += sizeof(struct ppp_stats);
+ iop->ioc_count = sizeof(struct ppp_stats);
+ psp->p = cp->stats;
+ psp->vj = cp->vj_comp.stats;
+ error = 0;
+ break;
+
+ case PPPIO_GETCSTAT:
+ np = allocb(sizeof(struct ppp_comp_stats), BPRI_HI);
+ if (np == 0) {
+ error = ENOSR;
+ break;
+ }
+ if (mp->b_cont != 0)
+ freemsg(mp->b_cont);
+ mp->b_cont = np;
+ csp = (struct ppp_comp_stats *) np->b_wptr;
+ np->b_wptr += sizeof(struct ppp_comp_stats);
+ iop->ioc_count = sizeof(struct ppp_comp_stats);
+ bzero((caddr_t)csp, sizeof(struct ppp_comp_stats));
+ if (cp->xstate != 0)
+ (*cp->xcomp->comp_stat)(cp->xstate, &csp->c);
+ if (cp->rstate != 0)
+ (*cp->rcomp->decomp_stat)(cp->rstate, &csp->d);
+ error = 0;
+ break;
+
+ case PPPIO_DEBUG:
+ if (iop->ioc_count != sizeof(int))
+ break;
+ if (mp->b_cont == 0) {
+ DPRINT1("ppp_comp_wput/%d: PPPIO_DEBUG b_cont = 0!\n", cp->unit);
+ break;
+ }
+ n = *(int *)mp->b_cont->b_rptr;
+ if (n == PPPDBG_LOG + PPPDBG_COMP) {
+ DPRINT1("ppp_comp%d: debug log enabled\n", cp->unit);
+ cp->flags |= DBGLOG;
+ error = 0;
+ iop->ioc_count = 0;
+ } else {
+ error = -1;
+ }
+ break;
+
+ case PPPIO_LASTMOD:
+ cp->flags |= LAST_MOD;
+ error = 0;
+ break;
+
+ default:
+ error = -1;
+ break;
+ }
+
+ if (error < 0)
+ putnext(q, mp);
+ else if (error == 0) {
+ mp->b_datap->db_type = M_IOCACK;
+ qreply(q, mp);
+ } else {
+ mp->b_datap->db_type = M_IOCNAK;
+ iop->ioc_error = error;
+ iop->ioc_count = 0;
+ qreply(q, mp);
+ }
+ break;
+
+ case M_CTL:
+ switch (*mp->b_rptr) {
+ case PPPCTL_MTU:
+ cp->mtu = ((unsigned short *)mp->b_rptr)[1];
+ break;
+ case PPPCTL_MRU:
+ cp->mru = ((unsigned short *)mp->b_rptr)[1];
+ break;
+ case PPPCTL_UNIT:
+ cp->unit = mp->b_rptr[1];
+ break;
+ }
+ putnext(q, mp);
+ break;
+
+ default:
+ putnext(q, mp);
+ }
+
+ return 0;
+}
+
+static int
+ppp_comp_wsrv(q)
+ queue_t *q;
+{
+ mblk_t *mp, *cmp = NULL;
+ comp_state_t *cp;
+ int len, proto, type, hlen, code;
+ struct ip *ip;
+ unsigned char *vjhdr, *dp;
+
+ cp = (comp_state_t *) q->q_ptr;
+ if (cp == 0) {
+ DPRINT("cp == 0 in ppp_comp_wsrv\n");
+ return 0;
+ }
+
+ while ((mp = getq(q)) != 0) {
+ /* assert(mp->b_datap->db_type == M_DATA) */
+#ifdef PRIOQ
+ if (!bcanputnext(q,mp->b_band))
+#else
+ if (!canputnext(q))
+#endif PRIOQ
+ {
+ putbq(q, mp);
+ break;
+ }
+
+ /*
+ * First check the packet length and work out what the protocol is.
+ */
+ len = msgdsize(mp);
+ if (len < PPP_HDRLEN) {
+ DPRINT1("ppp_comp_wsrv: bogus short packet (%d)\n", len);
+ freemsg(mp);
+ cp->stats.ppp_oerrors++;
+ putctl1(RD(q)->q_next, M_CTL, PPPCTL_OERROR);
+ continue;
+ }
+ proto = (MSG_BYTE(mp, 2) << 8) + MSG_BYTE(mp, 3);
+
+ /*
+ * Make sure we've got enough data in the first mblk
+ * and that we are its only user.
+ */
+ if (proto == PPP_CCP)
+ hlen = len;
+ else if (proto == PPP_IP)
+ hlen = PPP_HDRLEN + MAX_IPHDR;
+ else
+ hlen = PPP_HDRLEN;
+ if (hlen > len)
+ hlen = len;
+ if (mp->b_wptr < mp->b_rptr + hlen || mp->b_datap->db_ref > 1) {
+ PULLUP(mp, hlen);
+ if (mp == 0) {
+ DPRINT1("ppp_comp_wsrv: pullup failed (%d)\n", hlen);
+ cp->stats.ppp_oerrors++;
+ putctl1(RD(q)->q_next, M_CTL, PPPCTL_OERROR);
+ continue;
+ }
+ }
+
+ /*
+ * Do VJ compression if requested.
+ */
+ if (proto == PPP_IP && (cp->flags & COMP_VJC)) {
+ ip = (struct ip *) (mp->b_rptr + PPP_HDRLEN);
+ if (ip->ip_p == IPPROTO_TCP) {
+ type = vj_compress_tcp(ip, len - PPP_HDRLEN, &cp->vj_comp,
+ (cp->flags & COMP_VJCCID), &vjhdr);
+ switch (type) {
+ case TYPE_UNCOMPRESSED_TCP:
+ mp->b_rptr[3] = proto = PPP_VJC_UNCOMP;
+ break;
+ case TYPE_COMPRESSED_TCP:
+ dp = vjhdr - PPP_HDRLEN;
+ dp[1] = mp->b_rptr[1]; /* copy control field */
+ dp[0] = mp->b_rptr[0]; /* copy address field */
+ dp[2] = 0; /* set protocol field */
+ dp[3] = proto = PPP_VJC_COMP;
+ mp->b_rptr = dp;
+ break;
+ }
+ }
+ }
+
+ /*
+ * Do packet compression if enabled.
+ */
+ if (proto == PPP_CCP)
+ ppp_comp_ccp(q, mp, 0);
+ else if (proto != PPP_LCP && (cp->flags & CCP_COMP_RUN)
+ && cp->xstate != NULL) {
+ len = msgdsize(mp);
+ (*cp->xcomp->compress)(cp->xstate, &cmp, mp, len,
+ (cp->flags & CCP_ISUP? cp->mtu + PPP_HDRLEN: 0));
+ if (cmp != NULL) {
+#ifdef PRIOQ
+ cmp->b_band=mp->b_band;
+#endif PRIOQ
+ freemsg(mp);
+ mp = cmp;
+ }
+ }
+
+ /*
+ * Do address/control and protocol compression if enabled.
+ */
+ if ((cp->flags & COMP_AC)
+ && !(proto == PPP_LCP && LCP_USE_DFLT(mp))) {
+ mp->b_rptr += 2; /* drop the address & ctrl fields */
+ if (proto < 0x100 && (cp->flags & COMP_PROT))
+ ++mp->b_rptr; /* drop the high protocol byte */
+ } else if (proto < 0x100 && (cp->flags & COMP_PROT)) {
+ /* shuffle up the address & ctrl fields */
+ mp->b_rptr[2] = mp->b_rptr[1];
+ mp->b_rptr[1] = mp->b_rptr[0];
+ ++mp->b_rptr;
+ }
+
+ cp->stats.ppp_opackets++;
+ cp->stats.ppp_obytes += msgdsize(mp);
+ putnext(q, mp);
+ }
+
+ return 0;
+}
+
+static int
+ppp_comp_rput(q, mp)
+ queue_t *q;
+ mblk_t *mp;
+{
+ comp_state_t *cp;
+ struct iocblk *iop;
+ struct ppp_stats *psp;
+
+ cp = (comp_state_t *) q->q_ptr;
+ if (cp == 0) {
+ DPRINT("cp == 0 in ppp_comp_rput\n");
+ freemsg(mp);
+ return 0;
+ }
+
+ switch (mp->b_datap->db_type) {
+
+ case M_DATA:
+ putq(q, mp);
+ break;
+
+ case M_IOCACK:
+ iop = (struct iocblk *) mp->b_rptr;
+ switch (iop->ioc_cmd) {
+ case PPPIO_GETSTAT:
+ /*
+ * Catch this on the way back from the ppp_ahdl module
+ * so we can fill in the VJ stats.
+ */
+ if (mp->b_cont == 0 || iop->ioc_count != sizeof(struct ppp_stats))
+ break;
+ psp = (struct ppp_stats *) mp->b_cont->b_rptr;
+ psp->vj = cp->vj_comp.stats;
+ break;
+ }
+ putnext(q, mp);
+ break;
+
+ case M_CTL:
+ switch (mp->b_rptr[0]) {
+ case PPPCTL_IERROR:
+ ++cp->stats.ppp_ierrors;
+ break;
+ case PPPCTL_OERROR:
+ ++cp->stats.ppp_oerrors;
+ break;
+ }
+ putnext(q, mp);
+ break;
+
+ default:
+ putnext(q, mp);
+ }
+
+ return 0;
+}
+
+static int
+ppp_comp_rsrv(q)
+ queue_t *q;
+{
+ int proto, rv, i;
+ mblk_t *mp, *dmp = NULL, *np;
+ uchar_t *dp, *iphdr;
+ comp_state_t *cp;
+ int len, hlen, vjlen;
+ u_int iphlen;
+
+ cp = (comp_state_t *) q->q_ptr;
+ if (cp == 0) {
+ DPRINT("cp == 0 in ppp_comp_rsrv\n");
+ return 0;
+ }
+
+ while ((mp = getq(q)) != 0) {
+ /* assert(mp->b_datap->db_type == M_DATA) */
+ if (!canputnext(q)) {
+ putbq(q, mp);
+ break;
+ }
+
+ len = msgdsize(mp);
+ cp->stats.ppp_ibytes += len;
+ cp->stats.ppp_ipackets++;
+
+ /*
+ * First work out the protocol and where the PPP header ends.
+ */
+ i = 0;
+ proto = MSG_BYTE(mp, 0);
+ if (proto == PPP_ALLSTATIONS) {
+ i = 2;
+ proto = MSG_BYTE(mp, 2);
+ }
+ if ((proto & 1) == 0) {
+ ++i;
+ proto = (proto << 8) + MSG_BYTE(mp, i);
+ }
+ hlen = i + 1;
+
+ /*
+ * Now reconstruct a complete, contiguous PPP header at the
+ * start of the packet.
+ */
+ if (hlen < ((cp->flags & DECOMP_AC)? 0: 2)
+ + ((cp->flags & DECOMP_PROT)? 1: 2)) {
+ /* count these? */
+ goto bad;
+ }
+ if (mp->b_rptr + hlen > mp->b_wptr) {
+ adjmsg(mp, hlen); /* XXX check this call */
+ hlen = 0;
+ }
+ if (hlen != PPP_HDRLEN) {
+ /*
+ * We need to put some bytes on the front of the packet
+ * to make a full-length PPP header.
+ * If we can put them in *mp, we do, otherwise we
+ * tack another mblk on the front.
+ * XXX we really shouldn't need to carry around
+ * the address and control at this stage.
+ */
+ dp = mp->b_rptr + hlen - PPP_HDRLEN;
+ if (dp < mp->b_datap->db_base || mp->b_datap->db_ref > 1) {
+ np = allocb(PPP_HDRLEN, BPRI_MED);
+ if (np == 0)
+ goto bad;
+ np->b_cont = mp;
+ mp->b_rptr += hlen;
+ mp = np;
+ dp = mp->b_wptr;
+ mp->b_wptr += PPP_HDRLEN;
+ } else
+ mp->b_rptr = dp;
+
+ dp[0] = PPP_ALLSTATIONS;
+ dp[1] = PPP_UI;
+ dp[2] = proto >> 8;
+ dp[3] = proto;
+ }
+
+ /*
+ * Now see if we have a compressed packet to decompress,
+ * or a CCP packet to take notice of.
+ */
+ proto = PPP_PROTOCOL(mp->b_rptr);
+ if (proto == PPP_CCP) {
+ len = msgdsize(mp);
+ if (mp->b_wptr < mp->b_rptr + len) {
+ PULLUP(mp, len);
+ if (mp == 0)
+ goto bad;
+ }
+ ppp_comp_ccp(q, mp, 1);
+ } else if (proto == PPP_COMP) {
+ if ((cp->flags & CCP_ISUP)
+ && (cp->flags & CCP_DECOMP_RUN) && cp->rstate
+ && (cp->flags & CCP_ERR) == 0) {
+ rv = (*cp->rcomp->decompress)(cp->rstate, mp, &dmp);
+ switch (rv) {
+ case DECOMP_OK:
+ freemsg(mp);
+ mp = dmp;
+ if (mp == NULL) {
+ /* no error, but no packet returned either. */
+ continue;
+ }
+ break;
+ case DECOMP_ERROR:
+ cp->flags |= CCP_ERROR;
+ ++cp->stats.ppp_ierrors;
+ putctl1(q->q_next, M_CTL, PPPCTL_IERROR);
+ break;
+ case DECOMP_FATALERROR:
+ cp->flags |= CCP_FATALERROR;
+ ++cp->stats.ppp_ierrors;
+ putctl1(q->q_next, M_CTL, PPPCTL_IERROR);
+ break;
+ }
+ }
+ } else if (cp->rstate && (cp->flags & CCP_DECOMP_RUN)) {
+ (*cp->rcomp->incomp)(cp->rstate, mp);
+ }
+
+ /*
+ * Now do VJ decompression.
+ */
+ proto = PPP_PROTOCOL(mp->b_rptr);
+ if (proto == PPP_VJC_COMP || proto == PPP_VJC_UNCOMP) {
+ len = msgdsize(mp) - PPP_HDRLEN;
+ if ((cp->flags & DECOMP_VJC) == 0 || len <= 0)
+ goto bad;
+
+ /*
+ * Advance past the ppp header.
+ * Here we assume that the whole PPP header is in the first mblk.
+ */
+ np = mp;
+ dp = np->b_rptr + PPP_HDRLEN;
+ if (dp >= mp->b_wptr) {
+ np = np->b_cont;
+ dp = np->b_rptr;
+ }
+
+ /*
+ * Make sure we have sufficient contiguous data at this point.
+ */
+ hlen = (proto == PPP_VJC_COMP)? MAX_VJHDR: MAX_IPHDR;
+ if (hlen > len)
+ hlen = len;
+ if (np->b_wptr < dp + hlen || np->b_datap->db_ref > 1) {
+ PULLUP(mp, hlen + PPP_HDRLEN);
+ if (mp == 0)
+ goto bad;
+ np = mp;
+ dp = np->b_rptr + PPP_HDRLEN;
+ }
+
+ if (proto == PPP_VJC_COMP) {
+ /*
+ * Decompress VJ-compressed packet.
+ * First reset compressor if an input error has occurred.
+ */
+ if (cp->stats.ppp_ierrors != cp->vj_last_ierrors) {
+ if (cp->flags & DBGLOG)
+ DPRINT1("ppp%d: resetting VJ\n", cp->unit);
+ vj_uncompress_err(&cp->vj_comp);
+ cp->vj_last_ierrors = cp->stats.ppp_ierrors;
+ }
+
+ vjlen = vj_uncompress_tcp(dp, np->b_wptr - dp, len,
+ &cp->vj_comp, &iphdr, &iphlen);
+ if (vjlen < 0) {
+ if (cp->flags & DBGLOG)
+ DPRINT2("ppp%d: vj_uncomp_tcp failed, pkt len %d\n",
+ cp->unit, len);
+ ++cp->vj_last_ierrors; /* so we don't reset next time */
+ goto bad;
+ }
+
+ /* drop ppp and vj headers off */
+ if (mp != np) {
+ freeb(mp);
+ mp = np;
+ }
+ mp->b_rptr = dp + vjlen;
+
+ /* allocate a new mblk for the ppp and ip headers */
+ if ((np = allocb(iphlen + PPP_HDRLEN + 4, BPRI_MED)) == 0)
+ goto bad;
+ dp = np->b_rptr; /* prepend mblk with TCP/IP hdr */
+ dp[0] = PPP_ALLSTATIONS; /* reconstruct PPP header */
+ dp[1] = PPP_UI;
+ dp[2] = PPP_IP >> 8;
+ dp[3] = PPP_IP;
+ bcopy((caddr_t)iphdr, (caddr_t)dp + PPP_HDRLEN, iphlen);
+ np->b_wptr = dp + iphlen + PPP_HDRLEN;
+ np->b_cont = mp;
+
+ /* XXX there seems to be a bug which causes panics in strread
+ if we make an mbuf with only the IP header in it :-( */
+ if (mp->b_wptr - mp->b_rptr > 4) {
+ bcopy((caddr_t)mp->b_rptr, (caddr_t)np->b_wptr, 4);
+ mp->b_rptr += 4;
+ np->b_wptr += 4;
+ } else {
+ bcopy((caddr_t)mp->b_rptr, (caddr_t)np->b_wptr,
+ mp->b_wptr - mp->b_rptr);
+ np->b_wptr += mp->b_wptr - mp->b_rptr;
+ np->b_cont = mp->b_cont;
+ freeb(mp);
+ }
+
+ mp = np;
+
+ } else {
+ /*
+ * "Decompress" a VJ-uncompressed packet.
+ */
+ cp->vj_last_ierrors = cp->stats.ppp_ierrors;
+ if (!vj_uncompress_uncomp(dp, hlen, &cp->vj_comp)) {
+ if (cp->flags & DBGLOG)
+ DPRINT2("ppp%d: vj_uncomp_uncomp failed, pkt len %d\n",
+ cp->unit, len);
+ ++cp->vj_last_ierrors; /* don't need to reset next time */
+ goto bad;
+ }
+ mp->b_rptr[3] = PPP_IP; /* fix up the PPP protocol field */
+ }
+ }
+
+ putnext(q, mp);
+ continue;
+
+ bad:
+ if (mp != 0)
+ freemsg(mp);
+ cp->stats.ppp_ierrors++;
+ putctl1(q->q_next, M_CTL, PPPCTL_IERROR);
+ }
+
+ return 0;
+}
+
+/*
+ * Handle a CCP packet being sent or received.
+ * Here all the data in the packet is in a single mbuf.
+ */
+static void
+ppp_comp_ccp(q, mp, rcvd)
+ queue_t *q;
+ mblk_t *mp;
+ int rcvd;
+{
+ int len, clen;
+ comp_state_t *cp;
+ unsigned char *dp;
+
+ len = msgdsize(mp);
+ if (len < PPP_HDRLEN + CCP_HDRLEN)
+ return;
+
+ cp = (comp_state_t *) q->q_ptr;
+ dp = mp->b_rptr + PPP_HDRLEN;
+ len -= PPP_HDRLEN;
+ clen = CCP_LENGTH(dp);
+ if (clen > len)
+ return;
+
+ switch (CCP_CODE(dp)) {
+ case CCP_CONFREQ:
+ case CCP_TERMREQ:
+ case CCP_TERMACK:
+ cp->flags &= ~CCP_ISUP;
+ break;
+
+ case CCP_CONFACK:
+ if ((cp->flags & (CCP_ISOPEN | CCP_ISUP)) == CCP_ISOPEN
+ && clen >= CCP_HDRLEN + CCP_OPT_MINLEN
+ && clen >= CCP_HDRLEN + CCP_OPT_LENGTH(dp + CCP_HDRLEN)) {
+ if (!rcvd) {
+ if (cp->xstate != NULL
+ && (*cp->xcomp->comp_init)
+ (cp->xstate, dp + CCP_HDRLEN, clen - CCP_HDRLEN,
+ cp->unit, 0, ((cp->flags & DBGLOG) != 0)))
+ cp->flags |= CCP_COMP_RUN;
+ } else {
+ if (cp->rstate != NULL
+ && (*cp->rcomp->decomp_init)
+ (cp->rstate, dp + CCP_HDRLEN, clen - CCP_HDRLEN,
+ cp->unit, 0, cp->mru, ((cp->flags & DBGLOG) != 0)))
+ cp->flags = (cp->flags & ~CCP_ERR) | CCP_DECOMP_RUN;
+ }
+ }
+ break;
+
+ case CCP_RESETACK:
+ if (cp->flags & CCP_ISUP) {
+ if (!rcvd) {
+ if (cp->xstate && (cp->flags & CCP_COMP_RUN))
+ (*cp->xcomp->comp_reset)(cp->xstate);
+ } else {
+ if (cp->rstate && (cp->flags & CCP_DECOMP_RUN)) {
+ (*cp->rcomp->decomp_reset)(cp->rstate);
+ cp->flags &= ~CCP_ERROR;
+ }
+ }
+ }
+ break;
+ }
+}
+
+#if 0
+dump_msg(mp)
+ mblk_t *mp;
+{
+ dblk_t *db;
+
+ while (mp != 0) {
+ db = mp->b_datap;
+ DPRINT2("mp=%x cont=%x ", mp, mp->b_cont);
+ DPRINT3("rptr=%x wptr=%x datap=%x\n", mp->b_rptr, mp->b_wptr, db);
+ DPRINT2(" base=%x lim=%x", db->db_base, db->db_lim);
+ DPRINT2(" ref=%d type=%d\n", db->db_ref, db->db_type);
+ mp = mp->b_cont;
+ }
+}
+#endif
+
+static int
+msg_byte(mp, i)
+ mblk_t *mp;
+ unsigned int i;
+{
+ while (mp != 0 && i >= mp->b_wptr - mp->b_rptr)
+ mp = mp->b_cont;
+ if (mp == 0)
+ return -1;
+ return mp->b_rptr[i];
+}
diff --git a/mdk-stage1/ppp/solaris/ppp_comp_mod.c b/mdk-stage1/ppp/solaris/ppp_comp_mod.c
new file mode 100644
index 000000000..d22fbc81f
--- /dev/null
+++ b/mdk-stage1/ppp/solaris/ppp_comp_mod.c
@@ -0,0 +1,81 @@
+/*
+ * ppp_comp_mod.c - modload support for PPP compression STREAMS module.
+ *
+ * Copyright (c) 1994 The Australian National University.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation is hereby granted, provided that the above copyright
+ * notice appears in all copies. This software is provided without any
+ * warranty, express or implied. The Australian National University
+ * makes no representations about the suitability of this software for
+ * any purpose.
+ *
+ * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
+ * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
+ * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
+ * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
+ * OR MODIFICATIONS.
+ *
+ * $Id: ppp_comp_mod.c 195720 2001-06-11 11:44:34Z gc $
+ */
+
+/*
+ * This file is used under Solaris 2.
+ */
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/conf.h>
+#include <sys/modctl.h>
+#include <sys/sunddi.h>
+
+extern struct streamtab ppp_compinfo;
+
+static struct fmodsw fsw = {
+ "ppp_comp",
+ &ppp_compinfo,
+ D_NEW | D_MP | D_MTQPAIR
+};
+
+extern struct mod_ops mod_strmodops;
+
+static struct modlstrmod modlstrmod = {
+ &mod_strmodops,
+ "PPP compression module",
+ &fsw
+};
+
+static struct modlinkage modlinkage = {
+ MODREV_1,
+ (void *) &modlstrmod,
+ NULL
+};
+
+/*
+ * Entry points for modloading.
+ */
+int
+_init(void)
+{
+ return mod_install(&modlinkage);
+}
+
+int
+_fini(void)
+{
+ return mod_remove(&modlinkage);
+}
+
+int
+_info(mip)
+ struct modinfo *mip;
+{
+ return mod_info(&modlinkage, mip);
+}
diff --git a/mdk-stage1/ppp/solaris/ppp_mod.c b/mdk-stage1/ppp/solaris/ppp_mod.c
new file mode 100644
index 000000000..7a4f52add
--- /dev/null
+++ b/mdk-stage1/ppp/solaris/ppp_mod.c
@@ -0,0 +1,174 @@
+/*
+ * ppp_mod.c - modload support for PPP pseudo-device driver.
+ *
+ * Copyright (c) 1994 The Australian National University.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation is hereby granted, provided that the above copyright
+ * notice appears in all copies. This software is provided without any
+ * warranty, express or implied. The Australian National University
+ * makes no representations about the suitability of this software for
+ * any purpose.
+ *
+ * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
+ * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
+ * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
+ * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
+ * OR MODIFICATIONS.
+ *
+ * $Id: ppp_mod.c 195720 2001-06-11 11:44:34Z gc $
+ */
+
+/*
+ * This file is used under Solaris 2.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/conf.h>
+#include <sys/modctl.h>
+#include <sys/sunddi.h>
+#include <sys/ksynch.h>
+
+#ifdef __STDC__
+#define __P(x) x
+#else
+#define __P(x) ()
+#endif
+
+static int ppp_identify __P((dev_info_t *));
+static int ppp_attach __P((dev_info_t *, ddi_attach_cmd_t));
+static int ppp_detach __P((dev_info_t *, ddi_detach_cmd_t));
+static int ppp_devinfo __P((dev_info_t *, ddi_info_cmd_t, void *, void **));
+
+extern struct streamtab pppinfo;
+extern krwlock_t ppp_lower_lock;
+
+static dev_info_t *ppp_dip;
+
+static struct cb_ops cb_ppp_ops = {
+ nulldev, nulldev, nodev, nodev, /* cb_open, ... */
+ nodev, nodev, nodev, nodev, /* cb_dump, ... */
+ nodev, nodev, nodev, nochpoll, /* cb_devmap, ... */
+ ddi_prop_op, /* cb_prop_op */
+ &pppinfo, /* cb_stream */
+ D_NEW|D_MP|D_MTQPAIR|D_MTOUTPERIM|D_MTOCEXCL /* cb_flag */
+};
+
+static struct dev_ops ppp_ops = {
+ DEVO_REV, /* devo_rev */
+ 0, /* devo_refcnt */
+ ppp_devinfo, /* devo_getinfo */
+ ppp_identify, /* devo_identify */
+ nulldev, /* devo_probe */
+ ppp_attach, /* devo_attach */
+ ppp_detach, /* devo_detach */
+ nodev, /* devo_reset */
+ &cb_ppp_ops, /* devo_cb_ops */
+ NULL /* devo_bus_ops */
+};
+
+/*
+ * Module linkage information
+ */
+
+static struct modldrv modldrv = {
+ &mod_driverops, /* says this is a pseudo driver */
+ "PPP-2.3 multiplexing driver",
+ &ppp_ops /* driver ops */
+};
+
+static struct modlinkage modlinkage = {
+ MODREV_1,
+ (void *) &modldrv,
+ NULL
+};
+
+int
+_init(void)
+{
+ return mod_install(&modlinkage);
+}
+
+int
+_fini(void)
+{
+ return mod_remove(&modlinkage);
+}
+
+int
+_info(mip)
+ struct modinfo *mip;
+{
+ return mod_info(&modlinkage, mip);
+}
+
+static int
+ppp_identify(dip)
+ dev_info_t *dip;
+{
+ return strcmp(ddi_get_name(dip), "ppp") == 0? DDI_IDENTIFIED:
+ DDI_NOT_IDENTIFIED;
+}
+
+static int
+ppp_attach(dip, cmd)
+ dev_info_t *dip;
+ ddi_attach_cmd_t cmd;
+{
+
+ if (cmd != DDI_ATTACH)
+ return DDI_FAILURE;
+ if (ddi_create_minor_node(dip, "ppp", S_IFCHR, 0, DDI_PSEUDO, CLONE_DEV)
+ == DDI_FAILURE) {
+ ddi_remove_minor_node(dip, NULL);
+ return DDI_FAILURE;
+ }
+ rw_init(&ppp_lower_lock, NULL, RW_DRIVER, NULL);
+ return DDI_SUCCESS;
+}
+
+static int
+ppp_detach(dip, cmd)
+ dev_info_t *dip;
+ ddi_detach_cmd_t cmd;
+{
+ rw_destroy(&ppp_lower_lock);
+ ddi_remove_minor_node(dip, NULL);
+ return DDI_SUCCESS;
+}
+
+static int
+ppp_devinfo(dip, cmd, arg, result)
+ dev_info_t *dip;
+ ddi_info_cmd_t cmd;
+ void *arg;
+ void **result;
+{
+ int error;
+
+ error = DDI_SUCCESS;
+ switch (cmd) {
+ case DDI_INFO_DEVT2DEVINFO:
+ if (ppp_dip == NULL)
+ error = DDI_FAILURE;
+ else
+ *result = (void *) ppp_dip;
+ break;
+ case DDI_INFO_DEVT2INSTANCE:
+ *result = NULL;
+ break;
+ default:
+ error = DDI_FAILURE;
+ }
+ return error;
+}
diff --git a/mdk-stage1/ppp/solaris/ppp_mod.h b/mdk-stage1/ppp/solaris/ppp_mod.h
new file mode 100644
index 000000000..f0af00886
--- /dev/null
+++ b/mdk-stage1/ppp/solaris/ppp_mod.h
@@ -0,0 +1,190 @@
+/*
+ * Miscellaneous definitions for PPP STREAMS modules.
+ */
+
+/*
+ * Macros for allocating and freeing kernel memory.
+ */
+#ifdef SVR4 /* SVR4, including Solaris 2 */
+#include <sys/kmem.h>
+#define ALLOC_SLEEP(n) kmem_alloc((n), KM_SLEEP)
+#define ALLOC_NOSLEEP(n) kmem_alloc((n), KM_NOSLEEP)
+#define FREE(p, n) kmem_free((p), (n))
+#endif
+
+#ifdef SUNOS4
+#include <sys/kmem_alloc.h> /* SunOS 4.x */
+#define ALLOC_SLEEP(n) kmem_alloc((n), KMEM_SLEEP)
+#define ALLOC_NOSLEEP(n) kmem_alloc((n), KMEM_NOSLEEP)
+#define FREE(p, n) kmem_free((p), (n))
+#define NOTSUSER() (suser()? 0: EPERM)
+#define bcanputnext(q, band) canputnext((q))
+#endif /* SunOS 4 */
+
+#ifdef __osf__
+#include <sys/malloc.h>
+
+/* caution: this mirrors macros in sys/malloc.h, and uses interfaces
+ * which are subject to change.
+ * The problems are that:
+ * - the official MALLOC macro wants the lhs of the assignment as an argument,
+ * and it takes care of the assignment itself (yuck.)
+ * - PPP insists on using "FREE" which conflicts with a macro of the same name.
+ *
+ */
+#ifdef BUCKETINDX /* V2.0 */
+#define ALLOC_SLEEP(n) (void *)malloc((u_long)(n), BUCKETP(n), M_DEVBUF, M_WAITOK)
+#define ALLOC_NOSLEEP(n) (void *)malloc((u_long)(n), BUCKETP(n), M_DEVBUF, M_NOWAIT)
+#else
+#define ALLOC_SLEEP(n) (void *)malloc((u_long)(n), BUCKETINDEX(n), M_DEVBUF, M_WAITOK)
+#define ALLOC_NOSLEEP(n) (void *)malloc((u_long)(n), BUCKETINDEX(n), M_DEVBUF, M_NOWAIT)
+#endif
+
+#define bcanputnext(q, band) canputnext((q))
+
+#ifdef FREE
+#undef FREE
+#endif
+#define FREE(p, n) free((void *)(p), M_DEVBUF)
+
+#define NO_DLPI 1
+
+#ifndef IFT_PPP
+#define IFT_PPP 0x17
+#endif
+
+#include <sys/proc.h>
+#define NOTSUSER() (suser(u.u_procp->p_rcred, &u.u_acflag) ? EPERM : 0)
+
+/* #include "ppp_osf.h" */
+
+#endif /* __osf__ */
+
+#ifdef AIX4
+#define ALLOC_SLEEP(n) xmalloc((n), 0, pinned_heap) /* AIX V4.x */
+#define ALLOC_NOSLEEP(n) xmalloc((n), 0, pinned_heap) /* AIX V4.x */
+#define FREE(p, n) xmfree((p), pinned_heap)
+#define NOTSUSER() (suser()? 0: EPERM)
+#endif /* AIX */
+
+/*
+ * Macros for printing debugging stuff.
+ */
+#ifdef DEBUG
+#if defined(SVR4) || defined(__osf__)
+#if defined(SNI)
+#include <sys/strlog.h>
+#define STRLOG_ID 4712
+#define DPRINT(f) strlog(STRLOG_ID, 0, 0, SL_TRACE, f)
+#define DPRINT1(f, a1) strlog(STRLOG_ID, 0, 0, SL_TRACE, f, a1)
+#define DPRINT2(f, a1, a2) strlog(STRLOG_ID, 0, 0, SL_TRACE, f, a1, a2)
+#define DPRINT3(f, a1, a2, a3) strlog(STRLOG_ID, 0, 0, SL_TRACE, f, a1, a2, a3)
+#else
+#define DPRINT(f) cmn_err(CE_CONT, f)
+#define DPRINT1(f, a1) cmn_err(CE_CONT, f, a1)
+#define DPRINT2(f, a1, a2) cmn_err(CE_CONT, f, a1, a2)
+#define DPRINT3(f, a1, a2, a3) cmn_err(CE_CONT, f, a1, a2, a3)
+#endif /* SNI */
+#else
+#define DPRINT(f) printf(f)
+#define DPRINT1(f, a1) printf(f, a1)
+#define DPRINT2(f, a1, a2) printf(f, a1, a2)
+#define DPRINT3(f, a1, a2, a3) printf(f, a1, a2, a3)
+#endif /* SVR4 or OSF */
+
+#else
+#define DPRINT(f) 0
+#define DPRINT1(f, a1) 0
+#define DPRINT2(f, a1, a2) 0
+#define DPRINT3(f, a1, a2, a3) 0
+#endif /* DEBUG */
+
+#ifndef SVR4
+typedef unsigned char uchar_t;
+typedef unsigned short ushort_t;
+#ifndef __osf__
+typedef int minor_t;
+#endif
+#endif
+
+/*
+ * If we don't have multithreading support, define substitutes.
+ */
+#ifndef D_MP
+# define qprocson(q)
+# define qprocsoff(q)
+# define put(q, mp) ((*(q)->q_qinfo->qi_putp)((q), (mp)))
+# define canputnext(q) canput((q)->q_next)
+# define qwriter(q, mp, func, scope) (func)((q), (mp))
+#endif
+
+#ifdef D_MP
+/* Use msgpullup if we have other multithreading support. */
+#define PULLUP(mp, len) \
+ do { \
+ mblk_t *np = msgpullup((mp), (len)); \
+ freemsg((mp)); \
+ mp = np; \
+ } while (0)
+
+#else
+/* Use pullupmsg if we don't have any multithreading support. */
+#define PULLUP(mp, len) \
+ do { \
+ if (!pullupmsg((mp), (len))) { \
+ freemsg((mp)); \
+ mp = 0; \
+ } \
+ } while (0)
+#endif
+
+/*
+ * How to declare the open and close procedures for a module.
+ */
+#ifdef SVR4
+#define MOD_OPEN_DECL(name) \
+static int name __P((queue_t *, dev_t *, int, int, cred_t *))
+
+#define MOD_CLOSE_DECL(name) \
+static int name __P((queue_t *, int, cred_t *))
+
+#define MOD_OPEN(name) \
+static int name(q, devp, flag, sflag, credp) \
+ queue_t *q; \
+ dev_t *devp; \
+ int flag, sflag; \
+ cred_t *credp;
+
+#define MOD_CLOSE(name) \
+static int name(q, flag, credp) \
+ queue_t *q; \
+ int flag; \
+ cred_t *credp;
+
+#define OPEN_ERROR(x) return (x)
+#define DRV_OPEN_OK(dev) return 0
+
+#define NOTSUSER() (drv_priv(credp))
+
+#else /* not SVR4 */
+#define MOD_OPEN_DECL(name) \
+static int name __P((queue_t *, int, int, int))
+
+#define MOD_CLOSE_DECL(name) \
+static int name __P((queue_t *, int))
+
+#define MOD_OPEN(name) \
+static int name(q, dev, flag, sflag) \
+ queue_t *q; \
+ int dev; \
+ int flag, sflag;
+
+#define MOD_CLOSE(name) \
+static int name(q, flag) \
+ queue_t *q; \
+ int flag;
+
+#define OPEN_ERROR(x) { u.u_error = (x); return OPENFAIL; }
+#define DRV_OPEN_OK(dev) return (dev)
+
+#endif /* SVR4 */
diff --git a/mdk-stage1/ppp/sunos4/Makedefs b/mdk-stage1/ppp/sunos4/Makedefs
new file mode 100644
index 000000000..8b56a2b67
--- /dev/null
+++ b/mdk-stage1/ppp/sunos4/Makedefs
@@ -0,0 +1,13 @@
+#
+# defines common to several Makefiles
+#
+
+INSTALL= install -o root -g daemon
+
+BINDIR = /usr/local/etc
+MANDIR = /usr/local/man
+ETCDIR = /etc/ppp
+
+# To use gcc, uncomment the next line.
+#CC = gcc
+COPTS = -O
diff --git a/mdk-stage1/ppp/sunos4/Makefile b/mdk-stage1/ppp/sunos4/Makefile
new file mode 100644
index 000000000..e763b455e
--- /dev/null
+++ b/mdk-stage1/ppp/sunos4/Makefile
@@ -0,0 +1,57 @@
+#
+# Makefile for STREAMS modules for SunOS 4.
+#
+# $Id: Makefile 195720 2001-06-11 11:44:34Z gc $
+#
+
+include Makedefs
+
+LD = /usr/bin/ld # make sure we don't get gnu ld
+
+# Defining __$(ARCH)__ is for gcc's broken version of sun/vddrv.h.
+ARCH = `/bin/arch -k`
+DEFINES= -DKERNEL -D_KERNEL -DSUNOS4 -D$(ARCH) -D__$(ARCH)__ \
+ -DDEBUG -DNO_DLPI -DSNIT_SUPPORT
+CFLAGS= $(DEFINES) -I../include $(COPTS)
+
+MODULES= ppp_mod.o ppp_ahdl_mod.o ppp_comp_mod.o if_ppp_mod.o
+
+all: $(MODULES)
+
+ppp_mod.o: ppp.o ppp_vdcmd.o
+ $(LD) -r -o ppp_mod.o ppp.o ppp_vdcmd.o
+
+ppp_ahdl_mod.o: ppp_ahdlc.o ppp_ahdlc_vdcmd.o
+ $(LD) -r -o ppp_ahdl_mod.o ppp_ahdlc.o ppp_ahdlc_vdcmd.o
+
+COMP_OBJS = ppp_comp.o bsd-comp.o deflate.o zlib.o vjcompress.o \
+ ppp_comp_vdcmd.o
+ppp_comp_mod.o: $(COMP_OBJS)
+ $(LD) -r -o $@ $(COMP_OBJS)
+
+if_ppp.o: ../modules/if_ppp.c
+ $(CC) $(CFLAGS) -c $?
+bsd-comp.o: ../modules/bsd-comp.c
+ $(CC) $(CFLAGS) -c $?
+deflate.o: ../modules/deflate.c
+ $(CC) $(CFLAGS) -c $?
+ppp.o: ../modules/ppp.c
+ $(CC) $(CFLAGS) -c $?
+ppp_ahdlc.o: ../modules/ppp_ahdlc.c
+ $(CC) $(CFLAGS) -c $?
+ppp_comp.o: ../modules/ppp_comp.c
+ $(CC) $(CFLAGS) -c $?
+vjcompress.o: ../modules/vjcompress.c
+ $(CC) $(CFLAGS) -c $?
+zlib.o: ../common/zlib.c
+ $(CC) $(CFLAGS) -c $?
+
+if_ppp_mod.o: if_ppp.o if_ppp_vdcmd.o
+ $(LD) -r -o if_ppp_mod.o if_ppp.o if_ppp_vdcmd.o
+
+install: all
+ $(INSTALL) $(MODULES) $(BINDIR)
+ ./ppp.INSTALL
+
+clean:
+ rm -f ppp ppp_comp ppp_ahdl *.o *~ core
diff --git a/mdk-stage1/ppp/sunos4/Makefile.top b/mdk-stage1/ppp/sunos4/Makefile.top
new file mode 100644
index 000000000..c86e0884d
--- /dev/null
+++ b/mdk-stage1/ppp/sunos4/Makefile.top
@@ -0,0 +1,46 @@
+#
+# ppp top level makefile
+#
+
+include sunos4/Makedefs
+
+all:
+ cd chat; $(MAKE) all
+ cd pppd; $(MAKE) all
+ cd pppstats; $(MAKE) all
+ cd sunos4; $(MAKE) all
+ cd pppdump; $(MAKE) all
+
+install: $(BINDIR) $(MANDIR)/man8 install-progs install-etcppp
+
+install-progs:
+ cd chat; $(MAKE) install
+ cd pppd; $(MAKE) install
+ cd pppstats; $(MAKE) install
+ cd pppdump; $(MAKE) install
+ cd sunos4; $(MAKE) install
+
+install-etcppp: $(ETCDIR) $(ETCDIR)/options $(ETCDIR)/pap-secrets \
+ $(ETCDIR)/chap-secrets
+
+$(ETCDIR)/options:
+ $(INSTALL) -c -m 644 etc.ppp/options $@
+$(ETCDIR)/pap-secrets:
+ $(INSTALL) -c -m 600 etc.ppp/pap-secrets $@
+$(ETCDIR)/chap-secrets:
+ $(INSTALL) -c -m 600 etc.ppp/chap-secrets $@
+
+$(BINDIR):
+ $(INSTALL) -d -m 755 $@
+$(MANDIR)/man8:
+ $(INSTALL) -d -m 755 $@
+$(ETCDIR):
+ $(INSTALL) -d -m 755 $@
+
+clean:
+ rm -f *~
+ cd chat; $(MAKE) clean
+ cd pppd; $(MAKE) clean
+ cd pppstats; $(MAKE) clean
+ cd sunos4; $(MAKE) clean
+
diff --git a/mdk-stage1/ppp/sunos4/if_ppp_vdcmd.c b/mdk-stage1/ppp/sunos4/if_ppp_vdcmd.c
new file mode 100644
index 000000000..2bf9710f4
--- /dev/null
+++ b/mdk-stage1/ppp/sunos4/if_ppp_vdcmd.c
@@ -0,0 +1,57 @@
+#include <sys/types.h>
+#include <sys/errno.h>
+#include <sys/conf.h>
+#include <sun/vddrv.h>
+
+extern struct streamtab if_pppinfo;
+
+static struct vdldrv vd = {
+ VDMAGIC_USER,
+ "if_ppp"
+};
+
+static int fmodsw_index = -1;
+
+int
+if_ppp_vdcmd(fun, vdp, vdi, vds)
+ unsigned int fun;
+ struct vddrv *vdp;
+ addr_t vdi;
+ struct vdstat *vds;
+{
+ int n, error;
+
+ switch (fun) {
+ case VDLOAD:
+ vdp->vdd_vdtab = (struct vdlinkage *) &vd;
+ if (fmodsw_index >= 0)
+ return EBUSY;
+ for (n = 0; n < fmodcnt; ++n)
+ if (fmodsw[n].f_str == 0)
+ break;
+ if (n >= fmodcnt)
+ return ENODEV;
+ strncpy(fmodsw[n].f_name, vd.Drv_name, FMNAMESZ+1);
+ fmodsw[n].f_str = &if_pppinfo;
+ fmodsw_index = n;
+ break;
+
+ case VDUNLOAD:
+ if (fmodsw_index <= 0)
+ return EINVAL;
+ error = if_ppp_unload();
+ if (error != 0)
+ return error;
+ fmodsw[fmodsw_index].f_name[0] = 0;
+ fmodsw[fmodsw_index].f_str = 0;
+ fmodsw_index = -1;
+ break;
+
+ case VDSTAT:
+ break;
+
+ default:
+ return EIO;
+ }
+ return 0;
+}
diff --git a/mdk-stage1/ppp/sunos4/ppp.INSTALL b/mdk-stage1/ppp/sunos4/ppp.INSTALL
new file mode 100755
index 000000000..0018bf8d0
--- /dev/null
+++ b/mdk-stage1/ppp/sunos4/ppp.INSTALL
@@ -0,0 +1,104 @@
+#!/bin/sh
+
+# Script for loading, unloading, etc. ppp modules.
+
+moddir=/usr/local/etc
+etcppp=/etc/ppp
+
+PATH=/usr/etc:/usr/bin
+
+# Check that we're superuser
+touch /tmp/su$$
+if chown root /tmp/su$$ >/dev/null; then :
+else
+ echo "$0: must be root."
+ rm -f /tmp/su$$
+ exit 1
+fi
+rm -f /tmp/su$$
+
+case "$0" in
+*ppp.INSTALL)
+ if [ ! -f ppp.INSTALL ]; then
+ echo "ppp.INSTALL: not found"
+ exit 1
+ fi
+ for n in INSTALL LOAD UNLOAD MKDEV RMDEV; do
+ if [ -h /dev/ppp.$n -o -f /dev/ppp.$n ]; then
+ rm /dev/ppp.$n
+ fi
+ done
+ cp ppp.INSTALL /dev
+ for n in LOAD UNLOAD MKDEV RMDEV; do
+ ln -s ppp.INSTALL /dev/ppp.$n
+ done
+ ;;
+
+*ppp.LOAD)
+ if modstat | grep -w ppp >/dev/null; then
+ echo "ppp driver is already loaded."
+ exit 1
+ fi
+ if modstat | grep -w if_ppp >/dev/null; then
+ echo "if_ppp module already loaded: not reloading."
+ else
+ echo -n "if_ppp: "
+ modload $moddir/if_ppp_mod.o -sym -entry _if_ppp_vdcmd \
+ -o $etcppp/if_ppp_mod
+ fi
+ echo -n "ppp: "
+ modload $moddir/ppp_mod.o -sym -entry _ppp_vdcmd -exec /dev/ppp.MKDEV \
+ -o $etcppp/ppp_mod
+ echo -n "ppp_comp: "
+ modload $moddir/ppp_comp_mod.o -sym -entry _ppp_comp_vdcmd \
+ -o $etcppp/ppp_comp
+ echo -n "ppp_ahdl: "
+ modload $moddir/ppp_ahdl_mod.o -sym -entry _ppp_ahdlc_vdcmd \
+ -o $etcppp/ppp_ahdl
+ exit 0
+ ;;
+
+*ppp.MKDEV)
+ # args: module number, type, b-major, c-major
+ if [ $# -ne 4 ]; then
+ echo "Usage: $0 module-id module-type b-major c-major"
+ exit 1
+ fi
+ if [ "$2" -ne "12345607" -a "$2" -ne "12345600" ]; then
+ echo "$0: $2: bad module type"
+ exit 1
+ fi
+ rm -f /dev/ppp
+ # we "just know" that 37 is the major number of the clone driver
+ mknod /dev/ppp c 37 $4
+ chmod 644 /dev/ppp
+ exit 0
+ ;;
+
+*ppp.UNLOAD)
+ stat=0
+ if modstat | grep -w if_ppp >/dev/null; then
+ echo "$0: not unloading if_ppp module."
+ fi
+ for mod in ppp ppp_comp ppp_ahdl; do
+ id=`modstat | grep -w $mod | awk '{print $1}'`
+ if [ x$id = x ]; then
+ echo "$mod is not loaded."
+ stat=1
+ else
+ modunload -id $id
+ fi
+ done
+ exit $stat
+ ;;
+
+*ppp.RMDEV)
+ rm -f /dev/ppp
+ exit 0
+ ;;
+
+*)
+ echo "Invocation names: ppp.INSTALL ppp.LOAD ppp.UNLOAD ppp.MKDEV ppp.RMDEV"
+ exit 1
+ ;;
+esac
diff --git a/mdk-stage1/ppp/sunos4/ppp_ahdlc_vdcmd.c b/mdk-stage1/ppp/sunos4/ppp_ahdlc_vdcmd.c
new file mode 100644
index 000000000..2dbe8262b
--- /dev/null
+++ b/mdk-stage1/ppp/sunos4/ppp_ahdlc_vdcmd.c
@@ -0,0 +1,57 @@
+#include <sys/types.h>
+#include <sys/errno.h>
+#include <sys/conf.h>
+#include <sun/vddrv.h>
+
+extern struct streamtab ppp_ahdlcinfo;
+extern int ppp_ahdlc_count;
+
+static struct vdldrv vd = {
+ VDMAGIC_USER,
+ "ppp_ahdl"
+};
+
+static int fmodsw_index = -1;
+
+int
+ppp_ahdlc_vdcmd(fun, vdp, vdi, vds)
+ unsigned int fun;
+ struct vddrv *vdp;
+ addr_t vdi;
+ struct vdstat *vds;
+{
+ int n;
+
+ switch (fun) {
+ case VDLOAD:
+ vdp->vdd_vdtab = (struct vdlinkage *) &vd;
+ if (fmodsw_index >= 0)
+ return EBUSY;
+ for (n = 0; n < fmodcnt; ++n)
+ if (fmodsw[n].f_str == 0)
+ break;
+ if (n >= fmodcnt)
+ return ENODEV;
+ strncpy(fmodsw[n].f_name, vd.Drv_name, FMNAMESZ+1);
+ fmodsw[n].f_str = &ppp_ahdlcinfo;
+ fmodsw_index = n;
+ break;
+
+ case VDUNLOAD:
+ if (ppp_ahdlc_count > 0)
+ return EBUSY;
+ if (fmodsw_index <= 0)
+ return EINVAL;
+ fmodsw[fmodsw_index].f_name[0] = 0;
+ fmodsw[fmodsw_index].f_str = 0;
+ fmodsw_index = -1;
+ break;
+
+ case VDSTAT:
+ break;
+
+ default:
+ return EIO;
+ }
+ return 0;
+}
diff --git a/mdk-stage1/ppp/sunos4/ppp_comp_vdcmd.c b/mdk-stage1/ppp/sunos4/ppp_comp_vdcmd.c
new file mode 100644
index 000000000..b81bc47e8
--- /dev/null
+++ b/mdk-stage1/ppp/sunos4/ppp_comp_vdcmd.c
@@ -0,0 +1,57 @@
+#include <sys/types.h>
+#include <sys/errno.h>
+#include <sys/conf.h>
+#include <sun/vddrv.h>
+
+extern struct streamtab ppp_compinfo;
+extern int ppp_comp_count;
+
+static struct vdldrv vd = {
+ VDMAGIC_USER,
+ "ppp_comp"
+};
+
+static int fmodsw_index = -1;
+
+int
+ppp_comp_vdcmd(fun, vdp, vdi, vds)
+ unsigned int fun;
+ struct vddrv *vdp;
+ addr_t vdi;
+ struct vdstat *vds;
+{
+ int n;
+
+ switch (fun) {
+ case VDLOAD:
+ vdp->vdd_vdtab = (struct vdlinkage *) &vd;
+ if (fmodsw_index >= 0)
+ return EBUSY;
+ for (n = 0; n < fmodcnt; ++n)
+ if (fmodsw[n].f_str == 0)
+ break;
+ if (n >= fmodcnt)
+ return ENODEV;
+ strncpy(fmodsw[n].f_name, vd.Drv_name, FMNAMESZ+1);
+ fmodsw[n].f_str = &ppp_compinfo;
+ fmodsw_index = n;
+ break;
+
+ case VDUNLOAD:
+ if (ppp_comp_count > 0)
+ return EBUSY;
+ if (fmodsw_index <= 0)
+ return EINVAL;
+ fmodsw[fmodsw_index].f_name[0] = 0;
+ fmodsw[fmodsw_index].f_str = 0;
+ fmodsw_index = -1;
+ break;
+
+ case VDSTAT:
+ break;
+
+ default:
+ return EIO;
+ }
+ return 0;
+}
diff --git a/mdk-stage1/ppp/sunos4/ppp_vdcmd.c b/mdk-stage1/ppp/sunos4/ppp_vdcmd.c
new file mode 100644
index 000000000..68095c92e
--- /dev/null
+++ b/mdk-stage1/ppp/sunos4/ppp_vdcmd.c
@@ -0,0 +1,81 @@
+#include <sys/types.h>
+#include <sys/errno.h>
+#include <sys/conf.h>
+#include <sun/vddrv.h>
+
+extern struct streamtab pppinfo;
+extern int ppp_count;
+extern int nchrdev;
+
+static struct vdldrv vd = {
+ VDMAGIC_PSEUDO,
+ "ppp"
+};
+
+extern int nodev();
+
+static struct cdevsw ppp_cdevsw = {
+ nodev, nodev, nodev, nodev, nodev, nodev, nodev, 0,
+ &pppinfo
+};
+
+static struct cdevsw old_entry;
+
+int
+ppp_vdcmd(fun, vdp, vdi, vds)
+ unsigned int fun;
+ struct vddrv *vdp;
+ addr_t vdi;
+ struct vdstat *vds;
+{
+ static int majnum = -1;
+ int n, maj;
+
+ switch (fun) {
+ case VDLOAD:
+ /*
+ * It seems like modload doesn't install the cdevsw entry
+ * for us. Oh well...
+ */
+ for (maj = 1; maj < nchrdev; ++maj)
+ if (cdevsw[maj].d_open == vd_unuseddev)
+ break;
+ if (maj >= nchrdev)
+ return ENODEV;
+ vd.Drv_charmajor = maj;
+ old_entry = cdevsw[maj];
+ cdevsw[maj] = ppp_cdevsw;
+ vd.Drv_cdevsw = &ppp_cdevsw;
+ vdp->vdd_vdtab = (struct vdlinkage *) &vd;
+ majnum = maj;
+ break;
+
+ case VDUNLOAD:
+ if (ppp_count > 0)
+ return EBUSY;
+ if (vd.Drv_charmajor > 0)
+ cdevsw[vd.Drv_charmajor] = old_entry;
+ break;
+
+ case VDSTAT:
+ /*
+ * We have to fool the modstat command into thinking
+ * that this module is actually a driver! This is
+ * so that installation commands that use the -exec
+ * option of modload to run a shell script find out
+ * the block and/or char major numbers of the driver
+ * loaded (so that the shell script can go off to
+ * /dev and *MAKE* the bloody device nodes- remember
+ * they might change from one load to another if
+ * you don't hardwire the number!).
+ */
+ vds->vds_magic = VDMAGIC_DRV;
+ vds->vds_modinfo[0] = (char) 0;
+ vds->vds_modinfo[1] = (char) majnum;
+ break;
+
+ default:
+ return EIO;
+ }
+ return 0;
+}
diff --git a/mdk-stage1/ppp/svr4/Makedefs b/mdk-stage1/ppp/svr4/Makedefs
new file mode 100644
index 000000000..81db8ab2e
--- /dev/null
+++ b/mdk-stage1/ppp/svr4/Makedefs
@@ -0,0 +1,16 @@
+#
+# defines common to several Makefiles
+#
+
+INSTALL= /usr/sbin/install
+
+BINDIR = /usr/local/bin
+MANDIR = /usr/local/man
+ETCDIR = /etc/ppp
+
+COPTS = -O -Xa
+
+# For compiling with gcc, comment out the COPTS definition above and
+# uncomment the next 2 definitions.
+#CC = gcc
+#COPTS = -O2
diff --git a/mdk-stage1/ppp/svr4/Makedefs.sol2 b/mdk-stage1/ppp/svr4/Makedefs.sol2
new file mode 100644
index 000000000..61ad95551
--- /dev/null
+++ b/mdk-stage1/ppp/svr4/Makedefs.sol2
@@ -0,0 +1,59 @@
+#
+# Generic make definitions for Solaris 2
+#
+# $Id: Makedefs.sol2 195720 2001-06-11 11:44:34Z gc $
+#
+
+include ../svr4/Makedefs
+
+CPPFLAGS = -D_KERNEL -DSVR4 -DSOL2 -DPRIOQ -DDEBUG -I../include
+CFLAGS = $(CPPFLAGS) $(COPTS)
+
+# lint-specific variables
+LINT = lint
+LINT_OPT_32 =
+LINT_OPT_64 = -Xarch=v9 -errchk=longptr64
+
+LINT_32 =
+LINT_32 += -erroff=E_BAD_PTR_CAST_ALIGN
+LINT_32 += -erroff=E_SUPPRESSION_DIRECTIVE_UNUSED
+LINT_32 += -erroff=E_SUSPICIOUS_COMPARISON
+LINT_32 += -erroff=E_CAST_UINT_TO_SIGNED_INT
+LINT_32 += -erroff=E_PASS_UINT_TO_SIGNED_INT
+LINT_32 += -erroff=E_INVALID_ANNOTATION_NAME
+LINT_32 += -erroff=E_FUNC_ARG_UNUSED
+# This might be needed, but zlib.c and vjcompress.c will squawk
+# when not ignored
+LINT_32 += -erroff=E_CASE_FALLTHRU
+LINT_32 += -erroff=E_RET_INT_IMPLICITLY
+LINT_32 += -erroff=E_FUNC_NO_RET_VAL
+# Some STREAMS macros will be noisy too when this isn't ignored
+LINT_32 += -erroff=E_CONSTANT_CONDITION
+LINT_32 += -erroff=E_CONST_EXPR
+
+# Extra noise suppressant for 64-bit
+EXTRA_OFF =
+EXTRA_OFF += -erroff=E_CAST_INT_TO_SMALL_INT
+EXTRA_OFF += -erroff=E_CAST_INT_CONST_TO_SMALL_INT
+EXTRA_OFF += -erroff=E_CAST_TO_PTR_FROM_INT
+EXTRA_OFF += -erroff=E_ASSIGN_INT_TO_SMALL_INT
+EXTRA_OFF += -erroff=E_ASSIGN_INT_FROM_BIG_CONST
+EXTRA_OFF += -erroff=E_CONST_PROMOTED_UNSIGNED_LL
+EXTRA_OFF += -erroff=E_CONST_PROMOTED_LONG_LONG
+EXTRA_OFF += -erroff=E_CONST_TRUNCATED_BY_ASSIGN
+EXTRA_OFF += -erroff=E_PASS_INT_FROM_BIG_CONST
+EXTRA_OFF += -erroff=E_COMP_INT_WITH_LARGE_INT
+EXTRA_OFF += -erroff=E_ASSIGN_UINT_TO_SIGNED_INT
+EXTRA_OFF += -erroff=E_ASSIGN_NARROW_CONV
+EXTRA_OFF += -erroff=E_PASS_INT_TO_SMALL_INT
+EXTRA_OFF += -erroff=E_PTR_CONV_LOSES_BITS
+
+LINT_64 = $(LINT_32)
+LINT_64 += $(EXTRA_OFF)
+
+LINTFLAGS64 = -Xa -nsxmuF -errtags=yes $(LINT_OPT_64) $(LINT_64)
+LINT64 = $(LINT) -c $(LINTFLAGS64) $(CPPFLAGS)
+
+LINTFLAGS32 = -Xa -nsxmuF -errtags=yes $(LINT_OPT_32) $(LINT_32)
+LINT32 = $(LINT) -c $(LINTFLAGS32) $(CPPFLAGS)
+
diff --git a/mdk-stage1/ppp/svr4/Makefile.sol2 b/mdk-stage1/ppp/svr4/Makefile.sol2
new file mode 100644
index 000000000..d1df99c1a
--- /dev/null
+++ b/mdk-stage1/ppp/svr4/Makefile.sol2
@@ -0,0 +1,66 @@
+#
+# Makefile for STREAMS modules for Solaris 2.
+#
+# $Id: Makefile.sol2 195720 2001-06-11 11:44:34Z gc $
+#
+
+include Makedefs.sol2
+
+COPTS += -xO2 -xspace -W0,-Lt
+
+COMP_OBJS = ppp_comp.o bsd-comp.o deflate.o zlib.o vjcompress.o \
+ ppp_comp_mod.o
+
+all: ppp ppp_ahdl ppp_comp
+
+ppp: ppp.o ppp_mod.o
+ ld -r -o $@ ppp.o ppp_mod.o
+ chmod +x $@
+
+ppp_ahdl: ppp_ahdlc.o ppp_ahdlc_mod.o
+ ld -r -o $@ ppp_ahdlc.o ppp_ahdlc_mod.o
+ chmod +x $@
+
+ppp_comp: $(COMP_OBJS)
+ ld -r -o $@ $(COMP_OBJS)
+ chmod +x $@
+
+bsd-comp.o: ../modules/bsd-comp.c
+ $(CC) $(CFLAGS) -c $?
+deflate.o: ../modules/deflate.c
+ $(CC) $(CFLAGS) -c $?
+ppp.o: ../modules/ppp.c
+ $(CC) $(CFLAGS) -c $?
+ppp_mod.o: ppp_mod.c
+ $(CC) $(CFLAGS) -c $?
+ppp_ahdlc_mod.o: ppp_ahdlc_mod.c
+ $(CC) $(CFLAGS) -c $?
+ppp_ahdlc.o: ../modules/ppp_ahdlc.c
+ $(CC) $(CFLAGS) -c $?
+ppp_comp.o: ../modules/ppp_comp.c
+ $(CC) $(CFLAGS) -c $?
+ppp_comp_mod.o: ppp_comp_mod.c
+ $(CC) $(CFLAGS) -c $?
+vjcompress.o: ../modules/vjcompress.c
+ $(CC) $(CFLAGS) -c $?
+zlib.o: ../common/zlib.c
+ $(CC) $(CFLAGS) -c $?
+
+install:
+ cp ppp ppp.conf /kernel/drv
+ cp ppp_comp ppp_ahdl /kernel/strmod
+ if grep clone:ppp /etc/minor_perm; then :; else \
+ echo clone:ppp 0644 root sys >>/etc/minor_perm; fi
+ /usr/sbin/rem_drv ppp 2>/dev/null || true
+ /usr/sbin/add_drv ppp
+
+SRCS = ../modules/ppp.c ppp_mod.c ../modules/ppp_ahdlc.c ppp_ahdlc_mod.c \
+ ../modules/ppp_comp.c ../modules/bsd-comp.c ../modules/deflate.c \
+ ../common/zlib.c ../modules/vjcompress.c ppp_comp_mod.c
+
+lint:
+ $(LINT32) $(SRCS)
+
+clean:
+ rm -f ppp ppp_comp ppp_ahdl *.o *~ core
+ rm -f *.ln
diff --git a/mdk-stage1/ppp/svr4/Makefile.sol2-64 b/mdk-stage1/ppp/svr4/Makefile.sol2-64
new file mode 100644
index 000000000..ea0b3ed5b
--- /dev/null
+++ b/mdk-stage1/ppp/svr4/Makefile.sol2-64
@@ -0,0 +1,85 @@
+#
+# Makefile for 64-bit STREAMS modules for Solaris 2.
+#
+# $Id: Makefile.sol2-64 195720 2001-06-11 11:44:34Z gc $
+#
+
+include Makedefs.sol2
+
+# Sun's cc flag for LP64 compilation / linkage
+COPTS += -xchip=ultra -xarch=v9 -Wc,-xcode=abs32 -Wc,-Qiselect-regsym=0 -xO3 -xspace -W0,-Lt
+
+# subdirectory where 64-bit objects / binaries will be placed
+LP64DIR = sparcv9
+
+# Name of legacy Makefile (for 32-bit binaries)
+STD_MAKE = Makefile.sol2
+
+COMP_OBJS = $(LP64DIR)/ppp_comp.o $(LP64DIR)/bsd-comp.o \
+ $(LP64DIR)/deflate.o $(LP64DIR)/zlib.o $(LP64DIR)/vjcompress.o \
+ $(LP64DIR)/ppp_comp_mod.o
+
+all: std_objs $(LP64DIR) ppp ppp_ahdl ppp_comp
+
+std_objs:
+ $(MAKE) -f $(STD_MAKE) all
+
+ppp: $(LP64DIR)/ppp.o $(LP64DIR)/ppp_mod.o
+ ld -r -o $(LP64DIR)/$@ $(LP64DIR)/ppp.o $(LP64DIR)/ppp_mod.o
+ chmod +x $(LP64DIR)/$@
+
+ppp_ahdl: $(LP64DIR)/ppp_ahdlc.o $(LP64DIR)/ppp_ahdlc_mod.o
+ ld -r -o $(LP64DIR)/$@ $(LP64DIR)/ppp_ahdlc.o $(LP64DIR)/ppp_ahdlc_mod.o
+ chmod +x $(LP64DIR)/$@
+
+ppp_comp: $(COMP_OBJS)
+ ld -r -o $(LP64DIR)/$@ $(COMP_OBJS)
+ chmod +x $(LP64DIR)/$@
+
+$(LP64DIR)/bsd-comp.o: ../modules/bsd-comp.c
+ $(CC) $(CFLAGS) -c $? -o $@
+$(LP64DIR)/deflate.o: ../modules/deflate.c
+ $(CC) $(CFLAGS) -c $? -o $@
+$(LP64DIR)/ppp.o: ../modules/ppp.c
+ $(CC) $(CFLAGS) -c $? -o $@
+$(LP64DIR)/ppp_mod.o: ppp_mod.c
+ $(CC) $(CFLAGS) -c $? -o $@
+$(LP64DIR)/ppp_ahdlc_mod.o: ppp_ahdlc_mod.c
+ $(CC) $(CFLAGS) -c $? -o $@
+$(LP64DIR)/ppp_ahdlc.o: ../modules/ppp_ahdlc.c
+ $(CC) $(CFLAGS) -c $? -o $@
+$(LP64DIR)/ppp_comp.o: ../modules/ppp_comp.c
+ $(CC) $(CFLAGS) -c $? -o $@
+$(LP64DIR)/ppp_comp_mod.o: ppp_comp_mod.c
+ $(CC) $(CFLAGS) -c $? -o $@
+$(LP64DIR)/vjcompress.o: ../modules/vjcompress.c
+ $(CC) $(CFLAGS) -c $? -o $@
+$(LP64DIR)/zlib.o: ../common/zlib.c
+ $(CC) $(CFLAGS) -c $? -o $@
+
+$(LP64DIR):
+ mkdir -m 755 -p $@
+
+install:
+ cp ppp ppp.conf /kernel/drv
+ cp ppp_comp ppp_ahdl /kernel/strmod
+ cp $(LP64DIR)/ppp /kernel/drv/$(LP64DIR)
+ cp $(LP64DIR)/ppp_comp $(LP64DIR)/ppp_ahdl /kernel/strmod/$(LP64DIR)
+ if grep clone:ppp /etc/minor_perm; then :; else \
+ echo clone:ppp 0644 root sys >>/etc/minor_perm; fi
+ /usr/sbin/rem_drv ppp 2>/dev/null || true
+ /usr/sbin/add_drv ppp
+
+SRCS = ../modules/ppp.c ppp_mod.c ../modules/ppp_ahdlc.c ppp_ahdlc_mod.c \
+ ../modules/ppp_comp.c ../modules/bsd-comp.c ../modules/deflate.c \
+ ../common/zlib.c ../modules/vjcompress.c ppp_comp_mod.c
+
+lint:
+ $(LINT64) $(SRCS)
+
+lint-32:
+ $(LINT32) $(SRCS)
+
+clean:
+ $(MAKE) -f $(STD_MAKE) clean
+ rm -f $(LP64DIR)/ppp $(LP64DIR)/ppp_comp $(LP64DIR)/ppp_ahdl $(LP64DIR)/*.o $(LP64DIR)/*~ $(LP64DIR)/core
diff --git a/mdk-stage1/ppp/svr4/Makefile.svr4 b/mdk-stage1/ppp/svr4/Makefile.svr4
new file mode 100644
index 000000000..6649a9055
--- /dev/null
+++ b/mdk-stage1/ppp/svr4/Makefile.svr4
@@ -0,0 +1,60 @@
+#
+# Makefile for STREAMS modules for SVR4.
+#
+# $Id: Makefile.svr4 195720 2001-06-11 11:44:34Z gc $
+#
+
+COPTS = -O
+
+CFLAGS= -D_KERNEL -DSVR4 -DLACHTCP -I../include $(COPTS)
+
+all: ppp ppp_ahdl ppp_comp
+
+ppp: ppp.o
+ ld -r -o $@ ppp.o
+
+ppp_ahdl: ppp_ahdlc.o
+ ld -r -o $@ ppp_ahdlc.o
+
+ppp_comp: ppp_comp.o bsd-comp.o vjcompress.o deflate.o zlib.o
+ ld -r -o $@ ppp_comp.o bsd-comp.o vjcompress.o deflate.o zlib.o
+
+bsd-comp.o: ../modules/bsd-comp.c
+ $(CC) $(CFLAGS) -c $?
+deflate.o: ../modules/deflate.c
+ $(CC) $(CFLAGS) -c $?
+ppp.o: ../modules/ppp.c
+ $(CC) $(CFLAGS) -c $?
+ppp_ahdlc.o: ../modules/ppp_ahdlc.c
+ $(CC) $(CFLAGS) -c $?
+ppp_comp.o: ../modules/ppp_comp.c
+ $(CC) $(CFLAGS) -c $?
+vjcompress.o: ../modules/vjcompress.c
+ $(CC) $(CFLAGS) -c $?
+zlib.o: ../common/zlib.c
+ $(CC) $(CFLAGS) -c $?
+
+install: all
+ cp ppp Driver.o
+ cp ppp.Master Master
+ cp ppp.System System
+ cp ppp.Node Node
+ /etc/conf/bin/idinstall -d ppp
+ /etc/conf/bin/idinstall -a ppp
+ cp ppp_comp Driver.o
+ cp ppp_comp.Master Master
+ cp ppp_comp.System System
+ /etc/conf/bin/idinstall -d ppp_comp
+ /etc/conf/bin/idinstall -a ppp_comp
+ cp ppp_ahdl Driver.o
+ cp ppp_ahdl.Master Master
+ cp ppp_ahdl.System System
+ /etc/conf/bin/idinstall -d ppp_ahdl
+ /etc/conf/bin/idinstall -a ppp_ahdl
+ @echo
+ @echo 'NOTE: You must rebuild your kernel to incorporate the driver.'
+ @echo '(use /etc/conf/bin/idbuild)'
+ @echo
+
+clean:
+ rm -f ppp ppp_comp ppp_ahdl *.o *~ core
diff --git a/mdk-stage1/ppp/svr4/Makefile.top b/mdk-stage1/ppp/svr4/Makefile.top
new file mode 100644
index 000000000..f2e682d38
--- /dev/null
+++ b/mdk-stage1/ppp/svr4/Makefile.top
@@ -0,0 +1,50 @@
+#
+# ppp top level makefile for SVR4 and Solaris 2
+#
+# $Id: Makefile.top 195720 2001-06-11 11:44:34Z gc $
+#
+
+include svr4/Makedefs
+
+all:
+ cd chat; $(MAKE) all
+ cd pppd; $(MAKE) all
+ cd pppstats; $(MAKE) all
+ cd pppdump; $(MAKE) all
+ cd svr4; $(MAKE) all
+
+install: $(BINDIR) $(MANDIR)/man8 install-progs install-etcppp
+
+install-progs:
+ cd chat; $(MAKE) install
+ cd pppd; $(MAKE) install
+ cd pppstats; $(MAKE) install
+ cd pppdump; $(MAKE) install
+ cd svr4; $(MAKE) install
+
+install-etcppp: $(ETCDIR) $(ETCDIR)/options $(ETCDIR)/pap-secrets \
+ $(ETCDIR)/chap-secrets
+
+$(ETCDIR)/options:
+ cp etc.ppp/options $@
+ chmod go-w $@
+$(ETCDIR)/pap-secrets:
+ $(INSTALL) -f $(ETCDIR) -m 600 etc.ppp/pap-secrets
+$(ETCDIR)/chap-secrets:
+ $(INSTALL) -f $(ETCDIR) -m 600 etc.ppp/chap-secrets
+
+$(BINDIR):
+ mkdir -m 755 -p $@
+$(MANDIR)/man8:
+ mkdir -m 755 -p $@
+$(ETCDIR):
+ mkdir -m 755 -p $@
+
+clean:
+ rm -f *~
+ cd chat; $(MAKE) clean
+ cd pppd; $(MAKE) clean
+ cd pppstats; $(MAKE) clean
+ cd pppdump; $(MAKE) clean
+ cd svr4; $(MAKE) clean
+
diff --git a/mdk-stage1/ppp/svr4/ppp.Master b/mdk-stage1/ppp/svr4/ppp.Master
new file mode 100644
index 000000000..346db035b
--- /dev/null
+++ b/mdk-stage1/ppp/svr4/ppp.Master
@@ -0,0 +1 @@
+ppp - Sciof ppp 0 0 1 128 -1
diff --git a/mdk-stage1/ppp/svr4/ppp.Node b/mdk-stage1/ppp/svr4/ppp.Node
new file mode 100644
index 000000000..7767ade71
--- /dev/null
+++ b/mdk-stage1/ppp/svr4/ppp.Node
@@ -0,0 +1 @@
+clone ppp c ppp
diff --git a/mdk-stage1/ppp/svr4/ppp.System b/mdk-stage1/ppp/svr4/ppp.System
new file mode 100644
index 000000000..e60c0eec3
--- /dev/null
+++ b/mdk-stage1/ppp/svr4/ppp.System
@@ -0,0 +1 @@
+ppp Y 1 0 0 0 0 0 0 0
diff --git a/mdk-stage1/ppp/svr4/ppp.conf b/mdk-stage1/ppp/svr4/ppp.conf
new file mode 100644
index 000000000..e443a7aac
--- /dev/null
+++ b/mdk-stage1/ppp/svr4/ppp.conf
@@ -0,0 +1 @@
+name="ppp" parent="pseudo" instance=0;
diff --git a/mdk-stage1/ppp/svr4/ppp_ahdl.Master b/mdk-stage1/ppp/svr4/ppp_ahdl.Master
new file mode 100644
index 000000000..4fde52596
--- /dev/null
+++ b/mdk-stage1/ppp/svr4/ppp_ahdl.Master
@@ -0,0 +1 @@
+ppp_ahdl - iSf phdl 0 0 1 1 -1
diff --git a/mdk-stage1/ppp/svr4/ppp_ahdl.System b/mdk-stage1/ppp/svr4/ppp_ahdl.System
new file mode 100644
index 000000000..f41a500f4
--- /dev/null
+++ b/mdk-stage1/ppp/svr4/ppp_ahdl.System
@@ -0,0 +1 @@
+ppp_ahdl Y 1 0 0 0 0 0 0 0
diff --git a/mdk-stage1/ppp/svr4/ppp_ahdlc_mod.c b/mdk-stage1/ppp/svr4/ppp_ahdlc_mod.c
new file mode 100644
index 000000000..f81be8abb
--- /dev/null
+++ b/mdk-stage1/ppp/svr4/ppp_ahdlc_mod.c
@@ -0,0 +1,49 @@
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/conf.h>
+#include <sys/modctl.h>
+#include <sys/sunddi.h>
+
+extern struct streamtab ppp_ahdlcinfo;
+
+static struct fmodsw fsw = {
+ "ppp_ahdl",
+ &ppp_ahdlcinfo,
+ D_NEW | D_MP | D_MTQPAIR
+};
+
+extern struct mod_ops mod_strmodops;
+
+static struct modlstrmod modlstrmod = {
+ &mod_strmodops,
+ "PPP async HDLC module",
+ &fsw
+};
+
+static struct modlinkage modlinkage = {
+ MODREV_1,
+ (void *) &modlstrmod,
+ NULL
+};
+
+/*
+ * Entry points for modloading.
+ */
+int
+_init(void)
+{
+ return mod_install(&modlinkage);
+}
+
+int
+_fini(void)
+{
+ return mod_remove(&modlinkage);
+}
+
+int
+_info(mip)
+ struct modinfo *mip;
+{
+ return mod_info(&modlinkage, mip);
+}
diff --git a/mdk-stage1/ppp/svr4/ppp_comp.Master b/mdk-stage1/ppp/svr4/ppp_comp.Master
new file mode 100644
index 000000000..78019064e
--- /dev/null
+++ b/mdk-stage1/ppp/svr4/ppp_comp.Master
@@ -0,0 +1 @@
+ppp_comp - iSf pcmp 0 0 1 1 -1
diff --git a/mdk-stage1/ppp/svr4/ppp_comp.System b/mdk-stage1/ppp/svr4/ppp_comp.System
new file mode 100644
index 000000000..e69d4a1a3
--- /dev/null
+++ b/mdk-stage1/ppp/svr4/ppp_comp.System
@@ -0,0 +1 @@
+ppp_comp Y 1 0 0 0 0 0 0 0
diff --git a/mdk-stage1/ppp/svr4/ppp_comp_mod.c b/mdk-stage1/ppp/svr4/ppp_comp_mod.c
new file mode 100644
index 000000000..d22fbc81f
--- /dev/null
+++ b/mdk-stage1/ppp/svr4/ppp_comp_mod.c
@@ -0,0 +1,81 @@
+/*
+ * ppp_comp_mod.c - modload support for PPP compression STREAMS module.
+ *
+ * Copyright (c) 1994 The Australian National University.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation is hereby granted, provided that the above copyright
+ * notice appears in all copies. This software is provided without any
+ * warranty, express or implied. The Australian National University
+ * makes no representations about the suitability of this software for
+ * any purpose.
+ *
+ * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
+ * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
+ * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
+ * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
+ * OR MODIFICATIONS.
+ *
+ * $Id: ppp_comp_mod.c 195720 2001-06-11 11:44:34Z gc $
+ */
+
+/*
+ * This file is used under Solaris 2.
+ */
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/conf.h>
+#include <sys/modctl.h>
+#include <sys/sunddi.h>
+
+extern struct streamtab ppp_compinfo;
+
+static struct fmodsw fsw = {
+ "ppp_comp",
+ &ppp_compinfo,
+ D_NEW | D_MP | D_MTQPAIR
+};
+
+extern struct mod_ops mod_strmodops;
+
+static struct modlstrmod modlstrmod = {
+ &mod_strmodops,
+ "PPP compression module",
+ &fsw
+};
+
+static struct modlinkage modlinkage = {
+ MODREV_1,
+ (void *) &modlstrmod,
+ NULL
+};
+
+/*
+ * Entry points for modloading.
+ */
+int
+_init(void)
+{
+ return mod_install(&modlinkage);
+}
+
+int
+_fini(void)
+{
+ return mod_remove(&modlinkage);
+}
+
+int
+_info(mip)
+ struct modinfo *mip;
+{
+ return mod_info(&modlinkage, mip);
+}
diff --git a/mdk-stage1/ppp/svr4/ppp_mod.c b/mdk-stage1/ppp/svr4/ppp_mod.c
new file mode 100644
index 000000000..7a4f52add
--- /dev/null
+++ b/mdk-stage1/ppp/svr4/ppp_mod.c
@@ -0,0 +1,174 @@
+/*
+ * ppp_mod.c - modload support for PPP pseudo-device driver.
+ *
+ * Copyright (c) 1994 The Australian National University.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation is hereby granted, provided that the above copyright
+ * notice appears in all copies. This software is provided without any
+ * warranty, express or implied. The Australian National University
+ * makes no representations about the suitability of this software for
+ * any purpose.
+ *
+ * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
+ * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
+ * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
+ * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
+ * OR MODIFICATIONS.
+ *
+ * $Id: ppp_mod.c 195720 2001-06-11 11:44:34Z gc $
+ */
+
+/*
+ * This file is used under Solaris 2.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/conf.h>
+#include <sys/modctl.h>
+#include <sys/sunddi.h>
+#include <sys/ksynch.h>
+
+#ifdef __STDC__
+#define __P(x) x
+#else
+#define __P(x) ()
+#endif
+
+static int ppp_identify __P((dev_info_t *));
+static int ppp_attach __P((dev_info_t *, ddi_attach_cmd_t));
+static int ppp_detach __P((dev_info_t *, ddi_detach_cmd_t));
+static int ppp_devinfo __P((dev_info_t *, ddi_info_cmd_t, void *, void **));
+
+extern struct streamtab pppinfo;
+extern krwlock_t ppp_lower_lock;
+
+static dev_info_t *ppp_dip;
+
+static struct cb_ops cb_ppp_ops = {
+ nulldev, nulldev, nodev, nodev, /* cb_open, ... */
+ nodev, nodev, nodev, nodev, /* cb_dump, ... */
+ nodev, nodev, nodev, nochpoll, /* cb_devmap, ... */
+ ddi_prop_op, /* cb_prop_op */
+ &pppinfo, /* cb_stream */
+ D_NEW|D_MP|D_MTQPAIR|D_MTOUTPERIM|D_MTOCEXCL /* cb_flag */
+};
+
+static struct dev_ops ppp_ops = {
+ DEVO_REV, /* devo_rev */
+ 0, /* devo_refcnt */
+ ppp_devinfo, /* devo_getinfo */
+ ppp_identify, /* devo_identify */
+ nulldev, /* devo_probe */
+ ppp_attach, /* devo_attach */
+ ppp_detach, /* devo_detach */
+ nodev, /* devo_reset */
+ &cb_ppp_ops, /* devo_cb_ops */
+ NULL /* devo_bus_ops */
+};
+
+/*
+ * Module linkage information
+ */
+
+static struct modldrv modldrv = {
+ &mod_driverops, /* says this is a pseudo driver */
+ "PPP-2.3 multiplexing driver",
+ &ppp_ops /* driver ops */
+};
+
+static struct modlinkage modlinkage = {
+ MODREV_1,
+ (void *) &modldrv,
+ NULL
+};
+
+int
+_init(void)
+{
+ return mod_install(&modlinkage);
+}
+
+int
+_fini(void)
+{
+ return mod_remove(&modlinkage);
+}
+
+int
+_info(mip)
+ struct modinfo *mip;
+{
+ return mod_info(&modlinkage, mip);
+}
+
+static int
+ppp_identify(dip)
+ dev_info_t *dip;
+{
+ return strcmp(ddi_get_name(dip), "ppp") == 0? DDI_IDENTIFIED:
+ DDI_NOT_IDENTIFIED;
+}
+
+static int
+ppp_attach(dip, cmd)
+ dev_info_t *dip;
+ ddi_attach_cmd_t cmd;
+{
+
+ if (cmd != DDI_ATTACH)
+ return DDI_FAILURE;
+ if (ddi_create_minor_node(dip, "ppp", S_IFCHR, 0, DDI_PSEUDO, CLONE_DEV)
+ == DDI_FAILURE) {
+ ddi_remove_minor_node(dip, NULL);
+ return DDI_FAILURE;
+ }
+ rw_init(&ppp_lower_lock, NULL, RW_DRIVER, NULL);
+ return DDI_SUCCESS;
+}
+
+static int
+ppp_detach(dip, cmd)
+ dev_info_t *dip;
+ ddi_detach_cmd_t cmd;
+{
+ rw_destroy(&ppp_lower_lock);
+ ddi_remove_minor_node(dip, NULL);
+ return DDI_SUCCESS;
+}
+
+static int
+ppp_devinfo(dip, cmd, arg, result)
+ dev_info_t *dip;
+ ddi_info_cmd_t cmd;
+ void *arg;
+ void **result;
+{
+ int error;
+
+ error = DDI_SUCCESS;
+ switch (cmd) {
+ case DDI_INFO_DEVT2DEVINFO:
+ if (ppp_dip == NULL)
+ error = DDI_FAILURE;
+ else
+ *result = (void *) ppp_dip;
+ break;
+ case DDI_INFO_DEVT2INSTANCE:
+ *result = NULL;
+ break;
+ default:
+ error = DDI_FAILURE;
+ }
+ return error;
+}
diff --git a/mdk-stage1/probe-modules.c b/mdk-stage1/probe-modules.c
new file mode 100644
index 000000000..6f162aed4
--- /dev/null
+++ b/mdk-stage1/probe-modules.c
@@ -0,0 +1,70 @@
+/*
+ * Olivier Blin (blino@mandriva.com)
+ *
+ * Copyright 2007-2004 Mandriva
+ *
+ *
+ * This software may be freely redistributed under the terms of the GNU
+ * public license.
+ *
+ * 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.
+ *
+ */
+
+#include "log.h"
+#include "modules.h"
+#include "probing.h"
+#include "frontend.h"
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <string.h>
+#include "utils.h"
+
+void exit_bootsplash(void) {}
+void stg1_error_message(char *msg, ...)
+{
+ va_list args;
+ va_start(args, msg);
+ verror_message(msg, args);
+ va_end(args);
+}
+void fatal_error(char *msg)
+{
+ log_message("FATAL ERROR IN MODULES LOADER: %s\n\nI can't recover from this.\nYou may reboot your system.\n", msg);
+ exit(EXIT_FAILURE);
+}
+
+int main(int argc, char **argv, char **env)
+{
+ enum media_bus bus = BUS_ANY;
+ char *module = NULL;
+ char options[500] = "";
+
+ if (argc > 1) {
+ if (streq(argv[1], "--usb")) {
+ bus = BUS_USB;
+ } else if (!ptr_begins_static_str(argv[1], "--")) {
+ int i;
+ module = argv[1];
+ for (i = 2; i < argc; i++) {
+ strcat(options, argv[i]);
+ strcat(options, " ");
+ }
+ }
+ }
+
+ open_log();
+ init_modules_insmoding();
+
+ if (module) {
+ my_insmod(module, ANY_DRIVER_TYPE, options, 0);
+ } else {
+ find_media(bus);
+ }
+
+ close_log();
+
+ return 0;
+}
diff --git a/mdk-stage1/probing.c b/mdk-stage1/probing.c
new file mode 100644
index 000000000..fd0f39c50
--- /dev/null
+++ b/mdk-stage1/probing.c
@@ -0,0 +1,959 @@
+/*
+ * Guillaume Cottenceau (gc@mandrakesoft.com)
+ *
+ * Copyright 2000 Mandrakesoft
+ *
+ * This software may be freely redistributed under the terms of the GNU
+ * public license.
+ *
+ * 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.
+ *
+ */
+
+/*
+ * Portions from Erik Troan (ewt@redhat.com)
+ *
+ * Copyright 1996 Red Hat Software
+ *
+ */
+
+
+/*
+ * This contains stuff related to probing:
+ * (1) any (actually only SCSI, NET, CPQ, USB Controllers) devices (autoprobe for PCI and USB)
+ * (2) IDE media
+ * (3) SCSI media
+ * (4) ETH devices
+ */
+
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <fnmatch.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <pci/pci.h>
+#include <libldetect.h>
+#include "stage1.h"
+
+#include "log.h"
+#include "utils.h"
+#include "frontend.h"
+#include "modules.h"
+#include "pci-resource/pci-ids.h"
+#ifdef ENABLE_USB
+#include "usb-resource/usb-ids.h"
+#endif
+#ifdef ENABLE_PCMCIA
+#include "sysfs/libsysfs.h"
+#include "pcmcia-resource/pcmcia-ids.h"
+#endif
+
+#include "probing.h"
+
+
+struct media_info {
+ char * name;
+ char * model;
+ enum media_type type;
+};
+
+
+static void warning_insmod_failed(enum insmod_return r)
+{
+ if (IS_AUTOMATIC && r == INSMOD_FAILED_FILE_NOT_FOUND)
+ return;
+ if (r != INSMOD_OK) {
+ if (r == INSMOD_FAILED_FILE_NOT_FOUND)
+ stg1_error_message("This floppy doesn't contain the driver.");
+ else
+ stg1_error_message("Warning, installation of driver failed. (please include msg from <Alt-F3> for bugreports)");
+ }
+}
+
+#ifndef DISABLE_NETWORK
+struct net_description_elem
+{
+ char * intf_name;
+ char * intf_description;
+};
+static struct net_description_elem net_descriptions[50];
+static int net_descr_number = 0;
+static char * intf_descr_for_discover = NULL;
+static char * net_intf_too_early_name[50]; /* for modules providing more than one net intf */
+static int net_intf_too_early_number = 0;
+static int net_intf_too_early_ptr = 0;
+
+const char * safe_descr(const char * text) {
+ return text ? text : "unknown";
+}
+
+void prepare_intf_descr(const char * intf_descr)
+{
+ intf_descr_for_discover = strdup(intf_descr);
+}
+
+void net_discovered_interface(char * intf_name)
+{
+ if (!intf_descr_for_discover) {
+ net_intf_too_early_name[net_intf_too_early_number++] = strdup(intf_name);
+ return;
+ }
+ if (!intf_name) {
+ if (net_intf_too_early_ptr >= net_intf_too_early_number) {
+ log_message("NET: was expecting another network interface (broken net module?)");
+ return;
+ }
+ net_descriptions[net_descr_number].intf_name = net_intf_too_early_name[net_intf_too_early_ptr++];
+ }
+ else
+ net_descriptions[net_descr_number].intf_name = strdup(intf_name);
+ net_descriptions[net_descr_number].intf_description = strdup(intf_descr_for_discover);
+ intf_descr_for_discover = NULL;
+ net_descr_number++;
+}
+
+char * get_net_intf_description(char * intf_name)
+{
+ int i;
+ for (i = 0; i < net_descr_number ; i++)
+ if (!strcmp(net_descriptions[i].intf_name, intf_name))
+ return net_descriptions[i].intf_description;
+ return strdup("unknown");
+}
+#endif
+
+static int device_match_modules_list(struct pciusb_entry *e, char **modules, unsigned int modules_len) {
+ int i;
+ if (!e->module)
+ return 0;
+ for (i = 0; i < modules_len; i++)
+ if (!strcmp(modules[i], e->module))
+ return 1;
+ return 0;
+}
+
+struct pcitable_entry *detected_devices = NULL;
+int detected_devices_len = 0;
+
+static void detected_devices_destroy(void)
+{
+ if (detected_devices)
+ free(detected_devices);
+}
+
+static struct pcitable_entry *detected_device_new(void)
+{
+ static int detected_devices_maxlen = 0;
+ if (detected_devices_len >= detected_devices_maxlen) {
+ detected_devices_maxlen += 32;
+ if (detected_devices == NULL)
+ detected_devices = malloc(detected_devices_maxlen * sizeof(*detected_devices));
+ else
+ detected_devices = realloc(detected_devices, detected_devices_maxlen * sizeof(*detected_devices));
+ if (detected_devices == NULL)
+ log_perror("detected_device_new: could not (re)allocate table. Let it crash, sorry");
+ }
+ return &detected_devices[detected_devices_len++];
+}
+
+/* FIXME: factorize with probe_that_type() */
+
+static void add_detected_device(unsigned short vendor, unsigned short device, unsigned int subvendor, unsigned int subdevice, const char *name, const char *module)
+{
+ struct pcitable_entry *dev = detected_device_new();
+ dev->vendor = vendor;
+ dev->device = device;
+ dev->subvendor = subvendor;
+ dev->subdevice = subdevice;
+ strncpy(dev->module, module, sizeof(dev->module) - 1);
+ dev->module[sizeof(dev->module) - 1] = '\0';
+ strncpy(dev->description, safe_descr(name), sizeof(dev->description) - 1);
+ dev->description[sizeof(dev->description) - 1] = '\0';
+ log_message("detected device (%04x, %04x, %04x, %04x, %s, %s)", vendor, device, subvendor, subdevice, name, module);
+}
+
+static int add_detected_device_if_match(struct pciusb_entry *e, char **modules, unsigned int modules_len)
+{
+ int ret = device_match_modules_list(e, modules, modules_len);
+ if (ret)
+ add_detected_device(e->vendor, e->device, e->subvendor, e->subdevice,
+ e->text, e->module);
+ return ret;
+}
+
+void probing_detect_devices()
+{
+ static int already_detected_devices = 0;
+ struct pciusb_entries entries;
+ int i;
+
+ if (already_detected_devices)
+ return;
+
+ entries = pci_probe();
+ for (i = 0; i < entries.nb; i++) {
+ struct pciusb_entry *e = &entries.entries[i];
+#ifndef DISABLE_PCIADAPTERS
+#ifndef DISABLE_MEDIAS
+ if (add_detected_device_if_match(e, medias_ide_pci_modules, medias_ide_pci_modules_len))
+ continue;
+ if (add_detected_device_if_match(e, medias_other_pci_modules, medias_other_pci_modules_len))
+ continue;
+#endif
+
+#ifndef DISABLE_NETWORK
+ if (add_detected_device_if_match(e, network_pci_modules, network_pci_modules_len))
+ continue;
+#endif
+
+#ifdef ENABLE_USB
+ if (add_detected_device_if_match(e, usb_controller_modules, usb_controller_modules_len))
+ continue;
+#endif
+#endif
+ /* device can't be found in built-in pcitables, but keep it */
+ add_detected_device(e->vendor, e->device, e->subvendor, e->subdevice, e->text, e->module);
+ }
+ pciusb_free(&entries);
+
+ already_detected_devices = 1;
+}
+
+void probing_destroy(void)
+{
+ detected_devices_destroy();
+}
+
+#ifndef DISABLE_MEDIAS
+static const char * get_alternate_module(const char * name)
+{
+ struct alternate_mapping {
+ const char * a;
+ const char * b;
+ };
+ static struct alternate_mapping mappings[] = {
+ { "ahci", "ata_piix" },
+ };
+ int mappings_nb = sizeof(mappings) / sizeof(struct alternate_mapping);
+ int i;
+
+ for (i=0; i<mappings_nb; i++) {
+ const char * alternate = NULL;
+ if (streq(name, mappings[i].a))
+ alternate = mappings[i].b;
+ else if (streq(name, mappings[i].b))
+ alternate = mappings[i].a;
+ if (alternate) {
+ log_message("found alternate module %s for driver %s", alternate, name);
+ return alternate;
+ }
+ }
+ return NULL;
+}
+#endif
+
+void discovered_device(enum driver_type type, const char * description, const char * driver)
+{
+ description = safe_descr(description);
+
+ enum insmod_return failed = INSMOD_FAILED;
+#ifndef DISABLE_MEDIAS
+ if (type == MEDIA_ADAPTERS) {
+ const char * alternate = NULL;
+ wait_message("Loading driver for media adapter:\n \n%s", description);
+ failed = my_insmod(driver, MEDIA_ADAPTERS, NULL, 1);
+ alternate = get_alternate_module(driver);
+ if (!IS_NOAUTO && alternate) {
+ failed = failed || my_insmod(alternate, MEDIA_ADAPTERS, NULL, 1);
+ }
+ remove_wait_message();
+ warning_insmod_failed(failed);
+ }
+#endif
+#ifndef DISABLE_NETWORK
+ if (type == NETWORK_DEVICES) {
+ wait_message("Loading driver for network device:\n \n%s", description);
+ prepare_intf_descr(description);
+ failed = my_insmod(driver, NETWORK_DEVICES, NULL, 1);
+ warning_insmod_failed(failed);
+ remove_wait_message();
+ if (intf_descr_for_discover) /* for modules providing more than one net intf */
+ net_discovered_interface(NULL);
+ }
+#endif
+#ifdef ENABLE_USB
+ if (type == USB_CONTROLLERS)
+ /* we can't allow additional modules floppy since we need usbhid for keystrokes of usb keyboards */
+ failed = my_insmod(driver, USB_CONTROLLERS, NULL, 0);
+#endif
+}
+
+void probe_pci_modules(enum driver_type type, char **pci_modules, unsigned int pci_modules_len) {
+ struct pciusb_entries entries;
+ int i;
+
+ entries = pci_probe();
+ for (i = 0; i < entries.nb; i++) {
+ struct pciusb_entry *e = &entries.entries[i];
+ if (device_match_modules_list(e, pci_modules, pci_modules_len)) {
+ log_message("PCI: device %04x %04x %04x %04x is \"%s\", driver is %s",
+ e->vendor, e->device, e->subvendor, e->subdevice, safe_descr(e->text), e->module);
+ discovered_device(type, e->text, e->module);
+ }
+ }
+ pciusb_free(&entries);
+}
+
+/** Loads modules for known virtio devices
+ *
+ * virtio modules are not being loaded using the PCI probing mechanism
+ * because pcitable.gz does not have IDs for these devices.
+ *
+ * The possible correct solution for it is to fix the script which
+ * generates pcitable.gz to handle the virtio_device_id structure.
+ */
+void probe_virtio_modules(void)
+{
+ struct pciusb_entries entries;
+ int i;
+ char *name;
+ char *options;
+ int loaded_pci = 0;
+
+ entries = pci_probe();
+ for (i = 0; i < entries.nb; i++) {
+ struct pciusb_entry *e = &entries.entries[i];
+ if (e->vendor == VIRTIO_PCI_VENDOR) {
+ if (!loaded_pci) {
+ log_message("loading virtio-pci");
+ my_insmod("virtio_pci", ANY_DRIVER_TYPE, NULL, 0);
+ loaded_pci = 1;
+ }
+
+ name = NULL;
+ options = NULL;
+
+ switch (e->subdevice) {
+ case VIRTIO_ID_NET:
+ name = "virtio_net";
+ options = "csum=0";
+ break;
+ case VIRTIO_ID_BLOCK:
+ name = "virtio_blk";
+ break;
+ case VIRTIO_ID_BALLOON:
+ name = "virtio_balloon";
+ break;
+ default:
+ log_message("warning: unknown virtio device %04x", e->device);
+ }
+ if (name) {
+ log_message("virtio: loading %s", name);
+ my_insmod(name, ANY_DRIVER_TYPE, options, 0);
+ }
+ }
+ }
+ pciusb_free(&entries);
+}
+
+#ifdef ENABLE_USB
+void probe_that_type(enum driver_type type, enum media_bus bus)
+#else
+void probe_that_type(enum driver_type type, enum media_bus bus __attribute__ ((unused)))
+#endif
+{
+ static int already_probed_usb_controllers = 0;
+ static int already_loaded_usb_scsi = 0;
+ static int already_probed_virtio_devices = 0;
+
+ /* ---- PCI probe ---------------------------------------------- */
+ if (bus != BUS_USB) {
+ switch (type) {
+#ifndef DISABLE_PCIADAPTERS
+#ifndef DISABLE_MEDIAS
+ static int already_probed_media_adapters = 0;
+ case MEDIA_ADAPTERS:
+ if (already_probed_media_adapters)
+ break;
+ already_probed_media_adapters = 1;
+ probe_pci_modules(type, medias_ide_pci_modules, medias_ide_pci_modules_len);
+ probe_pci_modules(type, medias_other_pci_modules, medias_other_pci_modules_len);
+ break;
+#endif
+#ifndef DISABLE_NETWORK
+ case NETWORK_DEVICES:
+ probe_pci_modules(type, network_pci_modules, network_pci_modules_len);
+ break;
+#endif
+#endif
+#ifdef ENABLE_USB
+ case USB_CONTROLLERS:
+ if (already_probed_usb_controllers || IS_NOAUTO)
+ break;
+ already_probed_usb_controllers = 1;
+ probe_pci_modules(type, usb_controller_modules, usb_controller_modules_len);
+ break;
+#endif
+ case VIRTIO_DEVICES:
+ if (already_probed_virtio_devices)
+ break;
+ probe_virtio_modules();
+ already_probed_virtio_devices = 1;
+ break;
+ default:
+ break;
+ }
+ }
+
+
+#ifdef ENABLE_USB
+ /* ---- USB probe ---------------------------------------------- */
+ if ((bus == BUS_USB || bus == BUS_ANY) && !(IS_NOAUTO)) {
+ static int already_mounted_usbdev = 0;
+ struct pciusb_entries entries;
+ int i;
+
+ if (!already_probed_usb_controllers)
+ probe_that_type(USB_CONTROLLERS, BUS_ANY);
+
+ if (!already_mounted_usbdev) {
+ already_mounted_usbdev = 1;
+ if (mount("none", "/proc/bus/usb", "usbfs", 0, NULL) &&
+ mount("none", "/proc/bus/usb", "usbdevfs", 0, NULL)) {
+ log_message("USB: couldn't mount /proc/bus/usb");
+ goto end_usb_probe;
+ }
+ wait_message("Detecting USB devices.");
+ sleep(4); /* sucking background work */
+ my_insmod("usbhid", ANY_DRIVER_TYPE, NULL, 0);
+ remove_wait_message();
+ }
+
+ if (type != NETWORK_DEVICES)
+ goto end_usb_probe;
+
+ entries = usb_probe();
+ for (i = 0; i < entries.nb; i++) {
+ struct pciusb_entry *e = &entries.entries[i];
+ if (device_match_modules_list(e, usb_modules, usb_modules_len)) {
+ log_message("USB: device %04x %04x is \"%s\" (%s)", e->vendor, e->device, safe_descr(e->text), e->module);
+ discovered_device(type, e->text, e->module);
+ }
+ }
+ pciusb_free(&entries);
+ end_usb_probe:;
+ }
+#endif
+
+#ifdef ENABLE_PCMCIA
+ /* ---- PCMCIA probe ---------------------------------------------- */
+ if ((bus == BUS_PCMCIA || bus == BUS_ANY) && !(IS_NOAUTO)) {
+ struct pcmcia_alias * pcmciadb = NULL;
+ unsigned int len = 0;
+ char *base = "/sys/bus/pcmcia/devices";
+ DIR *dir;
+ struct dirent *dent;
+
+ dir = opendir(base);
+ if (dir == NULL)
+ goto end_pcmcia_probe;
+
+ switch (type) {
+#ifndef DISABLE_MEDIAS
+ case MEDIA_ADAPTERS:
+ pcmciadb = medias_pcmcia_ids;
+ len = medias_pcmcia_num_ids;
+ break;
+#endif
+#ifndef DISABLE_NETWORK
+ case NETWORK_DEVICES:
+ pcmciadb = network_pcmcia_ids;
+ len = network_pcmcia_num_ids;
+ break;
+#endif
+ default:
+ goto end_pcmcia_probe;
+ }
+
+ for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
+ struct sysfs_attribute *modalias_attr;
+ char keyfile[256];
+ int i, id;
+
+ if (dent->d_name[0] == '.')
+ continue;
+
+ log_message("PCMCIA: device found %s", dent->d_name);
+
+ snprintf(keyfile, sizeof(keyfile)-1, "%s/%s/modalias", base, dent->d_name);
+ modalias_attr = sysfs_open_attribute(keyfile);
+ if (!modalias_attr)
+ continue;
+ if (sysfs_read_attribute(modalias_attr) != 0 || !modalias_attr->value) {
+ sysfs_close_attribute(modalias_attr);
+ continue;
+ }
+
+ log_message("PCMCIA: device found %s", modalias_attr->value);
+
+ for (i = 0; i < len; i++) {
+ if (!fnmatch(pcmciadb[i].modalias, modalias_attr->value, 0)) {
+ char product[256];
+
+ log_message("PCMCIA: device found %s (%s)", pcmciadb[i].modalias, pcmciadb[i].module);
+ strcpy(product, "");
+ for (id = 1; id <= 4; id++) {
+ struct sysfs_attribute *product_attr;
+ snprintf(keyfile, sizeof(keyfile)-1, "%s/%s/prod_id%d", base, dent->d_name, id);
+ product_attr = sysfs_open_attribute(keyfile);
+ if (!product_attr)
+ continue;
+ if (sysfs_read_attribute(product_attr) || !product_attr->value) {
+ sysfs_close_attribute(product_attr);
+ continue;
+ }
+ snprintf(product + strlen(product), sizeof(product)-strlen(product)-1, "%s%s", product[0] ? " " : "", product_attr->value);
+ if (product[strlen(product)-1] == '\n')
+ product[strlen(product)-1] = '\0';
+ sysfs_close_attribute(product_attr);
+ }
+
+ if (!product[0])
+ strcpy(product, "PCMCIA device");
+
+ log_message("PCMCIA: device found %s (%s)", product, pcmciadb[i].module);
+ discovered_device(type, product, pcmciadb[i].module);
+ }
+ }
+
+ sysfs_close_attribute(modalias_attr);
+ }
+ end_pcmcia_probe:;
+ if (dir)
+ closedir(dir);
+ }
+#endif
+
+ /* be sure to load usb-storage after media adapters, so that they are in
+ same order than reboot, so that naming is the same */
+ if (type == MEDIA_ADAPTERS && (bus == BUS_USB || bus == BUS_SCSI || bus == BUS_ANY) &&
+ already_probed_usb_controllers && !already_loaded_usb_scsi) {
+ already_loaded_usb_scsi = 1;
+ /* we can't allow additional modules floppy since we need usbkbd for keystrokes of usb keyboards */
+ my_insmod("usb_storage", MEDIA_ADAPTERS, NULL, 0);
+ if (module_already_present("ieee1394"))
+ my_insmod("sbp2", MEDIA_ADAPTERS, NULL, 0);
+ wait_message("Detecting USB mass-storage devices.");
+ sleep(10); /* sucking background work */
+ remove_wait_message();
+ }
+}
+
+
+static struct media_info * medias = NULL;
+
+void find_media(enum media_bus bus)
+{
+ char b[50];
+ char buf[5000];
+ struct media_info tmp[50];
+ int count = 0;
+ int fd;
+
+ if (medias)
+ free(medias); /* that does not free the strings, by the way */
+
+ log_message("looking for media adapters");
+ probe_that_type(MEDIA_ADAPTERS, bus);
+
+ /* ----------------------------------------------- */
+ if (bus != BUS_IDE && bus != BUS_ANY)
+ goto find_media_after_ide;
+ log_message("looking for ide media");
+
+ strcpy(b, "/proc/ide/hd");
+ for (b[12] = 'a'; b[12] <= 't'; b[12]++) {
+ int i;
+ char ide_disk[] = "disk";
+ char ide_cdrom[] = "cdrom";
+ char ide_tape[] = "tape";
+ char ide_floppy[] = "floppy";
+
+ /* first, test if file exists (will tell if attached medium exists) */
+ b[13] = '\0';
+ if (access(b, R_OK))
+ continue;
+
+ tmp[count].name = strdup("hda");
+ tmp[count].name[2] = b[12];
+
+ /* media type */
+ strcpy(b + 13, "/media");
+ fd = open(b, O_RDONLY);
+ if (fd == -1) {
+ log_message("failed to open %s for reading", b);
+ continue;
+ }
+
+ i = read(fd, buf, sizeof(buf));
+ if (i == -1) {
+ log_message("failed to read %s", b);
+ continue;
+ }
+ buf[i] = '\0';
+ close(fd);
+
+ if (ptr_begins_static_str(buf, ide_disk))
+ tmp[count].type = DISK;
+ else if (ptr_begins_static_str(buf, ide_cdrom))
+ tmp[count].type = CDROM;
+ else if (ptr_begins_static_str(buf, ide_tape))
+ tmp[count].type = TAPE;
+ else if (ptr_begins_static_str(buf, ide_floppy))
+ tmp[count].type = FLOPPY;
+ else
+ tmp[count].type = UNKNOWN_MEDIA;
+
+ /* media model */
+ strcpy(b + 13, "/model");
+ fd = open(b, O_RDONLY);
+ if (fd == -1) {
+ log_message("failed to open %s for reading", b);
+ continue;
+ }
+
+ i = read(fd, buf, sizeof(buf));
+ if (i <= 0) {
+ log_message("failed to read %s", b);
+ tmp[count].model = strdup("(none)");
+ }
+ else {
+ buf[i-1] = '\0'; /* eat the \n */
+ tmp[count].model = strdup(buf);
+ }
+ close(fd);
+
+ log_message("IDE/%d: %s is a %s", tmp[count].type, tmp[count].name, tmp[count].model);
+ count++;
+ }
+
+ find_media_after_ide:
+ /* ----------------------------------------------- */
+ if (bus != BUS_SCSI && bus != BUS_USB && bus != BUS_PCMCIA && bus != BUS_ANY)
+ goto find_media_after_scsi;
+ log_message("looking for scsi media");
+
+ fd = open("/proc/scsi/scsi", O_RDONLY);
+ if (fd != -1) {
+ FILE * f;
+
+ enum { SCSI_TOP, SCSI_HOST, SCSI_VENDOR, SCSI_TYPE } state = SCSI_TOP;
+ char * start, * chptr, * next, * end;
+ char scsi_disk_count = 'a';
+ char scsi_cdrom_count = '0';
+ char scsi_tape_count = '0';
+
+ char scsi_no_devices[] = "Attached devices: none";
+ char scsi_some_devices[] = "Attached devices:";
+ char scsi_host[] = "Host: ";
+ char scsi_vendor[] = " Vendor: ";
+
+ int i = read(fd, &buf, sizeof(buf)-1);
+ if (i < 1) {
+ close(fd);
+ goto end_scsi;
+ }
+ close(fd);
+ buf[i] = '\0';
+
+ if (ptr_begins_static_str(buf, scsi_no_devices))
+ goto end_scsi;
+
+ start = buf;
+ while (*start) {
+ char tmp_model[50];
+ char tmp_name[10];
+
+ chptr = start;
+ while (*chptr != '\n') chptr++;
+ *chptr = '\0';
+ next = chptr + 1;
+
+ switch (state) {
+ case SCSI_TOP:
+ if (!ptr_begins_static_str(start, scsi_some_devices))
+ goto end_scsi;
+ state = SCSI_HOST;
+ break;
+
+ case SCSI_HOST:
+ if (!ptr_begins_static_str(start, scsi_host))
+ goto end_scsi;
+ state = SCSI_VENDOR;
+ break;
+
+ case SCSI_VENDOR:
+ if (!ptr_begins_static_str(start, scsi_vendor))
+ goto end_scsi;
+
+ /* (1) Grab Vendor info */
+ start += 10;
+ end = chptr = strstr(start, "Model:");
+ if (!chptr)
+ goto end_scsi;
+
+ chptr--;
+ while (*chptr == ' ')
+ chptr--;
+ if (*chptr == ':') {
+ chptr++;
+ *(chptr + 1) = '\0';
+ strcpy(tmp_model,"(unknown)");
+ } else {
+ *(chptr + 1) = '\0';
+ strcpy(tmp_model, start);
+ }
+
+ /* (2) Grab Model info */
+ start = end;
+ start += 7;
+
+ chptr = strstr(start, "Rev:");
+ if (!chptr)
+ goto end_scsi;
+
+ chptr--;
+ while (*chptr == ' ') chptr--;
+ *(chptr + 1) = '\0';
+
+ strcat(tmp_model, " ");
+ strcat(tmp_model, start);
+
+ tmp[count].model = strdup(tmp_model);
+
+ state = SCSI_TYPE;
+
+ break;
+
+ case SCSI_TYPE:
+ if (strncmp(" Type:", start, 7))
+ goto end_scsi;
+ *tmp_name = '\0';
+
+ if (strstr(start, "Direct-Access")) {
+ sprintf(tmp_name, "sd%c", scsi_disk_count++);
+ tmp[count].type = DISK;
+ } else if (strstr(start, "Sequential-Access")) {
+ sprintf(tmp_name, "st%c", scsi_tape_count++);
+ tmp[count].type = TAPE;
+ } else if (strstr(start, "CD-ROM")) {
+ sprintf(tmp_name, "sr%c", scsi_cdrom_count++);
+ tmp[count].type = CDROM;
+ }
+
+ if (!(f = fopen("/proc/partitions", "rb")) || !fgets(buf, sizeof(buf), f) || !fgets(buf, sizeof(buf), f)) {
+ log_message("Couldn't open /proc/partitions");
+ } else {
+ while (fgets(buf, sizeof(buf), f)) {
+ char name[100];
+ int major, minor, blocks;
+ memset(name, 0, sizeof(name));
+ sscanf(buf, " %d %d %d %s", &major, &minor, &blocks, name);
+ if (streq(name, tmp_name) && tmp[count].type == DISK && ((blocks == 1048575) || (blocks == 1440)))
+ tmp[count].type = FLOPPY;
+ }
+ fclose(f);
+ }
+
+ if (*tmp_name) {
+ tmp[count].name = strdup(tmp_name);
+ log_message("SCSI/%d: %s is a %s", tmp[count].type, tmp[count].name, tmp[count].model);
+ count++;
+ }
+
+ state = SCSI_HOST;
+ }
+
+ start = next;
+ }
+
+ end_scsi:;
+ }
+
+ /* ----------------------------------------------- */
+ log_message("looking for Compaq Smart Array media");
+ {
+ char * procfiles[] = { "/proc/driver/cpqarray/ida0", "/proc/driver/cciss/cciss0", // 2.4 style
+ "/proc/array/ida", "/proc/cciss/cciss", // 2.2 style
+ NULL };
+ static char cpq_descr[] = "Compaq RAID logical disk";
+ char ** procfile;
+ FILE * f;
+
+ for (procfile = procfiles; procfile && *procfile; procfile++) {
+ if((f = fopen(*procfile, "rb"))) {
+ while (fgets(buf, sizeof(buf), f)) {
+ if (ptr_begins_static_str(buf, "ida/") || ptr_begins_static_str(buf, "cciss/")) {
+ char * end = strchr(buf, ':');
+ if (!end)
+ log_message("Inconsistency in %s, line:\n%s", *procfile, buf);
+ else {
+ *end = '\0';
+ tmp[count].name = strdup(buf);
+ tmp[count].type = DISK;
+ tmp[count].model = cpq_descr;
+ log_message("CPQ: found %s", tmp[count].name);
+ count++;
+ }
+ }
+ }
+ fclose(f);
+ }
+ }
+ }
+
+ /* ----------------------------------------------- */
+ log_message("looking for DAC960");
+ {
+ FILE * f;
+ if ((f = fopen("/tmp/syslog", "rb"))) {
+ while (fgets(buf, sizeof(buf), f)) {
+ char * start;
+ if ((start = strstr(buf, "/dev/rd/"))) {
+ char * end = strchr(start, ':');
+ if (!end)
+ log_message("Inconsistency in syslog, line:\n%s", buf);
+ else {
+ *end = '\0';
+ tmp[count].name = strdup(start+5);
+ tmp[count].type = DISK;
+ start = end + 2;
+ end = strchr(start, ',');
+ if (end) {
+ *end = '\0';
+ tmp[count].model = strdup(start);
+ } else
+ tmp[count].model = "(unknown)";
+ log_message("DAC960: found %s (%s)", tmp[count].name, tmp[count].model);
+ count++;
+ }
+ }
+ }
+ fclose(f);
+ }
+ }
+ find_media_after_scsi:
+
+ /* ----------------------------------------------- */
+ tmp[count].name = NULL;
+ count++;
+
+ medias = memdup(tmp, sizeof(struct media_info) * count);
+}
+
+
+/* Finds by media */
+void get_medias(enum media_type media, char *** names, char *** models, enum media_bus bus)
+{
+ struct media_info * m;
+ char * tmp_names[50];
+ char * tmp_models[50];
+ int count;
+
+ find_media(bus);
+
+ m = medias;
+
+ count = 0;
+ while (m && m->name) {
+ if (m->type == media) {
+ tmp_names[count] = strdup(m->name);
+ tmp_models[count++] = strdup(m->model);
+ }
+ m++;
+ }
+ tmp_names[count] = NULL;
+ tmp_models[count++] = NULL;
+
+ *names = memdup(tmp_names, sizeof(char *) * count);
+ *models = memdup(tmp_models, sizeof(char *) * count);
+}
+
+
+#ifndef DISABLE_NETWORK
+static int is_net_interface_blacklisted(char *intf)
+{
+ /* see detect_devicess::is_lan_interface() */
+ char * blacklist[] = { "lo", "ippp", "isdn", "plip", "ppp", "wifi", "sit", NULL };
+ char ** ptr = blacklist;
+
+ while (ptr && *ptr) {
+ if (!strncmp(intf, *ptr, strlen(*ptr)))
+ return 1;
+ ptr++;
+ }
+
+ return 0;
+}
+
+char ** get_net_devices(void)
+{
+ char * tmp[50];
+ static int already_probed = 0;
+ FILE * f;
+ int i = 0;
+
+ if (!already_probed) {
+ already_probed = 1; /* cut off loop brought by: probe_that_type => my_insmod => get_net_devices */
+ probe_that_type(NETWORK_DEVICES, BUS_ANY);
+ }
+
+ /* use /proc/net/dev since SIOCGIFCONF doesn't work with some drivers (rt2500) */
+ f = fopen("/proc/net/dev", "rb");
+ if (f) {
+ char line[128];
+
+ /* skip the two first lines */
+ fgets(line, sizeof(line), f);
+ fgets(line, sizeof(line), f);
+
+ while (1) {
+ char *start, *end;
+ if (!fgets(line, sizeof(line), f))
+ break;
+ start = line;
+ while (*start == ' ')
+ start++;
+ end = strchr(start, ':');
+ if (end)
+ end[0] = '\0';
+ if (!is_net_interface_blacklisted(start)) {
+ log_message("found net interface %s", start);
+ tmp[i++] = strdup(start);
+ } else {
+ log_message("found net interface %s, but blacklisted", start);
+ }
+ }
+
+ fclose(f);
+ } else {
+ log_message("net: could not open devices file");
+ }
+
+ tmp[i++] = NULL;
+
+ return memdup(tmp, sizeof(char *) * i);
+
+}
+#endif /* DISABLE_NETWORK */
diff --git a/mdk-stage1/probing.h b/mdk-stage1/probing.h
new file mode 100644
index 000000000..fe427f541
--- /dev/null
+++ b/mdk-stage1/probing.h
@@ -0,0 +1,65 @@
+/*
+ * Guillaume Cottenceau (gc@mandrakesoft.com)
+ *
+ * Copyright 2000 Mandrakesoft
+ *
+ * This software may be freely redistributed under the terms of the GNU
+ * public license.
+ *
+ * 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.
+ *
+ */
+
+/*
+ * Portions from Erik Troan (ewt@redhat.com)
+ *
+ * Copyright 1996 Red Hat Software
+ *
+ */
+
+#ifndef _PROBING_H_
+#define _PROBING_H_
+
+enum media_type { CDROM, DISK, FLOPPY, TAPE, UNKNOWN_MEDIA };
+
+enum driver_type { MEDIA_ADAPTERS, NETWORK_DEVICES, USB_CONTROLLERS,
+ VIRTIO_DEVICES, ANY_DRIVER_TYPE };
+
+enum media_bus { BUS_IDE, BUS_SCSI, BUS_USB, BUS_PCMCIA, BUS_ANY };
+
+#define VIRTIO_PCI_VENDOR 0x1af4
+#define VIRTIO_ID_NET 0x0001
+#define VIRTIO_ID_BLOCK 0x0002
+#define VIRTIO_ID_BALLOON 0x0005
+
+void find_media(enum media_bus bus);
+void get_medias(enum media_type media, char *** names, char *** models, enum media_bus bus);
+char ** get_net_devices(void);
+void net_discovered_interface(char * intf_name);
+char * get_net_intf_description(char * intf_name);
+void prepare_intf_descr(const char * intf_descr);
+void probe_that_type(enum driver_type type, enum media_bus bus);
+
+/* Make sure the MATCH_ALL value is greater than all possible values
+ for subvendor & subdevice: this simplifies the orderer */
+#define PCITABLE_MATCH_ALL 0x10000
+
+struct pcitable_entry {
+ /* some bits stolen from pci-resource/pci-ids.h
+ * FIXME: split pci-ids.h into pci-ids.c and pci-ids.h so that the header can be re-used
+ */
+ unsigned short vendor; /* PCI vendor id */
+ unsigned short device; /* PCI device id */
+ unsigned int subvendor; /* PCI subvendor id */
+ unsigned int subdevice; /* PCI subdevice id */
+ char module[20]; /* module to load */
+ char description[100]; /* PCI human readable description */
+};
+extern struct pcitable_entry *detected_devices;
+extern int detected_devices_len;
+void probing_detect_devices();
+void probing_destroy(void);
+
+#endif
diff --git a/mdk-stage1/rescue-gui.c b/mdk-stage1/rescue-gui.c
new file mode 100644
index 000000000..fbf23329a
--- /dev/null
+++ b/mdk-stage1/rescue-gui.c
@@ -0,0 +1,297 @@
+/*
+ * Guillaume Cottenceau (gc@mandrakesoft.com)
+ *
+ * Copyright 2001 Mandrakesoft
+ *
+ *
+ * This software may be freely redistributed under the terms of the GNU
+ * public license.
+ *
+ * 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.
+ *
+ */
+
+#include <stdlib.h>
+#define _USE_BSD
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdio.h>
+#include <sys/mount.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <linux/unistd.h>
+#include <sys/select.h>
+
+#include "config-stage1.h"
+#include "frontend.h"
+#include "utils.h"
+#include "params.h"
+
+#include <sys/syscall.h>
+#define reboot(...) syscall(__NR_reboot, __VA_ARGS__)
+
+#if defined(__i386__) || defined(__x86_64__)
+#define ENABLE_RESCUE_MS_BOOT 1
+#endif
+
+char * env[] = {
+ "PATH=/usr/bin:/bin:/sbin:/usr/sbin:/mnt/sbin:/mnt/usr/sbin:/mnt/bin:/mnt/usr/bin",
+ "LD_LIBRARY_PATH=/lib:/usr/lib:/mnt/lib:/mnt/usr/lib:/usr/X11R6/lib:/mnt/usr/X11R6/lib"
+#if defined(__x86_64__) || defined(__ppc64__)
+ ":/lib64:/usr/lib64:/usr/X11R6/lib64:/mnt/lib64:/mnt/usr/lib64:/mnt/usr/X11R6/lib64"
+#endif
+ ,
+ "HOME=/",
+ "TERM=linux",
+ "TERMINFO=/etc/terminfo",
+ NULL
+};
+
+/* pause() already exists and causes the invoking process to sleep
+ until a signal is received */
+static void PAUSE(void) {
+ unsigned char t;
+ fflush(stdout);
+ read(0, &t, 1);
+}
+
+
+/* ------ UUURGH this is duplicated from `init.c', don't edit here........ */
+void fatal_error(char *msg)
+{
+ printf("FATAL ERROR IN RESCUE: %s\n\nI can't recover from this.\nYou may reboot your system.\n", msg);
+ while (1);
+}
+
+#define LOOP_CLR_FD 0x4C01
+void del_loop(char *device)
+{
+ int fd;
+ if ((fd = open(device, O_RDONLY, 0)) < 0) {
+ printf("del_loop open failed\n");
+ return;
+ }
+
+ if (ioctl(fd, LOOP_CLR_FD, 0) < 0) {
+ printf("del_loop ioctl failed");
+ return;
+ }
+
+ close(fd);
+}
+struct filesystem { char * dev; char * name; char * fs; int mounted; };
+void unmount_filesystems(void)
+{
+ int fd, size;
+ char buf[65535]; /* this should be big enough */
+ char *p;
+ struct filesystem fs[500];
+ int numfs = 0;
+ int i, nb;
+
+ printf("unmounting filesystems...\n");
+
+ fd = open("/proc/mounts", O_RDONLY, 0);
+ if (fd < 1) {
+ printf("ERROR: failed to open /proc/mounts");
+ sleep(2);
+ return;
+ }
+
+ size = read(fd, buf, sizeof(buf) - 1);
+ buf[size] = '\0';
+
+ close(fd);
+
+ p = buf;
+ while (*p) {
+ fs[numfs].mounted = 1;
+ fs[numfs].dev = p;
+ while (*p != ' ') p++;
+ *p++ = '\0';
+ fs[numfs].name = p;
+ while (*p != ' ') p++;
+ *p++ = '\0';
+ fs[numfs].fs = p;
+ while (*p != ' ') p++;
+ *p++ = '\0';
+ while (*p != '\n') p++;
+ p++;
+ if (strcmp(fs[numfs].name, "/") != 0) numfs++; /* skip if root, no need to take initrd root in account */
+ }
+
+ /* Pixel's ultra-optimized sorting algorithm:
+ multiple passes trying to umount everything until nothing moves
+ anymore (a.k.a holy shotgun method) */
+ do {
+ nb = 0;
+ for (i = 0; i < numfs; i++) {
+ /*printf("trying with %s\n", fs[i].name);*/
+ if (fs[i].mounted && umount(fs[i].name) == 0) {
+ if (strncmp(fs[i].dev + sizeof("/dev/") - 1, "loop",
+ sizeof("loop") - 1) == 0)
+ del_loop(fs[i].dev);
+
+ printf("\t%s\n", fs[i].name);
+ fs[i].mounted = 0;
+ nb++;
+ }
+ }
+ } while (nb);
+
+ for (i = nb = 0; i < numfs; i++)
+ if (fs[i].mounted) {
+ printf("\t%s umount failed\n", fs[i].name);
+ if (strcmp(fs[i].fs, "ext2") == 0) nb++; /* don't count not-ext2 umount failed */
+ }
+
+ if (nb) {
+ printf("failed to umount some filesystems\n");
+ while (1);
+ }
+}
+/* ------ UUURGH -- end */
+
+
+/* ------ UUURGH -- this is dirrrrrttttyyyyyy */
+void probe_that_type(void) {}
+void exit_bootsplash(void) {}
+
+
+int main(int argc __attribute__ ((unused)), char **argv __attribute__ ((unused)))
+{
+ enum return_type results;
+
+ char install_bootloader[] = "Re-install Boot Loader";
+#if ENABLE_RESCUE_MS_BOOT
+ char restore_ms_boot[] = "Restore Windows Boot Loader";
+#endif
+ char mount_parts[] = "Mount your partitions under /mnt";
+ char go_to_console[] = "Go to console";
+ char reboot_[] = "Reboot";
+ char doc[] = "Doc: what's addressed by this Rescue?";
+
+ char upgrade[] = "Upgrade to New Version";
+ char rootpass[] = "Reset Root Password";
+ char userpass[] = "Reset User Password";
+ char factory[] = "Reset to Factory Defaults";
+ char backup[] = "Backup User Files";
+ char restore[] = "Restore User Files from Backup";
+ char badblocks[] = "Test Key for Badblocks";
+
+ char * actions_default[] = { install_bootloader,
+#if ENABLE_RESCUE_MS_BOOT
+ restore_ms_boot,
+#endif
+ mount_parts, go_to_console, reboot_, doc, NULL };
+ char * actions_flash_rescue[] = { rootpass, userpass, factory, backup, restore,
+ badblocks, go_to_console, reboot_, NULL };
+ char * actions_flash_upgrade[] = { upgrade, go_to_console, reboot_, NULL };
+
+
+ char * flash_mode;
+ char ** actions;
+ char * choice;
+
+ process_cmdline();
+ flash_mode = get_param_valued("flash");
+ actions = !flash_mode ?
+ actions_default :
+ streq(flash_mode, "upgrade") ? actions_flash_upgrade : actions_flash_rescue;
+
+ init_frontend("Welcome to " DISTRIB_NAME " Rescue (" DISTRIB_VERSION ") " __DATE__ " " __TIME__);
+
+ do {
+ int pid;
+ char * binary = NULL;
+
+ choice = "";
+ results = ask_from_list("Please choose the desired action.", actions, &choice);
+
+ if (ptr_begins_static_str(choice, install_bootloader)) {
+ binary = "/usr/bin/install_bootloader";
+ }
+#if ENABLE_RESCUE_MS_BOOT
+ if (ptr_begins_static_str(choice, restore_ms_boot)) {
+ binary = "/usr/bin/restore_ms_boot";
+ }
+#endif
+ if (ptr_begins_static_str(choice, mount_parts)) {
+ binary = "/usr/bin/guessmounts";
+ }
+ if (ptr_begins_static_str(choice, reboot_)) {
+ finish_frontend();
+ sync(); sync();
+ sleep(2);
+ unmount_filesystems();
+ sync(); sync();
+ printf("rebooting system\n");
+ sleep(2);
+ reboot(0xfee1dead, 672274793, 0x01234567);
+ }
+ if (ptr_begins_static_str(choice, doc)) {
+ binary = "/usr/bin/rescue-doc";
+ }
+
+ /* Mandriva Flash entries */
+ if (ptr_begins_static_str(choice, rootpass)) {
+ binary = "/usr/bin/reset_rootpass";
+ }
+ if (ptr_begins_static_str(choice, userpass)) {
+ binary = "/usr/bin/reset_userpass";
+ }
+ if (ptr_begins_static_str(choice, factory)) {
+ binary = "/usr/bin/clear_systemloop";
+ }
+ if (ptr_begins_static_str(choice, backup)) {
+ binary = "/usr/bin/backup_systemloop";
+ }
+ if (ptr_begins_static_str(choice, restore)) {
+ binary = "/usr/bin/restore_systemloop";
+ }
+ if (ptr_begins_static_str(choice, badblocks)) {
+ binary = "/usr/bin/test_badblocks";
+ }
+ if (ptr_begins_static_str(choice, upgrade)) {
+ binary = "/usr/bin/upgrade";
+ }
+
+ if (binary) {
+ int wait_status;
+ suspend_to_console();
+ if (!(pid = fork())) {
+
+ char * child_argv[2];
+ child_argv[0] = binary;
+ child_argv[1] = NULL;
+
+ execve(child_argv[0], child_argv, env);
+ printf("Can't execute binary (%s)\n<press Enter>\n", binary);
+ PAUSE();
+
+ return 33;
+ }
+ while (wait4(-1, &wait_status, 0, NULL) != pid) {};
+ printf("<press Enter to return to Rescue menu>");
+ PAUSE();
+ resume_from_suspend();
+ if (!WIFEXITED(wait_status) || WEXITSTATUS(wait_status) != 0) {
+ error_message("Program exited abnormally (return code %d).", WEXITSTATUS(wait_status));
+ if (WIFSIGNALED(wait_status))
+ error_message("(received signal %d)", WTERMSIG(wait_status));
+ }
+ }
+
+ } while (results == RETURN_OK && !ptr_begins_static_str(choice, go_to_console));
+
+ finish_frontend();
+ printf("Bye.\n");
+
+ return 0;
+}
diff --git a/mdk-stage1/rp-pppoe/README b/mdk-stage1/rp-pppoe/README
new file mode 100644
index 000000000..269fc16be
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/README
@@ -0,0 +1,87 @@
+pppoe: a PPP-over-Ethernet redirector for pppd
+Copyright (C) 2001 Roaring Penguin Software Inc.
+
+Much inspiration from an earlier client by Luke Stras.
+
+The MSS clamping was inspired by mssclampfw by Marc Boucher <marc@mbsi.ca>
+with acknowledgements to Rebel.com (http://www.rebel.com). However, the
+actual MSS clamping code is original and is licensed under the GPL, unlike
+the original mssclampfw.
+
+Introduction
+============
+
+pppoe is a user-space redirector which permits the use of PPPoE
+(Point-to-Point Over Ethernet) with Linux. PPPoE is used by many
+ADSL service providers.
+
+Installation
+============
+
+Requirements
+------------
+
+1) Linux 2.2.9 or later on Intel, Sparc or PowerPC. It may work on
+ Alpha, too -- anyone care to let me know?
+
+ OR
+
+ Linux 2.0.36 or later.
+
+ OR
+
+ FreeBSD, NetBSD or OpenBSD with BPF support. I have access only
+ to FreeBSD. In general, I can't answer questions about the *BSD's
+ as well as I can about Linux.
+
+
+2) pppd 2.3.10 or later. Versions 2.3.7 and later work unless you use
+ demand-dialling. For demand dialling, you *must* use 2.3.10 or later.
+
+QUICKSTART
+----------
+
+If you're lucky, the "quickstart" method will work. After unpacking
+the archive, become root and type:
+
+ ./go
+
+This should configure, compile and install the software and set up your
+ADSL connection. You'll have to answer a few questions along the way.
+
+If you want the GUI wrapper, type:
+
+ ./go-gui
+
+If ./go and ./go-gui didn't work, read the rest of this README.
+
+Compiling
+---------
+
+Compile and install pppd if you don't already have it. Then:
+
+1) Unpack:
+
+ $ tar xzvf rp-pppoe-xxx.tar.gz
+
+2) Change to source directory:
+
+ $ cd src
+
+3) Configure:
+
+ $ ./configure
+
+4) Compile:
+
+ $ make
+
+4) Install (this step must be done as root)
+
+ # make install
+
+5) Now read doc/HOW-TO-CONNECT
+
+--
+David F. Skoll <dfs@roaringpenguin.com> | Roaring Penguin Software Inc.
+http://www.roaringpenguin.com | Linux and UNIX Specialists \ No newline at end of file
diff --git a/mdk-stage1/rp-pppoe/configs/firewall-masq b/mdk-stage1/rp-pppoe/configs/firewall-masq
new file mode 100644
index 000000000..cb16fbecf
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/configs/firewall-masq
@@ -0,0 +1,35 @@
+#!/bin/sh
+#
+# firewall-masq This script sets up firewall rules for a machine
+# acting as a masquerading gateway
+#
+# Copyright (C) 2000 Roaring Penguin Software Inc. This software may
+# be distributed under the terms of the GNU General Public License, version
+# 2 or any later version.
+
+# Interface to Internet
+EXTIF=ppp+
+
+ANY=0.0.0.0/0
+
+ipchains -P input ACCEPT
+ipchains -P output ACCEPT
+ipchains -P forward DENY
+
+ipchains -F forward
+ipchains -F input
+ipchains -F output
+
+# Deny TCP and UDP packets to privileged ports
+ipchains -A input -l -i $EXTIF -d $ANY 0:1023 -p udp -j DENY
+ipchains -A input -l -i $EXTIF -d $ANY 0:1023 -p tcp -j DENY
+
+# Deny TCP connection attempts
+ipchains -A input -l -i $EXTIF -p tcp -y -j DENY
+
+# Deny ICMP echo-requests
+ipchains -A input -l -i $EXTIF -s $ANY echo-request -p icmp -j DENY
+
+# Do masquerading
+ipchains -A forward -j MASQ
+echo 1 > /proc/sys/net/ipv4/ip_forward
diff --git a/mdk-stage1/rp-pppoe/configs/firewall-standalone b/mdk-stage1/rp-pppoe/configs/firewall-standalone
new file mode 100644
index 000000000..bcb1e92b1
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/configs/firewall-standalone
@@ -0,0 +1,32 @@
+#!/bin/sh
+#
+# firewall-standalone This script sets up firewall rules for a standalone
+# machine
+#
+# Copyright (C) 2000 Roaring Penguin Software Inc. This software may
+# be distributed under the terms of the GNU General Public License, version
+# 2 or any later version.
+
+# Interface to Internet
+EXTIF=ppp+
+
+ANY=0.0.0.0/0
+
+ipchains -P input ACCEPT
+ipchains -P output ACCEPT
+ipchains -P forward DENY
+
+ipchains -F forward
+ipchains -F input
+ipchains -F output
+
+# Deny TCP and UDP packets to privileged ports
+ipchains -A input -l -i $EXTIF -d $ANY 0:1023 -p udp -j DENY
+ipchains -A input -l -i $EXTIF -d $ANY 0:1023 -p tcp -j DENY
+
+# Deny TCP connection attempts
+ipchains -A input -l -i $EXTIF -p tcp -y -j DENY
+
+# Deny ICMP echo-requests
+ipchains -A input -l -i $EXTIF -s $ANY echo-request -p icmp -j DENY
+
diff --git a/mdk-stage1/rp-pppoe/configs/pap-secrets b/mdk-stage1/rp-pppoe/configs/pap-secrets
new file mode 100644
index 000000000..f4483a723
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/configs/pap-secrets
@@ -0,0 +1,9 @@
+# Edit this file and place it in /etc/ppp/pap-secrets
+
+#User #Server #Password #IP
+bxxxxx@sympatico.ca * my_password *
+
+# Replace bxxxxx@sympatico.ca with your Sympatico user-ID
+# Replace my_password with your Sympatico password
+
+# For Magma, use xxyyzz@magma.ca
diff --git a/mdk-stage1/rp-pppoe/configs/pppoe-server-options b/mdk-stage1/rp-pppoe/configs/pppoe-server-options
new file mode 100644
index 000000000..8319870ac
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/configs/pppoe-server-options
@@ -0,0 +1,5 @@
+# PPP options for the PPPoE server
+require-pap
+login
+lcp-echo-interval 10
+lcp-echo-failure 2
diff --git a/mdk-stage1/rp-pppoe/configs/pppoe.conf b/mdk-stage1/rp-pppoe/configs/pppoe.conf
new file mode 100644
index 000000000..6643f1778
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/configs/pppoe.conf
@@ -0,0 +1,126 @@
+#***********************************************************************
+#
+# pppoe.conf
+#
+# Configuration file for rp-pppoe. Edit as appropriate and install in
+# /etc/ppp/pppoe.conf
+#
+# NOTE: This file is used by the adsl-start, adsl-stop, adsl-connect and
+# adsl-status shell scripts. It is *not* used in any way by the
+# "pppoe" executable.
+#
+# Copyright (C) 2000 Roaring Penguin Software Inc.
+#
+# This file may be distributed under the terms of the GNU General
+# Public License.
+#
+# $Id: pppoe.conf 195724 2001-06-11 13:49:39Z gc $
+#***********************************************************************
+
+# When you configure a variable, DO NOT leave spaces around the "=" sign.
+
+# Ethernet card connected to ADSL modem
+ETH=eth1
+
+# ADSL user name. You may have to supply "@provider.com" Sympatico
+# users in Canada do need to include "@sympatico.ca"
+# Sympatico uses PAP authentication. Make sure /etc/ppp/pap-secrets
+# contains the right username/password combination.
+# For Magma, use xxyyzz@magma.ca
+USER=bxxxnxnx@sympatico.ca
+
+# Bring link up on demand? Default is to leave link up all the time.
+# If you want the link to come up on demand, set DEMAND to a number indicating
+# the idle time after which the link is brought down.
+DEMAND=no
+#DEMAND=300
+
+# DNS type: SERVER=obtain from server; SPECIFY=use DNS1 and DNS2;
+# NOCHANGE=do not adjust.
+DNSTYPE=SERVER
+
+# Obtain DNS server addresses from the peer (recent versions of pppd only)
+USEPEERDNS=yes
+
+DNS1=
+DNS2=
+
+### ONLY TOUCH THE FOLLOWING SETTINGS IF YOU'RE AN EXPERT
+
+# How long adsl-start waits for a new PPP interface to appear before
+# concluding something went wrong. If you use 0, then adsl-start
+# exits immediately with a successful status and does not wait for the
+# link to come up. Time is in seconds.
+#
+# WARNING WARNING WARNING:
+#
+# If you are using rp-pppoe on a physically-inaccessible host, set
+# CONNECT_TIMEOUT to 0. This makes SURE that the machine keeps trying
+# to connect forever after adsl-start is called. Otherwise, it will
+# give out after CONNECT_TIMEOUT seconds and will not attempt to
+# connect again, making it impossible to reach.
+CONNECT_TIMEOUT=30
+
+# How often in seconds adsl-start polls to check if link is up
+CONNECT_POLL=2
+
+# Specific desired AC Name
+ACNAME=
+
+# Specific desired service name
+SERVICENAME=
+
+# Character to echo at each poll. Use PING="" if you don't want
+# anything echoed
+PING="."
+
+# File where the adsl-connect script writes its process-ID.
+# Three files are actually used:
+# $PIDFILE contains PID of adsl-connect script
+# $PIDFILE.pppoe contains PID of pppoe process
+# $PIDFILE.pppd contains PID of pppd process
+CF_BASE=`basename $CONFIG`
+PIDFILE="/var/run/$CF_BASE-adsl.pid"
+
+# Do you want to use synchronous PPP? "yes" or "no". "yes" is much
+# easier on CPU usage, but may not work for you. It is safer to use
+# "no", but you may want to experiment with "yes". "yes" is generally
+# safe on Linux machines with the n_hdlc line discipline; unsafe on others.
+SYNCHRONOUS=no
+
+# Do you want to clamp the MSS? Here's how to decide:
+# - If you have only a SINGLE computer connected to the ADSL modem, choose
+# "no".
+# - If you have a computer acting as a gateway for a LAN, choose "1412".
+# The setting of 1412 is safe for either setup, but uses slightly more
+# CPU power.
+CLAMPMSS=1412
+#CLAMPMSS=no
+
+# LCP echo interval and failure count.
+LCP_INTERVAL=20
+LCP_FAILURE=3
+
+# PPPOE_TIMEOUT should be about 4*LCP_INTERVAL
+PPPOE_TIMEOUT=80
+
+# Firewalling: One of NONE, STANDALONE or MASQUERADE
+FIREWALL=NONE
+
+# Linux kernel-mode plugin for pppd. If you want to try the kernel-mode
+# plugin, use LINUX_PLUGIN=/etc/ppp/plugins/rp-pppoe.so
+LINUX_PLUGIN=
+
+# Any extra arguments to pass to pppoe. Normally, use a blank string
+# like this:
+PPPOE_EXTRA=""
+
+# Rumour has it that "Citizen's Communications" with a 3Com
+# HomeConnect ADSL Modem DualLink requires these extra options:
+# PPPOE_EXTRA="-f 3c12:3c13 -S ISP"
+
+# Any extra arguments to pass to pppd. Normally, use a blank string
+# like this:
+PPPD_EXTRA=""
+
+
diff --git a/mdk-stage1/rp-pppoe/doc/CHANGES b/mdk-stage1/rp-pppoe/doc/CHANGES
new file mode 100644
index 000000000..c009c84ad
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/doc/CHANGES
@@ -0,0 +1,177 @@
+Changes from Version 2.8 to 3.0:
+
+- Many small improvements to server. Server now only makes one
+ discovery socket, systemwide, with addition of "-n" option to pppoe.
+
+- Fixes for compilation problems on BSD, Solaris and some Linux platforms.
+
+- Added "-p" option to pppoe-server to allow you to specify a pool of
+ IP addresses to assign to clients.
+
+- Added GUI system (tkpppoe). This work was funded by Iospan
+ Wireless, Inc. The GUI includes a Set-UID wrapper (pppoe-wrapper)
+ which allows ordinary users to control a link (if so authorized.)
+ I believe the wrapper script is secure, but please audit the
+ source code (gui/wrapper.c) if you have any concerns.
+
+- Changes to scripts and pppoe.conf. DNS setup is now dynamic (happens
+ each time adsl-connect runs.)
+
+- Made relay.c check packet lengths rigorously; made it throw out Ethernet
+ frame padding on session packets as well as discovery packets.
+
+Changes from Version 2.7 to 2.8:
+
+- Added init scripts for TurboLinux, courtesy of Yasuhiro Sumi.
+
+- Made relay.c check packet lengths rigorously; made it throw out Ethernet
+ frame padding on discovery packets.
+
+*** NOTE: 2.7 was not released publicly
+
+Changes from Version 2.6 to 2.7:
+
+- Completely restructured source file tree.
+
+- Much internal restructuring to eliminate a bunch of global variables.
+
+- adsl-connect now executes /etc/ppp/adsl-lost whenever connection is dropped
+ or cannot be established.
+
+- Split pppoe.c into pppoe.c and discovery.c.
+
+- Added relay agent (pppoe-relay).
+
+- Made adsl-connect script use the "-U" (host-unique) option to better support
+ multiple PPPoE links.
+
+- Added support for kernel-mode PPPoE (EXPERIMENTAL, UNSUPPORTED!)
+
+- Added "-o" option to PPPoE server; encoded server PID in pppoe-server
+ cookie.
+
+Changes from Version 2.5 to 2.6:
+
+- Code should now compile cleanly on Caldera and Slackware Linux
+
+- Fixed rp-pppoe.spec file to work on Mandrake and Red Hat.
+
+- Deleted some obsolete files
+
+- Fixed bug in Solaris/x86 port (thanks to Philippe Levan)
+
+- Made shell scripts nicer under Solaris (again, Philippe Levan)
+
+- Made adsl-status look under /var/run and /etc/ppp for PID files. Should
+ fix problems with NetBSD.
+
+- Added PPPD_EXTRA to pppoe.conf; made the PID file depend on the config
+ file name. This makes it easier to run multiple PPPoE sessions.
+
+Changes from Version 2.4 to 2.5:
+
+- Tested for zero-length TCP option-length field, and for reverse-packing
+ of type/code bitfields. Thanks to Robert Schlabbach for pointing out
+ these problems.
+
+- Set umask to 077 in adsl-setup.in to protect created files like
+ /etc/ppp/pap-secrets.
+
+Changes from Version 2.3 to 2.4:
+
+- Fixed spec file to automatically add .gz extension to man files as required
+
+- Tightened firewall rules.
+
+- Better check for /var/run in adsl-status; minor shell script fixes and
+ cleanups for NetBSD and Solaris.
+
+- Added FAQ to HOW-TO-CONNECT regarding running a script each time a
+ connection is made.
+
+Changes from Version 2.2 to 2.3:
+
+- Fixed the init script to create/remove /var/lock/subsys/adsl (patch
+ courtesy of Charley Carter.)
+
+- Added support (under Linux) for N_HDLC line discipline which should
+ greatly reduce CPU usage. My tests show it cuts CPU usage in half.
+ My 486 DX2/66 gets 800 kb/s at 22% CPU usage.
+
+- adsl-connect uses "setsid" (if available) so that adsl-stop doesn't kill
+ its caller. There is (IMO) a bug in pppd which kills all processes in
+ its process group if the "pty" option is used. The setsid program gets
+ around this bug, on Linux at least.
+
+- Port to Solaris, courtesy of David Holland.
+
+- Renamed spec file from "spec" to "rp-pppoe.spec" and made some cleanups.
+ NOTE: Red Hat, in their infinite wisdom, decided to make the new RPM
+ compress man pages automatically. You may have problems building RPM's
+ from source unless you get the latest rpm package and make sure it
+ compresses man pages.
+
+Changes from Version 2.1 to 2.2:
+
+- Added "-f" option to pppoe to allow use of any Ethernet frame type
+ for PPPoE. USE WITH CAUTION -- this is a workaround for broken DSL
+ providers, not something you should monkey with freely!
+
+- Added pppoe-sniff program to help expose non-standard PPPoE implementations.
+
+Changes from Version 2.0 to 2.1:
+
+- Fixed minor bugs in bounds-checking
+
+- Modified adsl-status to use output of "netstat -r -n" to determine whether
+ or not link is up. This should make it independent of locale, I hope!
+
+- Added "-k" and "-d" options to pppoe.
+
+Changes from Version 1.9 to 2.0:
+
+- Addition of pppoe-server
+
+- Massive internal code restructuring
+
+- Zealous bounds-checking everywhere.
+
+- adsl-setup now quotes user name and password in /etc/ppp/pap-secrets.
+
+- Ported to OpenBSD, FreeBSD and NetBSD, courtesy of Geoff Mottram
+ and Yannis Sismanis.
+
+- Rearranged adsl-* shell scripts, courtesy of Heiko Schlittermann.
+
+- Fixed bug in which Host-Uniq did not work if access concentrator sent
+ a cookie.
+
+- Addition of SuSE-specific "init" script, courtesy of Gary Cameron.
+
+Changes from Version 1.8 to 1.9:
+
+- Added some more documentation to HOW-TO-CONNECT
+
+- Demand-dialling option now works correctly
+
+- SIGHUP terminates pppoe after sending a PADT to the access concentrator
+
+- Minor cleanups to connection shell scripts
+
+Changes from Version 1.7 to 1.8:
+
+- Added demand-dialling option
+
+- Clarified HOW-TO-CONNECT
+
+- Added adsl-status script
+
+- Added "restart" and "status" options to Red Hat /etc/rc.d/init.d/adsl script
+
+- Made adsl-setup check for existence of pppd
+
+- Wildcarded external interface in firewall rules
+
+- Made pppoe send a PADT frame if connection is terminated
+
+$Id: CHANGES 195724 2001-06-11 13:49:39Z gc $
diff --git a/mdk-stage1/rp-pppoe/doc/HOW-TO-CONNECT b/mdk-stage1/rp-pppoe/doc/HOW-TO-CONNECT
new file mode 100644
index 000000000..c2863f51d
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/doc/HOW-TO-CONNECT
@@ -0,0 +1,295 @@
+$Id: HOW-TO-CONNECT 195724 2001-06-11 13:49:39Z gc $
+
+This package lets you connect a Linux machine to Sympatico HSE or Magma's
+high-speed service using a Nortel 1-meg modem.
+
+Follow these steps and you should have your high-speed service up and running.
+
+0. Install the rp-pppoe-software
+--------------------------------
+
+You should have already done this by the time you're reading this. If not,
+go back and read README.
+
+1. Set up your Ethernet hardware
+--------------------------------
+
+First, make sure the Ethernet card you intend to use with the modem is
+visible to the Linux kernel. Just how to do this is beyond the scope
+of this document. However, if the card is the only Ethernet card in
+the system, executing:
+
+ ifconfig eth0
+
+should display something like this:
+
+ eth0 Link encap:Ethernet HWaddr 00:60:67:62:31:D4
+
+plust some more lines. Your HWaddr will be different. As long as you see
+the HWaddr line, your card should be working.
+
+DO NOT assign an IP address to the Ethernet card. DO NOT configure the
+card to come up at boot time.
+
+2. Configure various files
+--------------------------
+
+Several files need editing. The easiest way to do this is to run
+the following command as root:
+
+ adsl-setup
+
+Answer the questions and you should be all set. If you want to know what
+goes on behind the scenes, continue reading this document. If you don't
+care and your connection works, stop reading. :-)
+
+3. Edit pap-secrets
+-------------------
+
+Edit the "pap-secrets" file, inserting your proper user-ID and password.
+Install the file (or copy the relevant lines) to /etc/ppp/pap-secrets.
+Your ISP may use CHAP authentication. In this case, add the line to
+/etc/ppp/chap-secrets.
+
+4. Edit /etc/ppp/pppoe.conf
+-----------------------------
+
+The file /etc/ppp/pppoe.conf contains configuration information for the
+ADSL connection. You need to edit the following items:
+
+- Change ETH=eth1 to the correct Ethernet device for your modem.
+- Change USER=bxxxnxnx@sympatico.ca to your proper ADSL user-ID.
+
+Don't edit any of the other settings unless you're an expert.
+
+5. Set up DNS
+-------------
+
+If you are using DNS servers supplied by your ISP, edit the file
+/etc/resolv.conf to contain these lines:
+
+ nameserver ip_addr_of_first_dns_server
+ nameserver ip_addr_of_second_dns_server
+
+For example:
+
+ nameserver 204.101.251.1
+ nameserver 204.101.251.2
+
+
+6. Firewall your machine
+------------------------
+
+MAKE SURE YOU FIREWALL YOUR MACHINE. A sample firewall script is given
+in the shell script "firewall" To install the script:
+
+a) Copy it to /etc/rc.d/init.d/firewall
+b) Type: chkconfig firewall on
+c) Start the firewall: sh /etc/rc.d/init.d/firewall start
+
+(The above procedure works ONLY on Red Hat-like systems.)
+
+You may want to tweak the script somewhat.
+
+7. Bring up the connection at boot time
+---------------------------------------
+
+On a Red Hat system, the installation procedure should have installed
+a script called /etc/rc.d/init.d/adsl. To bring up the connection
+at boot time, just type this command as root:
+
+ chkconfig --add adsl
+
+On non-Red-Hat systems, add this line to the end
+of /etc/rc.d/rc.local:
+
+ /usr/sbin/adsl-start
+
+8. Configure LAN Hosts
+----------------------
+
+If you have a LAN behind the firewall, you have to lower the TCP
+maximum segment size from the normal 1460 to 1452 (or better, 1412.)
+You have two options: Either set the MTU of all the interfaces on
+other hosts on the LAN to 1452, or use the "-m 1412" option to pppoe.
+The "-m" option for pppoe is far simpler and makes it easier to add
+hosts to the LAN, but consumes some extra CPU time.
+
+If you want to manually configure the LAN hosts, here's how:
+
+In Linux, use: "ifconfig eth0 mtu 1452". For best results, put this
+in an /etc/rc.d/rc.local script.
+
+For Windows, machines, see http://lan.cns.ksu.edu/OS/WIN95/slip95.htm.
+Set the MaxMTU to 1452.
+
+9. Commands to control the ADSL link
+------------------------------------
+
+As root, bring up the link by typing: adsl-start
+As root, bring down the link by typing: adsl-stop
+
+That's it!
+
+--
+David F. Skoll <dfs@roaringpenguin.com> | Roaring Penguin Software Inc.
+http://www.roaringpenguin.com | Linux and UNIX Specialists
+
+PROBLEMS! DAVE, IT DOESN'T WORK!
+---------------------------------
+
+Here are some problems PPPoE users have encountered.
+
+-----------------------------------------------------------------------------
+A) Can't see the Ethernet interface
+
+Well, I can't really help you here. To use these instructions, you must
+have Linux working to the point where it recognizes your Ethernet card.
+If you type "ifconfig ethx" and you get back a HWAddr value, your Ethernet
+card is probably OK. But I really can't help with hardware configuration
+issues.
+
+-----------------------------------------------------------------------------
+B) Connection seems to come up, but I can't browse the web or ping anything
+
+You probably don't have DNS set up. See step 6.
+
+-----------------------------------------------------------------------------
+C) Can't compile PPPoE
+
+I have only tested compilation on 2.2-kernel machines. Make sure you have
+"make", the C compiler and all development header files installed.
+
+-----------------------------------------------------------------------------
+D) pppd complains about (i) "unknown option pty" or (ii) "pty option precludes
+ specifying device name"
+
+(i) Your pppd is too old. You need at least 2.3.7.
+(ii) Your /etc/ppp/options file is not empty. Empty it!
+
+-----------------------------------------------------------------------------
+E) pppoe dies with the log message "Message too long"
+
+You set the MTU of the Ethernet interface connected to the ADSL modem
+to less than 1500. Don't do that.
+
+-----------------------------------------------------------------------------
+F) Internal hosts can't see the Internet
+
+Do you have masquerading set up? I can't help you in great detail, but
+see the IPCHAINS-HOWTO and the IP-Masquerade mini-HOWTO.
+
+-----------------------------------------------------------------------------
+G) Authentication fails
+
+Make sure you have the right secret in /etc/ppp/pap-secrets. Your ISP
+may be using CHAP; it won't hurt to copy the line to /etc/ppp/chap-secrets.
+
+Also, MAKE SURE that /etc/ppp/options is EMPTY. The "adsl-connect" script
+supplies all required options on the command line; additional options
+in /etc/ppp/options may mess things up.
+
+-----------------------------------------------------------------------------
+H) VPN software does not work
+
+If you are using VPN software on a Windows or Linux machine with another
+Linux machine running PPPoE as the gateway, you MUST NOT use the "-m" option
+to pppoe. This alters IP packets, which will break any VPN which uses IPSec.
+In /etc/ppp/pppoe.conf, set CLAMPMSS to "no". You'll also have to reduce
+the MTU on the hosts behind the gateway to 1452.
+
+-----------------------------------------------------------------------------
+I) I can browse some web sites just fine, but others stall forever.
+
+There is probably a buggy router or firewall between you and the Web server.
+One possible workaround: In /etc/ppp/pppoe.conf, find the line which reads:
+
+ CLAMPMSS=1412
+
+Try lowering the 1412 until it works (go down in steps of 100 or so.) Each
+time you lower the value, you have to restart your connection like this:
+
+ adsl-stop; adsl-start
+
+This should work around buggy routers which do not support Path MTU discovery.
+
+-----------------------------------------------------------------------------
+J) Whenever I connect using ADSL, my internal LAN no longer sees the gateway
+
+You are more than likely running a 2.0.X Linux kernel. To solve this
+problem, give the Ethernet card connected to the DSL modem a fake IP
+address. For example, if eth0 is your internal LAN card and eth1 goes to
+the DSL modem, do something like this:
+
+ ifconfig eth1 10.0.0.1 netmask 255.255.255.0
+
+(You may have to choose a different IP address; experiment.)
+-----------------------------------------------------------------------------
+K) How can I run a script every time I connect and get a new IP address?
+
+Put the script in /etc/ppp/ip-up. See the pppd(8) man page.
+-----------------------------------------------------------------------------
+L) Nothing works!
+
+You may need to put your Ethernet card in half-duplex, 10Mb/s mode to
+work with the DSL modem. You may have to run a DOS program to do this,
+or pass special parameters to the Linux driver.
+
+Some providers object to attempts to set the MRU or MTU. Try removing
+"mtu 1492 mru 1492" from PPP_STD_OPTIONS in the adsl-connect script.
+This problem has been seen with an ISP in Hong Kong.
+
+Your DSL provider may be using non-standard PPPoE frames or require
+something special in the Service-Name field. If you have two computers,
+you can try sniffing out these values with the "pppoe-sniff" program.
+Type "man pppoe-sniff" for details. If you don't have two computers,
+you'll have to ask your DSL provider if it uses non-standard PPPoE frames
+or special Service-Name fields. Good luck getting an answer...
+
+If pppoe-sniff indicates that nothing is amiss, make sure the Ethernet
+card associated with the ADSL modem does NOT have a valid IP address.
+(NOTE: For 2.0 kernels, you may have to give it a fake IP address
+which is not on your internal subnet. Something like 192.168.42.42
+might work if you are not using 192.168.42.*)
+
+If you are using synchronous PPP on a slow machine, try switching to
+asynchronous PPP.
+
+Make sure no entries in the routing table go through the Ethernet card
+connected to the ADSL modem. You might want to add these lines in
+adsl-connect:
+
+ ifconfig ethx down
+ ifconfig ethx up mtu 1500
+
+which should reset things to sane values.
+
+#######################################################################
+# WHEN ALL ELSE FAILS: #
+#######################################################################
+
+If you are completely unable to connect, run the adsl-start script in
+debugging mode. If you are using bash as your shell (if you don't
+know what your shell is, it's probably bash), type this:
+
+ DEBUG=1 adsl-start
+
+In tcsh or csh, use:
+
+ setenv DEBUG 1; adsl-start
+
+Then follow the instructions to mail the debugging file to me. PLEASE
+DON'T DO THIS until you have exhausted all other avenues; rp-pppoe is
+free software and it costs me time and money to help people with
+problems. While I don't mind doing this, I do mind it if you don't
+make an effort to fix the problem yourself first.
+
+WARNING: If you run adsl-start in debugging mode and you manage to
+connect, your connection will be extremely slow and huge amounts of
+data will quickly fill your /tmp directory. Do not use debugging mode
+unless you really cannot get your connection to work.
+
+Be aware that debugging mode produces hex dumps which potentially reveal
+your user name and password. If the debugging output includes packets
+labeled "PPPOE Session", you may wish to remove these packets from the
+dump before mailing it to me.
diff --git a/mdk-stage1/rp-pppoe/doc/KERNEL-MODE-PPPOE b/mdk-stage1/rp-pppoe/doc/KERNEL-MODE-PPPOE
new file mode 100644
index 000000000..454c4b870
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/doc/KERNEL-MODE-PPPOE
@@ -0,0 +1,39 @@
+RP-PPPoE now supports kernel-mode PPPoE on Linux kernels 2.4.x. However,
+the default "./go" build procedure does not make kernel-mode support.
+
+Here's what you need to do:
+
+1) Download Michal Ostrowski's patched version of pppd which supports
+a PPPoE plugin. The latest version as of this writing is
+at http://www.math.uwaterloo.ca/~mostrows/ in
+http://www.math.uwaterloo.ca/~mostrows/ppp-2.4.0-pppoe4.tgz. It is
+also mirrored at http://www.roaringpenguin.com/pppoe/
+
+2) Unpack that version of pppd and build and install it.
+
+3) In the rp-pppoe directory, change to src/ and type:
+
+ ./configure --enable-plugin=/path/to/ppp-tree
+
+Here, /path/to/ppp-tree is where you unpacked the pppd software. It
+should be the directory named ppp-2.4.0.pppoe
+
+4) Type make; make install
+
+5) Edit /etc/ppp/pppoe.conf to include this line:
+
+ LINUX_PLUGIN=/etc/ppp/plugins/rp-pppoe.so
+
+6) Make sure your kernel was built with support for PPP, PPPOX and that
+all modules are locatable by modprobe. Make sure you have a /dev/ppp
+device:
+
+ mknod /dev/ppp c 108 0
+
+After that, adsl-start should use kernel-mode PPPoE.
+
+This code is experimental and unsupported. Use at your own risk.
+
+--
+David F. Skoll <dfs@roaringpenguin.com>
+
diff --git a/mdk-stage1/rp-pppoe/doc/LICENSE b/mdk-stage1/rp-pppoe/doc/LICENSE
new file mode 100644
index 000000000..9ed341535
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/doc/LICENSE
@@ -0,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ Appendix: How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ 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.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/mdk-stage1/rp-pppoe/doc/PROBLEMS b/mdk-stage1/rp-pppoe/doc/PROBLEMS
new file mode 100644
index 000000000..f0b7d7d59
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/doc/PROBLEMS
@@ -0,0 +1,3 @@
+Problems?
+
+See the last section of HOW-TO-CONNECT.
diff --git a/mdk-stage1/rp-pppoe/go b/mdk-stage1/rp-pppoe/go
new file mode 100755
index 000000000..0bc2da42d
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/go
@@ -0,0 +1,43 @@
+#!/bin/sh
+#***********************************************************************
+#
+# go
+#
+# Quick-start shell script to set up ADSL
+#
+# Copyright (C) 2000 Roaring Penguin Software Inc.
+#
+# $Id: go 195724 2001-06-11 13:49:39Z gc $
+#***********************************************************************
+
+# Figure out directory of script
+MYDIR=`dirname $0`
+cd $MYDIR/src
+
+echo "Running ./configure..."
+./configure
+if [ "$?" != 0 ] ; then
+ echo "Oops! It looks like ./configure failed."
+ exit 1
+fi
+
+echo "Running make..."
+make
+if [ "$?" != 0 ] ; then
+ echo "Oops! It looks like make failed."
+ exit 1
+fi
+
+echo "Running make install..."
+make install
+
+if [ "$?" != 0 ] ; then
+ echo "Oops! It looks like make install failed."
+ exit 1
+fi
+
+for i in a a a a a a a a a a a a a a a a a a a a a a a a a a a a ; do
+ echo ""
+done
+
+sh ../scripts/adsl-setup
diff --git a/mdk-stage1/rp-pppoe/go-gui b/mdk-stage1/rp-pppoe/go-gui
new file mode 100755
index 000000000..37e160217
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/go-gui
@@ -0,0 +1,92 @@
+#!/bin/sh
+#***********************************************************************
+#
+# go-gui
+#
+# Quick-start shell script to set up ADSL and GUI wrapper
+#
+# Copyright (C) 2000 Roaring Penguin Software Inc.
+#
+# $Id: go-gui 195724 2001-06-11 13:49:39Z gc $
+#***********************************************************************
+
+# GUI only works on Linux
+if test "`uname`" != "Linux" ; then
+ echo "Sorry, the GUI only works on Linux."
+ exit 1
+fi
+
+# Figure out directory of script
+MYDIR=`dirname $0`
+cd $MYDIR/src
+
+echo "Running ./configure..."
+./configure
+if [ "$?" != 0 ] ; then
+ echo "Oops! It looks like ./configure failed."
+ exit 1
+fi
+
+echo "Running make..."
+make
+if [ "$?" != 0 ] ; then
+ echo "Oops! It looks like make failed."
+ exit 1
+fi
+
+echo "Running make install..."
+make install
+
+if [ "$?" != 0 ] ; then
+ echo "Oops! It looks like make install failed."
+ exit 1
+fi
+
+echo "Building GUI wrapper..."
+cd ../gui
+make
+if [ "$?" != 0 ] ; then
+ echo "Oops! It looks like make failed."
+ exit 1
+fi
+
+echo "Installing GUI..."
+make install
+
+if [ "$?" != 0 ] ; then
+ echo "Oops! It looks like make install failed."
+ exit 1
+fi
+
+# Install entry in KDE menu
+if test -n "$KDEDIR" ; then
+ echo "Installing KDE menu entry Internet : TkPPPoE..."
+ mkdir -p "$KDEDIR/share/applnk/Internet"
+ cat <<EOF > "$KDEDIR/share/applnk/Internet/tkpppoe.kdelnk"
+# KDE Config File
+[KDE Desktop Entry]
+Name=TkPPPoE
+Comment=Start/Stop ADSL connections
+Exec=tkpppoe
+Terminal=0
+Type=Application
+EOF
+fi
+
+# Install entry in GNOME menus
+GNOMEDIR=`gnome-config --datadir 2>/dev/null`
+if test -n "$GNOMEDIR" ; then
+ echo "Installing GNOME menu entry Internet : TkPPPoE..."
+ mkdir -p "$GNOMEDIR/gnome/apps/Internet"
+cat <<EOF > "$GNOMEDIR/gnome/apps/Internet/tkpppoe.desktop"
+[Desktop Entry]
+Name=TkPPPoE
+Comment=Start/Stop ADSL connections
+Exec=tkpppoe
+Terminal=0
+Type=Application
+EOF
+fi
+echo "Running GUI configuration tool..."
+tkpppoe &
+exit 0
diff --git a/mdk-stage1/rp-pppoe/gui/Makefile.in b/mdk-stage1/rp-pppoe/gui/Makefile.in
new file mode 100644
index 000000000..a4f95ae5a
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/gui/Makefile.in
@@ -0,0 +1,64 @@
+# @configure_input@
+#***********************************************************************
+#
+# Makefile
+#
+# Makefile for GUI for Roaring Penguin's Linux user-space PPPoE client.
+#
+# Copyright (C) 2001 Roaring Penguin Software Inc.
+#
+# This program may be distributed according to the terms of the GNU
+# General Public License, version 2 or (at your option) any later version.
+#
+# $Id: Makefile.in 195724 2001-06-11 13:49:39Z gc $
+#***********************************************************************
+DEFINES=
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+mandir=@mandir@
+install=@INSTALL@
+install_dir=@INSTALL@ -d
+sbindir=@sbindir@
+bindir=@bindir@
+
+ADSL_START_PATH=@sbindir@/adsl-start
+ADSL_STOP_PATH=@sbindir@/adsl-stop
+ADSL_STATUS_PATH=@sbindir@/adsl-status
+
+PATHS='-DADSL_START_PATH="$(ADSL_START_PATH)"' '-DADSL_STOP_PATH="$(ADSL_STOP_PATH)"' '-DADSL_STATUS_PATH="$(ADSL_STATUS_PATH)"'
+
+CFLAGS= @CFLAGS@ $(DEFINES) $(PATHS)
+
+all: pppoe-wrapper
+ @echo ""
+ @echo "Type 'make install' as root to install the software."
+
+pppoe-wrapper: wrapper.o
+ @CC@ -o pppoe-wrapper wrapper.o
+
+wrapper.o: wrapper.c
+ @CC@ $(CFLAGS) -c -o wrapper.o wrapper.c
+
+install: all
+ -mkdir -p $(RPM_INSTALL_ROOT)$(sbindir)
+ -mkdir -p $(RPM_INSTALL_ROOT)$(bindir)
+ -mkdir -p $(RPM_INSTALL_ROOT)/etc/ppp/rp-pppoe-gui
+ $(install) -m 4755 -s pppoe-wrapper $(RPM_INSTALL_ROOT)$(sbindir)
+ $(install) -m 755 tkpppoe $(RPM_INSTALL_ROOT)$(bindir)
+ -mkdir -p $(RPM_INSTALL_ROOT)$(mandir)/man1
+ $(install) -m 644 pppoe-wrapper.1 $(RPM_INSTALL_ROOT)$(mandir)/man1
+ $(install) -m 644 tkpppoe.1 $(RPM_INSTALL_ROOT)$(mandir)/man1
+ -mkdir -p $(RPM_INSTALL_ROOT)/usr/share/rp-pppoe-gui
+ for i in tkpppoe.html mainwin-busy.png mainwin-nonroot.png mainwin.png props-advanced.png props-basic.png props-nic.png props-options.png ; do \
+ $(install) -m 644 html/$$i $(RPM_INSTALL_ROOT)/usr/share/rp-pppoe-gui; \
+ done
+
+clean:
+ rm -f *.o *~ pppoe-wrapper
+
+distclean: clean
+ rm -f Makefile tkpppoe
+
+.PHONY: clean
+
+.PHONY: distclean
diff --git a/mdk-stage1/rp-pppoe/gui/html/tkpppoe.html b/mdk-stage1/rp-pppoe/gui/html/tkpppoe.html
new file mode 100644
index 000000000..51aadb895
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/gui/html/tkpppoe.html
@@ -0,0 +1,181 @@
+<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+ <meta name="GENERATOR" content="Mozilla/4.76 [en] (X11; U; Linux 2.2.14-5.0 i686) [Netscape]">
+ <title>TkPPPoE Manual</title>
+</head>
+<body text="#000000" bgcolor="#FFFFFF" link="#0000EF" vlink="#59188E" alink="#FF0000">
+
+<center>
+<h1>tkpppoe - A GUI for managing PPPoE Connections</h1>
+</center>
+
+<h1>Introduction</h1>
+
+TkPPPoE is a graphical user interface for managing PPPoE connections. It
+performs two different functions:
+<ul>
+<li>TkPPPoE lets you <em>define</em> connection properties. This step must
+be done as root.
+<li>TkPPPoE lets you <em>start and stop</em> PPPoE connections. This step
+may be done as a normal user, depending on how you configured the connection.
+</ul>
+
+<h1>Defining Connections</h1>
+
+To define connections, start TkPPPoE as root. You can do this from
+a terminal by typing <code>tkpppoe</code>, or from the KDE or GNOME menus
+by selecting <b>Internet : TkPPPoE</b>. The following window pops up:
+
+<p>
+<center><img src="mainwin.png" width="361" height="73" alt="Main Window">
+</center>
+
+<p>
+Because you have not yet defined any connections, the connection property
+window also pops up:
+
+<p>
+<center><img src="props-basic.png" width="440" height="259" alt="Connection Properties - Basic">
+</center>
+
+You can pop up the connection property window at any time by clicking
+<b>New Connection...</b> You can edit the properties of an existing
+connection by selecting the connection's name and clicking
+<b>Properties...</b>
+<h4>Basic Information</h4>
+
+Let's fill in the basic information:
+<ul>
+<li>For <b>Connection Name</b>, enter a unique name for this connection. It
+can be anything you like, but must contain only letters, numbers, underscores
+or dashes. In particular, it can't contain spaces. If you have only one
+PPPoE connection, a good name is <b>Default</b>.
+<li>For <b>User Name</b>, enter the user name supplied by your ISP. Enter
+only the user name; do not enter an "@isp.com" part.
+<li>For <b>Network</b>, you may have to enter your ISP's domain name.
+(For example, <b>isp.com</b>.) Some DSL providers add this to your user
+name; others do not. You may have to experiment a bit. The two most likely
+choices are your ISP's domain name, or blank. Try both.
+<li>For <b>Password</b>, enter the password your ISP provided you with.
+</ul>
+
+<h4>NIC and DNS</h4>
+Click on the <b>NIC and DNS</b> tab:
+
+<p>
+<center><img src="props-nic.png" width="440" height="259" alt="Connection Properties - NIC and DNS"></center>
+<p>
+<ul>
+<li>For <b>Ethernet Interface</b>, enter the Ethernet interface connected
+to the DSL modem. It is something like <b>eth0</b> or <b>eth1</b>. Click
+on <b>...</b> to browse a list of detected Ethernet interfaces.
+<li>For <b>DNS Setup</b>, you have three options:
+<ol>
+<li><b>From Server</b> means that the system will obtain DNS information from
+the PPPoE server. This is the correct choice for most ISPs.
+<li><b>Specify</b> means that you will enter the IP addresses of your DNS
+servers manually. In this case, enter the addresses in the <b>Primary DNS</b>
+and <b>Secondary DNS</b> entries.
+<li><b>Do not Adjust</b> means that you want RP-PPPoE to leave your
+DNS setup alone. Use this if you are running your own caching DNS server
+or know that you don't want the DNS setup touched.
+</ol>
+</ul>
+
+<h4>Options</h4>
+Click on the <b>Options</b> tab:
+
+<p>
+<center><img src="props-options.png" width="440" height="259" alt="Connection Properties - Options"></center>
+<p>
+<ul>
+<li>If you want ordinary users to be able to start and stop this connection,
+enable <b>Allow use by non-root users</b>. If you do not enable this,
+non-root users will be able to monitor the connection, but not control it.
+<li>If you want to use synchronous PPP, enable <b>Use synchronous PPP</b>.
+This is recommended as it conserves CPU usage, but may not work on some
+(misconfigured) Linux kernels.
+<li>For <b>Firewalling</b>, you have three options:
+<ol>
+<li><b>Stand-Alone</b> installs a simple firewall ruleset for stand-alone
+machines. Use this if you have only a single computer connected to the DSL
+modem.
+<li><b>Masquerading</b> installs a simple firewall ruleset for using
+your Linux computer as an Internet sharing device. If you have two Ethernet
+cards, you can connect one card to the DSL modem and the other to an
+internal LAN. The masquerading firewall ruleset lets internal machines
+share the DSL connection.
+<li><b>None</b>. If you already have your own firewall rules, or you wish
+to run servers on your machine, select None. This is <em>not recommended</em>
+unless you take steps to secure your machine, and know what you are doing.
+</ol>
+</ul>
+
+<h4>Advanced</h4>
+Click on the <b>Advanced</b> tab:
+
+<p>
+<center><img src="props-advanced.png" width="440" height="259" alt="Connection Properties - Advanced"></center>
+<p>
+
+In most cases, you can leave <b>AC-Name</b> and <b>Service-Name</b> blank.
+In some cases, your ISP may require you to enter information in these fields;
+contact your ISP for more information.
+
+<h1>Controlling Connections</h1>
+For these examples, run <code>tkpppoe</code> as a normal user (not root).
+The main window appears like this:
+
+<p>
+<center><img src="mainwin-nonroot.png" width="206" height="73" alt="Main Window - Non-root">
+</center>
+<p>
+<ul>
+<li>To start a connection, press <b>Start</b>. The two LEDs flash red
+and grey. If the connection is established, they turn green.
+<li>To stop a connection, press <b>Stop</b>.
+</ul>
+
+<p>The two rectangles to the right of the connection name are the
+<em>status LEDs</em>. The top LED corresponds to transmitted data and
+the bottom to received. The LEDs are colored as follows:
+<ul>
+<li>Grey -- connection is not established.
+<li>Flashing red/grey -- connection is being started.
+<li>Green -- connection is up, but idle.
+<li>Yellow -- connection is up and data is being sent or received.
+<li>Red -- connection has been lost, but the system is trying to reestablish it.
+</ul>
+
+<p>
+When a connection is established, two graphs appear:
+
+<p>
+<center><img src="mainwin-busy.png" width="206" height="73" alt="Main Window - Established Connection">
+</center>
+<p>
+
+The left (red) graph shows transmitted packets and the average
+transmission speed (in bits per second) over the sample time. The
+right (green) graph shows received packets.
+
+<h1>Miscellaneous Information</h1>
+<ul>
+<li>The connection menu has an entry called <b>User's Manual</b> which
+will pop up this user manual (if you have Netscape installed.)
+<li>You can define multiple PPPoE connections, but you should not use
+more than one simultaneuously unless you feel comfortable editing scripts
+and setting up routing tables. By default, TkPPPoE tries to add a default
+route for connections. This does not work well with multiple simultaneous
+connections.
+<li>If you exit from TkPPPoE, connections which are up remain up. You
+have to explicitly stop connections if you want them terminated.
+</ul>
+<hr>
+<a href="http://www.roaringpenguin.com/pppoe/">TkPPPoE</a> is Copyright 2001 by <a href="http://www.roaringpenguin.com">Roaring Penguin Software Inc</a> and
+is licensed under the GNU General Public License.
+<p>Screenshots show TkPPPoE running under the <a href="http://www.xfce.org">XFCE</a> desktop, a lightweight UNIX and Linux desktop.
+</body>
+</html>
diff --git a/mdk-stage1/rp-pppoe/gui/pppoe-wrapper.1 b/mdk-stage1/rp-pppoe/gui/pppoe-wrapper.1
new file mode 100644
index 000000000..8ffb8704e
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/gui/pppoe-wrapper.1
@@ -0,0 +1,45 @@
+.\" $Id: pppoe-wrapper.1 195724 2001-06-11 13:49:39Z gc $
+.TH PPPOE-WRAPPER 1 "26 February 2001"
+.UC 4
+.SH NAME
+pppoe-wrapper \- SUID wrapper for starting and stopping PPPoE connections.
+.SH SYNOPSIS
+.B pppoe-wrapper start linkname
+.P
+.B pppoe-wrapper stop linkname
+.P
+.B pppoe-wrapper status linkname
+
+.SH DESCRIPTION
+\fBpppoe-wrapper\fR is a small SUID program which allows non-root users
+to start and stop PPPoE links. It operates as follows:
+
+.TP
+.B o
+First, \fIlinkname\fR is sanity-checked. Too-long names and names containing
+illegal characters are rejected.
+
+.TP
+.B o
+Second, \fBpppoe-wrapper\fR opens the file \fB/etc/ppp/rp-pppoe-gui/\fR\fIlinkname\fR for reading. If that file does not contain the line:
+.nf
+
+ NONROOT=OK
+
+.fi
+then \fBpppoe-wrapper\fR fails.
+
+.TP
+.B o
+Otherwise, \fBpppoe-wrapper\fR runs \fBadsl-start\fR, \fBadsl-stop\fR or
+\fBadsl-status\fR with the above filename as its single argument.
+
+.SH AUTHOR
+\fBpppoe-wrapper\fR was written by David F. Skoll <dfs@roaringpenguin.com>.
+
+The \fBpppoe\fR home page is \fIhttp://www.roaringpenguin.com/pppoe/\fR.
+
+.SH SEE ALSO
+adsl-start(8), adsl-stop(8), adsl-status(8), tkpppoe(1)
+
+
diff --git a/mdk-stage1/rp-pppoe/gui/tkpppoe.1 b/mdk-stage1/rp-pppoe/gui/tkpppoe.1
new file mode 100644
index 000000000..6239b7df5
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/gui/tkpppoe.1
@@ -0,0 +1,36 @@
+.\" $Id: tkpppoe.1 195724 2001-06-11 13:49:39Z gc $
+.TH TKPPPOE 1 "26 February 2001"
+.UC 4
+.SH NAME
+tkpppoe \- Graphical interface for controlling rp-pppoe
+.SH SYNOPSIS
+.B tkpppoe
+
+.SH DESCRIPTION
+\fBtkpppoe\fR is a graphical program for controlling PPPoE links.
+It works with the RP-PPPoE package and has its own HTML manual.
+
+.SH FILES
+
+.TP
+.B /etc/ppp/rp-pppoe-gui/connection-info
+Contains connection information. This file is not human-editable.
+
+.TP
+.B /etc/ppp/rp-pppoe-gui/passwd
+Contains passwords for each connection. This file is not human-editable.
+
+.TP
+.B /etc/ppp/rp-pppoe-gui/conf.*
+These configuration files are used by \fBadsl-start\fR. They are
+generated anew by \fBtkpppoe\fR each time a change is made to a
+connection's properties.
+
+.SH AUTHOR
+\fBtkpppoe\fR was written by David F. Skoll <dfs@roaringpenguin.com>.
+
+The \fBpppoe\fR home page is \fIhttp://www.roaringpenguin.com/pppoe/\fR.
+
+.SH SEE ALSO
+adsl-start(8), adsl-stop(8), pppoe-wrapper(8).
+
diff --git a/mdk-stage1/rp-pppoe/gui/tkpppoe.in b/mdk-stage1/rp-pppoe/gui/tkpppoe.in
new file mode 100755
index 000000000..9fb6d75ca
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/gui/tkpppoe.in
@@ -0,0 +1,2891 @@
+#!/bin/sh
+# -*-Mode: TCL;-*-
+
+#--------------------------------------------------------------
+# tkpppoe
+#
+# A graphical front-end for configuring and using rp-pppoe.
+#
+# Copyright (C) 2001 by Roaring Penguin Software Inc.
+# This file may be distributed under the terms of the GNU General Public
+# License, Version 2, or (at your option) any later version.
+#
+# The "Roaring Penguin" logo is a trademark of Roaring Penguin Software Inc.
+#
+# http://www.roaringpenguin.com
+#
+#--------------------------------------------------------------
+
+# $Id: tkpppoe.in 195724 2001-06-11 13:49:39Z gc $
+
+# the next line restarts using wish \
+umask 022; \
+exec wish "$0" "$@" || clear; echo "*****"; echo "Cannot find 'wish' -- you need Tcl/Tk installed to run this program"; exit 1
+
+# Set app name
+tk appname TkPPPoE
+
+# Set this to one if you want to allow multiple instances of TkPPPoE
+set AllowMultipleInstances 0
+
+# Check for other instances
+if {"[tk appname]" != "TkPPPoE"} {
+ # Must be another instance running...
+ if {!$AllowMultipleInstances} {
+ send TkPPPoE AnotherInstance
+ exit 0
+ }
+}
+
+# Location of config directory
+set ConfigDir /etc/ppp/rp-pppoe-gui
+
+# Are we running as root?
+set Admin 0
+
+# Location of connection info file
+set ConnectionInfoFile [file join $ConfigDir connection-info]
+
+# Location of password file
+set PasswordFile [file join $ConfigDir passwd]
+
+# Location of "already run" file
+set AlreadyRunFile [file join $ConfigDir gui-already-run]
+
+# Connection information
+set ConnectionInfo {}
+
+# Connection options
+set OPTS(nonroot) 0
+set OPTS(sync) 1
+
+# Location of wrapper
+set Wrapper "@WRAPPER@"
+
+# Timer token for UpdateConnectionState
+set UpdateToken {}
+
+# Update interval in milliseconds
+set UpdateInterval 500
+
+# Packet counters for signalling activity
+set Packets(in) 0
+set Packets(out) 0
+set Bytes(in) 0
+set Bytes(out) 0
+set MeasureTime 0
+
+# Set up some options to make it look better
+option add *Button.borderWidth 1
+option add *Button.Pad 1
+option add *Menubutton.borderWidth 1
+option add *Menubutton.Pad 1
+option add *Entry.Background white
+
+# Array holding help strings for windows
+array set HelpData {}
+
+bind HelpWin <Enter> "HelpWindowEntered %W"
+bind HelpWin <Leave> "HelpWindowLeft %W"
+
+proc AnotherInstance {} {
+ wm deiconify .
+ raise .
+}
+
+#***********************************************************************
+# %PROCEDURE: HelpWindowEntered
+# %ARGUMENTS:
+# w -- window
+# %RETURNS:
+# Nothing
+# %DESCRIPTION:
+# Looks for procedure in HelpData; evals it if found.
+#***********************************************************************
+proc HelpWindowEntered { w } {
+ global HelpData
+ if {[info exists HelpData($w)]} {
+ set cmd "$HelpData($w) Enter"
+ uplevel #0 $cmd
+ }
+}
+
+#***********************************************************************
+# %PROCEDURE: HelpWindowLeft
+# %ARGUMENTS:
+# w -- window
+# %RETURNS:
+# Nothing
+# %DESCRIPTION:
+# Looks for procedure in HelpData; evals it if found.
+#***********************************************************************
+proc HelpWindowLeft { w } {
+ global HelpData
+ if {[info exists HelpData($w)]} {
+ set cmd "$HelpData($w) Leave"
+ uplevel #0 $cmd
+ }
+}
+
+#***********************************************************************
+# %PROCEDURE: RegisterHelpWindow
+# %ARGUMENTS:
+# w -- window we need help about
+# helptext -- the help text
+# win -- window in which to put help messages
+# %RETURNS:
+# Nothing
+# %DESCRIPTION:
+# Sets things up so help text appears in "$win" when mouse enters "$w"
+#***********************************************************************
+proc RegisterHelpWindow {w helptext win} {
+ global HelpData
+ set tags [bindtags $w]
+ if {[lsearch -exact $tags HelpWin] < 0} {
+ lappend tags HelpWin
+ bindtags $w $tags
+ }
+ set HelpData($w) [list HelpInTextWin $helptext $win]
+}
+
+#***********************************************************************
+# %PROCEDURE: HelpInTextWin
+# %ARGUMENTS:
+# text -- help text
+# tw -- window in which to write text
+# what -- one of "Enter" or "Leave"
+# %RETURNS:
+# Nothing
+# %DESCRIPTION:
+# Clears out $tw; if $what is "Enter", puts $text in $tw.
+#***********************************************************************
+proc HelpInTextWin {text tw what} {
+ $tw configure -state normal
+ $tw delete 1.0 end
+ if {"$what" == "Enter"} {
+ $tw insert end $text
+ }
+ $tw configure -state disabled
+}
+
+
+#***********************************************************************
+# %PROCEDURE: drawLogo
+# %ARGUMENTS:
+# c -- canvas to draw logo in
+# bg -- background color of canvas
+# pencolor -- color of the word "Penguin"
+# %RETURNS:
+# Nothing
+# %DESCRIPTION:
+# Draws Roaring Penguin logo in a Tcl canvas
+#***********************************************************************
+proc drawLogo { c bg {pengcolor #6699cc} } {
+ $c create polygon 372.249 5.182 361.23 5.519 \
+ 346.164 8.892 316.482 20.023 305.463 17.774 296.468 \
+ 19.573 288.935 24.97 282.864 33.177 267.348 55.102 \
+ 254.531 77.814 236.204 125.26 225.635 174.844 \
+ 221.026 226.113 213.605 228.025 208.658 232.634 \
+ 225.523 240.28 250.708 243.316 282.752 242.416 \
+ 320.079 238.818 330.985 193.17 338.181 146.735 \
+ 338.743 99.963 335.483 76.577 329.524 53.191 345.602 \
+ 48.131 353.135 45.995 359.768 41.048 342.679 43.184 \
+ 324.689 40.036 334.583 28.905 348.3 18.674 372.249 \
+ 5.182 -fill #000000 -outline {} -width 1 -tags logo
+
+ $c create line 372.249 5.182 361.23 5.519 \
+ 346.164 8.892 316.482 20.023 305.463 17.774 296.468 \
+ 19.573 288.935 24.97 282.864 33.177 267.348 55.102 \
+ 254.531 77.814 236.204 125.26 225.635 174.844 \
+ 221.026 226.113 213.605 228.025 208.658 232.634 \
+ 225.523 240.28 250.708 243.316 282.752 242.416 \
+ 320.079 238.818 330.985 193.17 338.181 146.735 \
+ 338.743 99.963 335.483 76.577 329.524 53.191 345.602 \
+ 48.131 353.135 45.995 359.768 41.048 342.679 43.184 \
+ 324.689 40.036 334.583 28.905 348.3 18.674 372.249 \
+ 5.182 -tags logo
+
+ $c create polygon 298.605 109.632 290.734 \
+ 159.328 282.752 182.939 271.958 205.65 262.851 \
+ 171.133 263.75 138.752 264.537 164.5 271.958 192.833 \
+ 286.687 157.192 298.605 109.632 -fill #ffffff \
+ -outline {} -width 1 -tags logo
+
+ $c create line 298.605 109.632 290.734 159.328 \
+ 282.752 182.939 271.958 205.65 262.851 171.133 \
+ 263.75 138.752 264.537 164.5 271.958 192.833 286.687 \
+ 157.192 298.605 109.632 -tags logo
+
+ $c create polygon 312.546 30.592 315.132 35.876 \
+ 310.747 39.586 308.161 34.414 312.546 30.592 -fill \
+ #ffffff -outline {} -width 1 -tags logo
+
+ $c create line 312.546 30.592 315.132 35.876 \
+ 310.747 39.586 308.161 34.414 312.546 30.592 -tags logo
+
+ $c create polygon 328.624 54.427 322.665 58.7 \
+ 314.458 61.286 289.16 59.15 284.55 74.665 285.338 \
+ 90.181 303.214 98.951 308.499 106.259 310.523 \
+ 116.378 305.913 130.208 312.771 141.563 308.049 \
+ 167.76 299.729 192.158 279.041 238.593 313.558 \
+ 233.871 327.388 185.75 335.033 139.989 335.82 96.253 \
+ 328.624 54.427 -fill #ffffff -outline {} -width 1 -tags logo
+
+ $c create line 328.624 54.427 322.665 58.7 \
+ 314.458 61.286 289.16 59.15 284.55 74.665 285.338 \
+ 90.181 303.214 98.951 308.499 106.259 310.523 \
+ 116.378 305.913 130.208 312.771 141.563 308.049 \
+ 167.76 299.729 192.158 279.041 238.593 313.558 \
+ 233.871 327.388 185.75 335.033 139.989 335.82 96.253 \
+ 328.624 54.427 -tags logo
+
+ $c create polygon 53.837 185.412 54.399 185.862 \
+ 53.837 188.223 54.399 188.673 53.837 188.673 53.837 \
+ 189.572 53.837 190.472 53.387 191.034 52.938 192.833 \
+ 50.577 195.644 49.677 196.656 49.677 197.105 48.215 \
+ 198.455 47.316 198.904 46.866 198.904 44.505 200.816 \
+ 43.606 200.366 42.594 201.265 42.144 201.715 41.245 \
+ 202.277 40.795 202.727 40.345 202.277 39.783 202.277 \
+ 36.972 203.177 36.522 203.177 36.073 203.177 35.623 \
+ 203.627 34.723 203.627 34.161 203.627 34.161 204.076 \
+ 30.901 204.526 28.54 205.538 26.291 205.088 25.729 \
+ 205.088 24.829 205.088 24.38 204.526 23.93 204.526 \
+ 23.48 204.526 22.918 205.088 22.918 206.437 22.918 \
+ 206.887 22.918 207.337 22.468 207.337 22.468 208.798 \
+ 22.018 209.248 22.018 211.16 22.018 211.609 21.569 \
+ 213.521 21.119 215.769 21.569 216.781 20.669 218.13 \
+ 20.669 219.592 20.669 220.042 20.107 220.941 20.107 \
+ 221.953 20.107 223.752 19.657 225.664 19.208 226.113 \
+ 19.657 227.013 18.308 230.835 17.858 240.167 17.296 \
+ 248.15 17.296 249.05 16.846 250.062 15.947 250.062 \
+ 15.048 250.062 15.048 250.511 12.686 251.86 12.237 \
+ 251.86 11.675 251.411 11.675 250.511 11.675 246.689 \
+ 11.225 245.339 11.225 243.878 10.775 240.617 11.225 \
+ 239.268 11.225 238.818 10.775 238.256 10.325 237.357 \
+ 10.325 236.007 9.876 232.634 9.876 231.735 9.876 \
+ 231.285 9.876 230.835 9.876 230.386 9.876 229.824 \
+ 9.426 229.374 9.426 226.113 9.876 226.113 9.876 \
+ 225.664 9.426 224.202 9.426 223.752 9.426 223.302 \
+ 10.325 221.953 9.426 220.941 9.426 219.592 9.426 \
+ 219.142 9.426 218.58 9.426 217.681 9.426 217.231 \
+ 9.426 216.781 8.864 216.332 8.864 214.42 8.864 \
+ 213.97 8.414 213.521 8.414 210.148 8.414 209.248 \
+ 7.964 207.899 8.414 205.988 8.414 204.526 7.065 \
+ 201.265 7.515 200.816 9.426 201.715 10.325 201.265 \
+ 10.775 200.816 10.775 198.904 11.225 198.005 11.225 \
+ 197.555 10.775 197.555 9.876 196.094 9.426 194.744 \
+ 7.515 194.295 6.615 193.845 6.053 193.845 5.153 \
+ 193.283 3.804 191.484 3.804 190.022 3.804 189.572 \
+ 3.804 189.123 3.242 188.673 3.242 186.762 3.804 \
+ 185.412 4.254 184.85 4.704 184.4 7.964 180.24 10.325 \
+ 178.779 11.225 178.779 12.237 177.879 14.036 176.98 \
+ 15.497 175.968 21.569 173.607 22.918 173.157 23.48 \
+ 173.157 24.38 172.707 24.829 172.707 29.102 171.808 \
+ 29.551 171.808 30.001 171.358 31.35 170.796 31.913 \
+ 171.358 32.362 170.796 39.783 171.358 40.345 170.796 \
+ 42.144 171.358 47.766 174.619 48.778 176.418 49.227 \
+ 176.418 49.677 176.98 50.127 176.98 51.588 178.329 \
+ 52.038 179.228 52.488 180.69 52.038 181.14 52.038 \
+ 181.59 52.488 182.039 52.938 182.039 53.387 182.601 \
+ 53.837 183.051 53.837 183.501 53.837 185.412 -fill \
+ $pengcolor -outline {} -width 1 -tags logo
+
+ $c create polygon 42.594 222.853 43.156 221.953 \
+ 41.694 222.403 39.783 224.202 39.783 224.764 39.783 \
+ 225.214 40.345 225.214 41.245 224.202 41.694 223.752 \
+ 42.594 222.853 -fill $pengcolor -outline {} -width 1 -tags logo
+
+ $c create polygon 58.559 234.096 59.009 234.096 \
+ 59.009 234.546 58.559 234.995 58.559 235.445 57.21 \
+ 236.907 56.648 237.806 52.938 241.067 52.038 241.629 \
+ 52.038 242.079 51.026 242.529 50.577 242.978 50.127 \
+ 242.978 49.227 244.44 45.405 246.239 44.055 246.689 \
+ 43.606 246.689 43.606 247.251 42.144 247.251 41.694 \
+ 247.7 40.795 247.7 38.434 248.15 36.522 248.15 \
+ 35.173 247.7 34.161 246.689 33.711 246.239 32.812 \
+ 244.44 32.362 241.629 32.812 239.718 32.812 239.268 \
+ 33.711 234.995 36.522 229.824 35.623 228.474 35.623 \
+ 227.013 36.522 225.664 37.534 224.202 38.883 222.853 \
+ 41.694 220.492 42.594 219.592 43.156 219.592 43.606 \
+ 219.142 45.405 217.681 45.967 217.681 46.416 217.231 \
+ 48.778 215.769 52.038 214.87 53.387 214.42 54.849 \
+ 214.87 55.299 214.87 56.198 215.769 56.198 217.681 \
+ 56.198 218.58 54.399 221.953 53.837 222.853 53.837 \
+ 223.302 53.387 223.752 50.577 226.113 49.677 226.563 \
+ 47.316 228.474 43.156 230.386 41.245 230.835 40.795 \
+ 230.835 40.345 230.835 39.333 230.835 38.883 230.835 \
+ 38.883 229.824 39.783 229.374 40.795 228.474 41.694 \
+ 228.025 42.594 227.575 45.967 227.013 46.866 226.563 \
+ 50.127 224.764 51.588 223.302 52.488 221.953 52.488 \
+ 220.492 52.488 219.142 51.026 218.13 49.677 218.13 \
+ 48.778 218.13 47.766 219.142 47.316 219.142 47.316 \
+ 219.592 46.866 219.592 45.967 220.941 44.505 221.953 \
+ 44.055 222.403 43.606 222.853 42.594 223.752 41.694 \
+ 225.664 41.245 225.664 41.245 226.113 40.345 226.563 \
+ 39.333 227.575 39.333 228.474 38.434 229.374 36.522 \
+ 233.197 35.623 236.457 35.623 237.357 35.623 238.256 \
+ 35.173 241.067 35.623 242.079 36.522 243.428 37.534 \
+ 243.878 37.984 244.44 38.434 244.89 38.883 244.89 \
+ 39.783 245.339 43.156 245.339 45.967 244.44 49.227 \
+ 242.529 50.127 241.629 50.577 241.067 54.399 238.818 \
+ 54.399 238.256 54.399 237.806 56.198 236.907 58.559 \
+ 234.096 -fill $pengcolor -outline {} -width 1 -tags logo
+
+ $c create polygon 92.289 248.6 92.739 249.05 \
+ 92.289 249.05 91.84 249.05 90.94 248.6 90.378 248.6 \
+ 89.478 247.7 89.029 247.251 88.129 246.689 87.117 \
+ 245.789 85.768 244.89 85.318 244.44 85.768 244.44 \
+ 85.318 242.529 84.756 242.079 84.756 240.617 84.756 \
+ 240.167 84.756 239.718 84.756 239.268 83.857 236.457 \
+ 83.407 234.096 83.407 233.197 83.407 231.735 83.407 \
+ 223.302 83.407 221.391 82.957 220.941 82.508 221.953 \
+ 80.596 226.113 80.146 226.563 80.146 227.013 79.697 \
+ 228.025 79.135 228.474 79.697 228.474 76.324 234.096 \
+ 75.874 234.995 75.424 236.457 74.975 236.457 74.975 \
+ 236.907 74.975 237.357 74.075 239.268 73.513 239.718 \
+ 73.063 240.167 72.613 241.067 72.164 242.529 71.714 \
+ 242.529 71.714 243.878 70.252 245.789 69.803 246.689 \
+ 68.903 246.689 68.903 247.251 67.891 247.7 66.542 \
+ 247.7 66.092 247.7 65.643 247.7 65.08 247.251 65.08 \
+ 246.689 65.08 245.789 64.631 242.079 65.08 242.079 \
+ 64.631 241.629 65.08 241.067 65.08 238.818 64.631 \
+ 237.806 64.631 236.457 64.631 234.546 64.631 233.197 \
+ 64.631 232.634 64.631 232.185 64.631 231.735 64.631 \
+ 228.924 64.631 227.575 64.631 225.664 64.631 225.214 \
+ 64.631 224.764 64.631 223.302 64.631 217.231 65.08 \
+ 216.332 65.643 215.769 69.803 214.87 70.252 215.32 \
+ 70.252 216.332 70.252 217.681 70.252 218.58 69.803 \
+ 219.142 69.803 220.492 69.353 220.941 69.353 221.391 \
+ 68.903 221.953 68.903 225.664 68.453 226.563 68.453 \
+ 228.025 68.453 228.474 67.891 228.924 67.891 230.835 \
+ 68.453 236.457 68.453 237.806 68.453 238.818 68.453 \
+ 240.617 68.453 241.067 68.903 241.067 68.903 241.629 \
+ 69.353 241.629 70.702 241.067 70.702 240.617 71.264 \
+ 240.167 71.264 239.268 72.164 238.256 73.063 236.457 \
+ 74.525 234.546 74.975 233.197 76.324 230.835 77.336 \
+ 229.824 78.235 227.575 78.235 227.013 78.685 226.563 \
+ 78.685 225.664 79.135 225.214 79.697 224.764 79.697 \
+ 224.202 80.146 222.403 81.046 220.941 81.945 217.681 \
+ 82.957 215.769 85.318 214.87 85.768 214.87 87.567 \
+ 214.42 87.567 215.769 87.117 216.332 87.567 216.781 \
+ 88.129 219.592 87.567 219.592 87.567 220.492 87.567 \
+ 221.391 87.567 224.764 87.567 225.664 87.567 226.113 \
+ 87.117 226.113 87.117 227.575 87.567 229.374 88.579 \
+ 235.445 89.029 239.268 89.029 239.718 89.029 241.067 \
+ 89.478 242.529 89.478 242.978 89.928 243.878 89.928 \
+ 244.44 90.378 244.89 90.94 246.239 92.289 248.6 \
+ -fill $pengcolor -outline {} -width 1 -tags logo
+
+ $c create polygon 117.587 220.492 118.037 \
+ 222.403 117.587 222.853 117.587 224.764 116.687 \
+ 226.113 116.687 227.013 116.238 228.025 114.776 \
+ 229.374 113.877 231.285 112.865 231.735 109.154 \
+ 234.995 106.343 236.457 105.444 237.357 103.982 \
+ 237.806 103.083 238.256 102.633 238.818 102.183 \
+ 238.818 101.172 239.268 99.822 239.718 98.361 \
+ 239.268 97.461 239.718 96.562 239.268 96.0 238.818 \
+ 95.55 238.818 94.201 236.907 94.201 235.445 94.201 \
+ 233.646 94.65 233.197 94.65 232.634 95.1 232.185 \
+ 95.1 231.735 95.55 231.735 96.0 230.386 97.461 \
+ 228.025 97.461 227.575 98.361 226.563 99.822 224.764 \
+ 101.172 223.302 101.172 222.853 102.633 221.391 \
+ 103.083 220.941 104.432 219.592 103.982 218.58 \
+ 103.982 217.231 103.982 216.781 103.982 215.32 \
+ 104.432 214.42 103.982 210.148 103.982 209.698 \
+ 103.982 209.248 104.432 208.798 104.432 207.899 \
+ 104.432 205.988 104.432 205.538 104.994 203.177 \
+ 104.994 202.277 104.994 201.265 104.994 200.816 \
+ 104.994 200.366 104.994 199.916 105.894 199.467 \
+ 106.343 198.904 106.793 198.455 107.243 198.904 \
+ 108.255 198.904 108.255 199.467 108.705 199.467 \
+ 108.705 202.727 108.255 204.076 108.255 205.538 \
+ 108.255 205.988 107.805 205.988 107.805 206.887 \
+ 107.805 209.698 107.243 210.71 106.793 212.059 \
+ 106.343 214.87 106.343 215.32 106.343 215.769 \
+ 105.894 217.681 106.343 217.681 106.793 217.681 \
+ 107.243 217.231 108.705 215.32 109.604 215.32 \
+ 110.054 214.42 110.054 213.97 110.616 213.97 110.616 \
+ 214.42 111.965 214.87 112.415 214.87 112.865 215.32 \
+ 114.326 216.332 116.238 217.681 116.687 218.58 \
+ 117.137 219.592 117.587 220.042 117.587 220.492 \
+ -fill $pengcolor -outline {} -width 1 -tags logo
+
+ $c create polygon 123.658 258.944 123.658 \
+ 259.394 123.658 260.293 123.658 261.755 123.658 \
+ 262.654 123.658 263.104 123.209 266.364 123.209 \
+ 267.376 122.759 269.175 122.309 269.737 121.859 \
+ 271.087 121.859 271.536 121.859 271.986 121.297 \
+ 271.986 121.297 272.548 120.847 273.448 120.398 \
+ 273.448 120.398 273.897 118.486 276.259 118.037 \
+ 276.708 117.587 277.608 117.137 278.17 116.687 \
+ 278.17 115.675 278.62 115.675 279.069 113.427 \
+ 280.419 112.865 280.981 112.415 280.981 111.965 \
+ 281.43 110.054 282.33 109.154 282.33 108.705 282.78 \
+ 108.255 282.78 107.805 283.229 104.994 283.792 \
+ 104.432 283.792 103.982 283.792 103.533 283.792 \
+ 103.083 283.792 102.633 283.792 102.183 283.792 \
+ 101.172 283.792 100.722 283.792 99.822 283.792 98.81 \
+ 283.792 96.562 282.33 96.0 282.78 95.1 281.88 94.201 \
+ 281.43 91.84 279.969 92.289 279.519 92.289 278.62 \
+ 93.751 279.069 93.751 279.519 94.201 279.519 94.65 \
+ 279.969 95.1 279.969 96.0 280.981 98.81 281.88 \
+ 101.172 281.88 101.621 281.88 102.633 281.88 103.083 \
+ 281.88 103.533 281.88 104.432 281.43 104.994 281.88 \
+ 105.444 281.43 106.793 281.43 107.805 280.981 \
+ 108.705 280.419 109.154 280.419 109.604 279.969 \
+ 110.054 279.969 110.616 279.969 111.066 279.519 \
+ 112.865 278.17 113.427 277.608 113.877 277.608 \
+ 113.877 277.158 114.326 277.158 114.326 276.708 \
+ 114.776 276.259 115.226 276.259 116.238 274.347 \
+ 116.687 274.347 116.687 273.897 117.587 272.998 \
+ 117.587 272.548 118.037 271.986 119.498 267.826 \
+ 120.398 265.015 120.398 262.204 119.948 259.843 \
+ 119.948 259.394 119.948 258.944 119.498 257.482 \
+ 118.486 254.222 118.037 253.772 117.587 251.86 \
+ 115.675 249.05 115.226 248.6 114.776 248.15 113.877 \
+ 247.251 111.965 246.239 111.515 246.239 110.616 \
+ 246.239 110.054 246.239 109.154 246.239 107.243 \
+ 247.251 106.343 247.251 105.444 247.7 104.994 247.7 \
+ 103.083 248.15 102.183 248.6 101.621 248.6 101.172 \
+ 249.05 100.722 249.499 99.822 250.062 98.361 250.062 \
+ 97.461 249.499 97.012 249.499 96.562 249.05 96.562 \
+ 248.6 97.012 248.15 99.822 245.789 100.272 245.339 \
+ 101.621 244.44 101.621 243.878 102.183 243.428 \
+ 102.633 243.428 102.633 242.978 103.982 241.629 \
+ 103.982 241.067 103.982 240.617 103.982 240.167 \
+ 105.444 239.268 108.705 236.907 108.705 236.457 \
+ 109.154 236.457 110.054 235.445 111.066 234.546 \
+ 112.415 234.096 112.865 233.646 113.427 233.646 \
+ 113.877 233.646 113.877 234.096 114.326 234.995 \
+ 114.776 235.445 114.776 236.457 114.326 237.357 \
+ 113.427 238.818 112.415 239.268 112.415 240.167 \
+ 111.965 240.167 111.515 240.617 110.054 241.629 \
+ 110.054 242.079 109.604 242.529 108.705 242.978 \
+ 110.054 242.978 113.427 242.079 114.326 242.529 \
+ 115.226 242.978 116.687 244.44 119.048 246.689 \
+ 119.498 247.7 119.498 248.15 119.948 248.6 119.948 \
+ 249.05 120.398 249.05 120.398 249.499 120.847 \
+ 249.499 120.847 250.062 121.297 250.511 121.297 \
+ 251.411 121.859 252.31 122.759 252.872 122.759 \
+ 254.222 122.759 254.671 123.658 258.494 123.658 \
+ 258.944 -fill $pengcolor -outline {} -width 1 -tags logo
+
+ $c create polygon 147.607 215.769 148.506 215.32 \
+ 148.506 217.231 148.506 217.681 148.506 218.13 \
+ 148.956 218.58 148.506 220.492 148.506 220.941 \
+ 148.506 222.853 148.956 224.764 148.956 226.113 \
+ 148.506 226.563 148.956 226.563 148.506 228.924 \
+ 148.956 229.824 148.956 231.285 148.506 232.185 \
+ 148.956 232.634 148.956 233.646 149.405 234.995 \
+ 148.956 234.995 149.405 235.445 149.405 236.907 \
+ 149.405 237.357 149.968 238.818 150.867 240.167 \
+ 150.867 240.617 151.317 242.079 152.216 243.428 \
+ 153.228 245.339 154.128 245.789 155.027 246.239 \
+ 156.939 245.789 157.388 246.239 156.489 246.689 \
+ 155.027 247.7 154.128 247.7 153.228 247.7 152.216 \
+ 247.7 151.767 247.7 150.867 247.251 150.417 246.239 \
+ 149.405 246.239 148.056 245.339 147.607 244.44 \
+ 147.157 243.428 145.695 241.629 145.695 240.617 \
+ 145.245 240.167 145.245 239.718 144.796 238.256 \
+ 144.346 236.907 144.346 235.445 143.784 234.546 \
+ 143.784 233.197 143.784 232.185 143.784 230.835 \
+ 143.334 229.824 143.784 229.374 143.334 229.374 \
+ 143.334 228.474 142.884 230.386 141.985 231.735 \
+ 140.973 233.197 140.523 234.096 140.523 234.546 \
+ 140.523 234.995 139.624 236.457 139.174 237.806 \
+ 138.162 239.718 137.263 241.067 136.813 242.079 \
+ 135.913 242.978 134.452 244.89 134.002 245.789 \
+ 133.552 245.789 132.091 246.689 131.191 247.251 \
+ 129.73 248.15 129.28 248.15 128.38 247.7 128.38 \
+ 248.15 126.919 247.7 126.019 247.251 125.12 246.239 \
+ 125.12 245.339 124.67 244.89 124.67 244.44 124.67 \
+ 243.428 124.67 242.529 124.67 241.067 124.67 239.718 \
+ 125.12 239.268 124.67 239.268 124.67 238.256 125.12 \
+ 237.806 125.12 237.357 125.12 236.907 125.12 236.007 \
+ 125.12 234.096 125.57 233.197 125.57 232.185 126.019 \
+ 232.185 126.019 231.285 126.019 230.386 126.019 \
+ 229.374 126.469 228.474 126.469 227.013 126.469 \
+ 225.214 126.019 225.214 126.469 225.214 126.019 \
+ 223.302 126.019 221.953 126.019 220.492 125.57 \
+ 220.042 125.12 219.592 124.108 219.142 123.209 \
+ 219.142 121.859 220.042 121.297 220.042 120.398 \
+ 220.941 119.498 221.391 119.048 221.391 118.486 \
+ 221.953 118.037 221.953 118.037 221.391 118.486 \
+ 220.941 119.498 220.042 120.847 219.142 122.759 \
+ 217.681 124.108 216.781 125.12 215.769 126.469 \
+ 214.87 126.919 214.87 127.481 214.87 128.38 214.87 \
+ 128.83 214.87 129.73 214.87 129.73 215.769 130.292 \
+ 215.769 130.742 216.781 130.742 217.681 130.292 \
+ 219.142 130.292 221.953 130.292 223.302 130.292 \
+ 224.202 129.73 225.214 129.28 227.013 128.83 227.575 \
+ 129.28 227.575 129.28 228.474 128.83 229.374 129.28 \
+ 229.824 129.28 230.386 128.83 231.735 128.38 234.096 \
+ 128.38 234.995 127.931 236.457 127.931 239.268 \
+ 127.931 240.167 127.931 241.629 128.83 242.978 \
+ 129.28 243.878 129.73 244.44 130.742 244.44 131.191 \
+ 244.44 132.091 244.44 133.103 243.878 134.002 \
+ 242.978 134.902 242.079 135.351 241.067 135.913 \
+ 240.167 136.363 239.268 136.813 238.818 137.263 \
+ 237.806 137.712 236.907 138.162 235.445 138.724 \
+ 234.546 139.174 233.646 139.624 232.634 140.523 \
+ 230.835 140.973 228.924 141.535 227.013 142.435 \
+ 225.664 142.884 223.302 143.334 221.391 143.334 \
+ 220.941 143.334 219.142 144.346 217.681 144.796 \
+ 216.781 145.695 216.332 146.595 216.332 147.607 \
+ 215.769 -fill $pengcolor -outline {} -width 1 -tags logo
+
+ $c create polygon 165.371 241.067 165.371 \
+ 241.067 164.921 243.878 164.921 246.239 163.46 \
+ 246.689 161.211 247.251 160.649 247.251 160.199 \
+ 244.44 160.199 243.878 160.199 243.428 160.199 \
+ 242.079 160.199 240.167 160.199 239.718 159.749 \
+ 239.268 160.199 237.806 159.749 237.357 159.749 \
+ 236.007 159.749 230.835 159.749 229.824 159.749 \
+ 228.924 159.749 226.113 159.749 225.664 159.749 \
+ 223.752 159.749 222.853 159.749 218.58 159.749 \
+ 218.13 159.749 217.681 160.199 217.231 161.661 \
+ 216.781 162.11 216.781 162.56 216.781 163.46 216.781 \
+ 164.022 219.142 163.46 222.403 163.46 222.853 163.46 \
+ 224.202 163.46 225.664 163.46 226.563 163.46 227.013 \
+ 163.46 228.924 163.01 230.835 163.01 232.634 163.46 \
+ 233.197 164.022 232.634 164.472 232.634 164.921 \
+ 232.185 164.921 231.735 165.371 231.735 165.821 \
+ 232.185 165.371 233.646 165.821 236.007 165.371 \
+ 238.256 165.371 238.818 165.371 240.617 165.371 \
+ 241.067 -fill $pengcolor -outline {} -width 1 -tags logo
+
+ $c create polygon 165.821 214.42 166.833 215.32 \
+ 166.271 215.32 165.821 216.332 165.371 216.332 \
+ 165.371 216.781 165.821 217.681 165.821 218.13 \
+ 165.371 219.142 165.371 220.042 164.921 222.853 \
+ 165.371 224.764 164.921 225.664 165.371 227.575 \
+ 165.371 228.474 164.921 228.474 164.472 227.575 \
+ 164.472 226.113 164.022 224.764 164.472 224.202 \
+ 164.472 223.752 164.472 222.403 164.921 214.87 \
+ 164.472 213.521 164.472 212.959 164.472 212.509 \
+ 164.022 212.509 163.46 212.509 163.01 212.959 162.56 \
+ 212.959 161.661 212.959 161.211 212.059 161.211 \
+ 211.609 160.649 211.609 160.199 209.698 160.649 \
+ 208.349 163.46 206.437 164.472 206.437 165.821 \
+ 207.899 165.821 208.349 166.833 210.148 166.833 \
+ 210.71 165.821 211.609 165.371 212.059 165.371 \
+ 212.959 165.821 213.97 165.821 214.42 -fill $pengcolor \
+ -outline {} -width 1 -tags logo
+
+ $c create polygon 201.462 248.6 201.462 249.05 \
+ 201.012 249.05 200.563 249.05 200.001 248.6 199.551 \
+ 248.6 198.651 247.7 197.752 247.251 196.74 246.689 \
+ 196.29 245.789 194.379 244.89 194.379 244.44 194.379 \
+ 242.529 193.929 242.079 193.479 240.617 193.479 \
+ 240.167 193.929 239.718 193.479 239.268 193.03 \
+ 236.457 192.58 234.096 192.58 233.197 192.58 231.735 \
+ 192.58 223.302 192.58 221.391 192.13 220.941 191.568 \
+ 221.953 189.769 226.113 189.319 226.563 189.319 \
+ 227.013 188.757 228.025 188.307 228.474 188.757 \
+ 228.474 185.497 234.096 185.047 234.995 184.597 \
+ 236.457 184.147 236.457 184.147 236.907 184.147 \
+ 237.357 183.136 239.268 182.686 239.268 182.686 \
+ 239.718 182.236 240.167 181.786 241.067 181.337 \
+ 242.529 180.887 242.529 180.887 243.878 179.425 \
+ 245.789 178.975 246.689 178.076 246.689 178.076 \
+ 247.251 177.064 247.7 175.715 247.7 175.265 247.7 \
+ 174.703 247.7 174.253 247.251 174.253 246.689 \
+ 174.253 245.789 173.804 242.079 174.253 242.079 \
+ 173.804 241.629 173.804 241.067 173.804 238.818 \
+ 173.804 237.806 173.804 236.457 173.354 234.546 \
+ 173.354 233.197 173.804 232.634 173.804 232.185 \
+ 173.804 231.735 173.804 228.924 173.354 227.575 \
+ 173.804 227.575 173.804 225.664 173.804 225.214 \
+ 173.804 224.764 173.804 223.302 173.804 217.231 \
+ 174.253 216.332 174.703 215.769 178.526 214.87 \
+ 179.425 215.32 179.425 216.332 179.425 217.681 \
+ 179.425 218.58 178.975 219.142 178.526 220.492 \
+ 178.526 220.941 178.076 221.391 178.076 221.953 \
+ 178.076 225.664 177.514 226.563 177.514 228.025 \
+ 177.064 228.474 177.064 228.924 177.064 230.835 \
+ 177.514 236.457 177.064 237.806 177.514 237.806 \
+ 177.514 238.818 177.514 240.617 177.514 241.067 \
+ 178.076 241.629 178.526 241.629 179.425 241.067 \
+ 179.875 240.617 179.875 240.167 180.325 239.268 \
+ 181.337 238.256 182.236 236.457 183.698 234.546 \
+ 184.147 233.197 185.497 230.835 186.509 229.824 \
+ 187.408 227.575 187.408 227.013 187.408 226.563 \
+ 187.858 225.664 188.307 225.214 188.757 224.764 \
+ 188.757 224.202 189.319 222.403 190.219 220.941 \
+ 191.118 217.681 192.13 215.769 194.379 214.87 \
+ 194.941 214.87 196.74 214.42 196.74 215.769 196.29 \
+ 215.769 196.29 216.332 196.29 216.781 196.74 219.592 \
+ 196.74 220.492 196.29 221.391 196.74 224.764 196.29 \
+ 225.664 196.29 226.113 196.29 227.575 196.74 229.374 \
+ 197.19 235.445 198.202 239.268 198.202 239.718 \
+ 198.202 241.067 198.202 242.529 198.651 242.978 \
+ 199.101 243.878 199.101 244.44 199.551 244.89 \
+ 200.001 246.239 201.462 248.6 -fill $pengcolor -outline \
+ {} -width 1 -tags logo
+
+ $c create polygon 71.714 185.412 71.714 110.869 \
+ 81.496 110.869 82.845 110.981 83.969 111.431 85.094 \
+ 112.106 86.105 113.118 86.893 114.467 87.567 116.041 \
+ 88.017 117.39 88.242 118.065 88.467 118.852 88.579 \
+ 119.639 88.804 120.538 88.916 121.438 89.029 122.337 \
+ 89.141 123.349 89.254 124.361 89.366 125.485 89.366 \
+ 126.61 89.478 127.734 89.478 128.971 89.478 130.208 \
+ 89.478 131.444 89.478 132.456 89.478 133.468 89.478 \
+ 134.48 89.366 135.492 89.254 136.391 89.254 137.291 \
+ 89.141 138.19 89.029 139.09 88.916 139.877 88.804 \
+ 140.664 88.691 141.451 88.579 142.238 88.354 143.362 \
+ 88.129 144.374 87.904 145.386 87.567 146.398 87.342 \
+ 147.297 87.005 148.197 86.668 148.984 86.218 149.771 \
+ 87.005 151.233 87.342 152.02 87.68 152.919 87.904 \
+ 153.931 88.129 154.943 88.129 155.505 88.354 156.854 \
+ 88.354 157.641 88.354 158.428 88.467 159.328 88.467 \
+ 160.34 88.467 161.352 88.467 162.476 88.579 163.6 \
+ 88.579 164.837 88.579 166.186 88.579 166.973 88.691 \
+ 167.873 88.804 168.885 88.916 169.897 89.029 171.021 \
+ 89.029 172.258 89.029 173.719 89.029 175.068 89.029 \
+ 176.305 89.029 177.542 89.141 178.554 89.141 179.566 \
+ 89.141 180.353 89.141 181.14 89.254 181.814 89.366 \
+ 182.714 89.478 183.051 89.478 185.412 83.857 185.412 \
+ 83.857 184.738 83.744 183.951 83.744 183.276 83.744 \
+ 182.489 83.744 180.803 83.857 179.791 83.857 178.891 \
+ 83.857 177.879 83.857 176.867 83.857 175.743 83.857 \
+ 174.619 83.857 173.27 83.857 172.033 83.744 170.908 \
+ 83.744 170.009 83.632 169.109 83.632 168.322 83.52 \
+ 166.973 83.407 166.524 83.407 166.186 83.407 165.062 \
+ 83.407 164.05 83.295 163.151 83.295 162.251 83.295 \
+ 161.464 83.182 160.789 82.957 159.553 81.945 158.203 \
+ 80.596 157.754 76.886 157.754 76.886 185.412 71.714 \
+ 185.412 -fill #000000 -outline {} -width 1 -tags logo
+
+ $c create polygon 92.289 148.309 92.289 147.185 \
+ 92.289 146.061 92.289 145.049 92.402 143.924 92.402 \
+ 142.8 92.402 141.788 92.402 140.664 92.514 139.652 \
+ 92.514 138.64 92.627 137.628 92.627 136.616 92.739 \
+ 135.717 92.739 134.705 92.851 133.805 92.964 132.793 \
+ 92.964 131.894 93.076 130.995 93.301 129.196 93.414 \
+ 128.409 93.526 127.509 93.639 126.722 93.751 125.935 \
+ 93.863 125.148 93.976 124.361 94.313 122.787 94.426 \
+ 122.112 94.65 121.325 94.763 120.651 95.1 119.301 \
+ 95.55 117.615 96.112 116.041 96.674 114.692 97.236 \
+ 113.455 97.799 112.443 98.361 111.544 99.035 110.757 \
+ 99.71 110.082 100.385 109.632 101.059 109.295 \
+ 101.846 109.07 102.633 108.958 104.207 109.295 \
+ 104.882 109.632 105.556 110.082 106.231 110.757 \
+ 106.906 111.544 107.468 112.443 108.03 113.455 \
+ 108.592 114.692 109.154 116.041 109.604 117.615 \
+ 110.054 119.301 110.279 119.976 110.616 121.325 \
+ 110.841 122.112 110.953 122.787 111.178 123.574 \
+ 111.403 125.148 111.628 125.935 111.74 126.722 \
+ 111.853 127.622 111.965 128.409 112.078 129.308 \
+ 112.19 130.208 112.302 130.995 112.415 132.006 \
+ 112.64 133.805 112.752 134.817 112.865 135.717 \
+ 112.977 136.729 112.977 137.741 113.089 138.752 \
+ 113.089 139.764 113.202 140.776 113.202 141.788 \
+ 113.314 142.912 113.314 143.924 113.314 145.049 \
+ 113.427 146.061 113.427 147.185 113.427 148.309 \
+ 113.427 149.546 113.314 150.783 113.314 151.907 \
+ 113.314 153.032 113.314 154.156 113.202 155.28 \
+ 113.202 156.405 113.089 157.529 113.089 158.541 \
+ 112.977 159.553 112.865 160.565 112.752 161.576 \
+ 112.64 162.588 112.527 163.6 112.415 164.5 112.302 \
+ 165.512 112.19 166.411 112.078 167.311 111.965 \
+ 168.21 111.853 169.109 111.628 169.897 111.515 \
+ 170.796 111.403 171.583 111.178 172.37 111.066 \
+ 173.157 110.616 174.731 110.504 175.518 110.279 \
+ 176.193 110.054 176.98 109.604 178.666 109.154 \
+ 180.128 108.592 181.59 108.03 182.826 107.468 \
+ 183.951 106.906 184.963 106.231 185.75 105.556 \
+ 186.424 104.882 186.986 104.207 187.436 103.42 \
+ 187.661 102.633 187.661 101.846 187.661 101.059 \
+ 187.436 100.385 186.986 99.71 186.424 99.035 185.75 \
+ 98.361 184.963 97.799 183.951 97.236 182.826 96.674 \
+ 181.59 96.112 180.128 95.55 178.666 95.1 176.98 \
+ 94.988 176.193 94.763 175.518 94.538 174.731 94.426 \
+ 173.944 94.088 172.37 93.976 171.583 93.863 170.796 \
+ 93.639 169.897 93.526 169.109 93.414 168.21 93.301 \
+ 167.311 93.189 166.411 93.076 165.512 92.964 164.5 \
+ 92.964 163.6 92.851 162.588 92.739 161.576 92.627 \
+ 160.565 92.627 159.553 92.514 158.541 92.514 157.529 \
+ 92.514 156.405 92.402 155.28 92.402 154.156 92.402 \
+ 153.032 92.289 151.907 92.289 150.783 92.289 149.546 \
+ 92.289 148.309 -fill #000000 -outline {} -width 1 -tags logo
+
+ $c create polygon 121.859 110.869 127.481 \
+ 110.869 134.902 185.412 129.28 185.412 127.931 \
+ 171.808 120.847 171.808 119.948 185.412 114.326 \
+ 185.412 121.859 110.869 -fill #000000 -outline {} \
+ -width 1 -tags logo
+
+ $c create polygon 137.263 185.412 137.263 \
+ 110.869 147.157 110.869 148.394 110.981 149.518 \
+ 111.431 150.417 112.106 151.317 113.118 152.104 \
+ 114.467 152.778 116.041 153.228 117.39 153.341 \
+ 118.065 153.566 118.852 153.903 120.538 154.015 \
+ 121.438 154.128 122.337 154.24 123.349 154.353 \
+ 124.361 154.465 125.485 154.465 126.61 154.577 \
+ 127.734 154.577 128.971 154.577 130.208 154.577 \
+ 131.444 154.577 132.456 154.577 133.468 154.577 \
+ 134.48 154.577 135.492 154.577 136.391 154.577 \
+ 137.291 154.577 138.19 154.465 139.09 154.465 \
+ 139.877 154.353 140.664 154.24 141.451 154.128 \
+ 142.238 153.903 143.362 153.678 144.374 153.341 \
+ 145.386 153.003 146.398 152.554 147.297 152.216 \
+ 148.197 151.767 148.984 151.317 149.771 152.104 \
+ 151.233 152.441 152.02 152.778 152.919 153.003 \
+ 153.931 153.228 154.943 153.341 155.505 153.453 \
+ 156.854 153.566 157.641 153.678 158.428 153.79 \
+ 159.328 153.903 160.34 154.015 161.352 154.015 \
+ 162.476 154.128 163.6 154.128 164.837 154.128 \
+ 166.186 154.128 166.973 154.128 167.873 154.128 \
+ 168.885 154.128 169.897 154.128 171.021 154.128 \
+ 172.258 154.128 173.719 154.24 175.068 154.24 \
+ 176.305 154.353 177.542 154.353 178.554 154.465 \
+ 179.566 154.577 180.353 154.69 181.14 154.69 181.814 \
+ 154.915 182.714 155.027 183.051 155.027 185.412 \
+ 149.405 185.412 149.405 184.738 149.293 183.951 \
+ 149.293 183.276 149.181 182.489 149.181 180.803 \
+ 149.068 179.791 149.068 178.891 149.068 177.879 \
+ 149.068 176.867 148.956 175.743 148.956 174.619 \
+ 148.956 173.27 148.956 172.033 148.956 170.908 \
+ 148.956 170.009 148.956 169.109 148.956 168.322 \
+ 148.956 166.973 148.956 166.524 148.956 166.186 \
+ 148.956 165.062 148.843 164.05 148.731 163.151 \
+ 148.618 162.251 148.506 161.464 148.394 160.789 \
+ 148.056 159.553 147.269 158.203 146.145 157.754 \
+ 142.435 157.754 142.435 185.412 137.263 185.412 \
+ -fill #000000 -outline {} -width 1 -tags logo
+
+ $c create polygon 158.4 185.412 158.4 110.869 \
+ 164.022 110.869 164.022 185.412 158.4 185.412 -fill \
+ #000000 -outline {} -width 1 -tags logo
+
+ $c create polygon 168.182 185.412 168.182 \
+ 110.869 173.804 110.869 177.514 135.267 177.739 \
+ 136.054 177.851 136.954 177.964 137.853 178.076 \
+ 138.752 178.301 139.539 178.413 140.439 178.526 \
+ 141.338 178.751 143.137 178.975 144.037 179.088 \
+ 144.824 179.2 145.723 179.313 146.623 179.425 147.41 \
+ 179.538 148.422 179.763 149.321 179.875 150.333 \
+ 180.1 151.233 180.212 152.132 180.437 153.032 180.55 \
+ 154.043 180.774 154.943 180.887 155.842 180.999 \
+ 156.742 181.224 157.754 181.337 158.653 181.337 \
+ 157.641 181.224 156.629 181.224 155.617 181.224 \
+ 154.606 181.224 153.594 181.112 152.582 181.112 \
+ 151.682 181.112 150.67 180.999 149.771 180.999 \
+ 148.759 180.999 147.86 180.887 146.96 180.887 \
+ 145.948 180.887 145.049 180.887 144.149 180.887 \
+ 143.25 180.887 142.125 180.887 141.114 180.887 \
+ 140.102 180.887 139.09 180.887 138.078 180.887 \
+ 137.178 180.887 136.166 180.887 135.267 180.887 \
+ 134.368 180.887 133.468 180.887 132.569 180.887 \
+ 131.669 180.887 130.882 180.887 130.095 180.887 \
+ 110.869 185.946 110.869 185.946 185.412 180.325 \
+ 185.412 176.165 160.565 176.052 159.778 175.94 \
+ 158.99 175.827 158.203 175.602 156.517 175.49 \
+ 155.617 175.378 154.718 175.265 153.931 175.153 \
+ 153.032 175.04 152.02 174.928 151.12 174.703 150.221 \
+ 174.591 149.321 174.478 148.422 174.366 147.41 \
+ 174.141 146.51 174.028 145.611 173.804 144.599 \
+ 173.691 143.587 173.579 142.575 173.354 141.676 \
+ 173.241 140.551 173.017 139.539 172.904 138.528 \
+ 172.904 139.539 172.904 140.551 173.017 141.563 \
+ 173.017 142.575 173.017 143.587 173.129 144.599 \
+ 173.129 145.498 173.129 146.51 173.241 147.41 \
+ 173.241 148.422 173.241 149.321 173.354 150.221 \
+ 173.354 151.233 173.354 152.132 173.354 153.144 \
+ 173.354 154.156 173.354 155.055 173.354 156.067 \
+ 173.354 156.967 173.354 157.866 173.354 158.766 \
+ 173.354 159.553 173.354 160.452 173.354 161.239 \
+ 173.354 162.026 173.354 162.926 173.354 185.412 \
+ 168.182 185.412 -fill #000000 -outline {} -width 1 -tags logo
+
+ $c create polygon 206.184 185.412 205.622 \
+ 175.968 205.397 177.092 205.172 178.217 204.948 \
+ 179.228 204.61 180.128 204.385 181.027 204.048 \
+ 181.814 203.823 182.489 203.486 183.164 203.149 \
+ 183.838 202.811 184.4 202.024 185.75 201.125 186.762 \
+ 200.113 187.436 199.101 187.661 198.089 187.549 \
+ 197.19 186.986 196.29 186.087 195.391 184.85 194.941 \
+ 184.176 194.491 183.389 194.042 182.489 193.592 \
+ 181.477 193.255 180.465 192.805 179.341 192.467 \
+ 178.217 192.13 176.98 191.905 176.193 191.68 175.406 \
+ 191.568 174.619 191.456 173.832 191.231 172.932 \
+ 191.118 172.145 191.006 171.246 190.781 169.559 \
+ 190.669 168.66 190.556 167.648 190.444 166.748 \
+ 190.331 165.736 190.219 164.725 190.106 163.825 \
+ 189.994 162.926 189.994 162.026 189.882 161.127 \
+ 189.769 160.227 189.769 159.215 189.657 158.316 \
+ 189.544 157.304 189.544 156.405 189.432 155.393 \
+ 189.432 154.381 189.319 153.369 189.319 152.357 \
+ 189.319 151.345 189.319 150.333 189.319 149.321 \
+ 189.319 148.197 189.319 146.96 189.319 145.948 \
+ 189.319 144.824 189.319 143.7 189.319 142.688 \
+ 189.432 141.563 189.432 140.551 189.544 139.539 \
+ 189.544 138.528 189.544 137.516 189.657 136.504 \
+ 189.769 135.492 189.769 134.592 189.882 133.581 \
+ 189.994 132.681 189.994 131.782 190.106 130.882 \
+ 190.219 129.983 190.331 129.083 190.556 127.397 \
+ 190.669 126.61 190.781 125.823 191.006 124.923 \
+ 191.118 124.136 191.231 123.462 191.568 121.887 \
+ 191.793 121.213 191.905 120.426 192.13 119.751 \
+ 192.58 117.952 193.142 116.378 193.704 114.917 \
+ 194.266 113.567 194.941 112.443 195.616 111.431 \
+ 196.29 110.532 196.965 109.857 197.752 109.295 \
+ 198.426 108.845 199.214 108.62 200.001 108.508 \
+ 201.799 108.958 202.699 109.407 203.374 110.194 \
+ 204.161 111.094 204.835 112.218 205.51 113.567 \
+ 206.184 115.141 206.634 116.491 206.859 117.165 \
+ 206.971 117.952 207.421 119.526 207.534 120.426 \
+ 207.758 121.325 207.871 122.225 207.983 123.124 \
+ 208.096 124.136 208.208 125.036 208.321 126.047 \
+ 208.433 127.172 208.545 128.184 208.658 129.308 \
+ 208.77 130.32 208.77 131.557 208.883 132.681 208.995 \
+ 133.805 204.273 133.805 204.161 132.681 203.936 \
+ 131.557 203.711 130.432 203.486 129.533 203.261 \
+ 128.633 202.924 127.734 202.699 126.947 202.362 \
+ 126.385 201.35 124.586 200.001 124.024 199.438 \
+ 124.136 198.989 124.361 198.426 124.923 197.977 \
+ 125.598 197.527 126.497 197.077 127.622 196.628 \
+ 128.971 196.29 130.545 196.178 131.219 195.953 \
+ 132.681 195.84 133.356 195.728 134.143 195.616 \
+ 134.93 195.503 135.829 195.278 137.516 195.278 \
+ 138.303 195.166 139.315 195.166 140.214 195.053 \
+ 141.114 195.053 142.125 194.941 143.137 194.941 \
+ 144.149 194.941 145.161 194.941 146.173 194.941 \
+ 147.297 194.941 148.309 194.941 149.546 194.941 \
+ 150.67 194.941 151.907 194.941 152.919 195.053 \
+ 154.043 195.053 155.168 195.166 156.18 195.166 \
+ 157.192 195.278 158.091 195.391 159.103 195.391 \
+ 160.002 195.503 160.902 195.616 161.801 195.728 \
+ 162.588 195.84 163.375 196.065 164.162 196.178 \
+ 164.949 196.29 165.736 196.628 167.198 197.077 \
+ 168.547 197.527 169.672 197.977 170.571 198.426 \
+ 171.246 198.989 171.808 199.438 172.145 200.001 \
+ 172.258 200.9 171.92 201.575 171.246 202.249 170.009 \
+ 202.811 168.547 203.149 167.76 203.374 166.973 \
+ 203.598 166.186 203.823 165.399 204.048 164.5 \
+ 204.273 163.488 204.385 162.476 204.498 161.464 \
+ 204.61 160.34 204.723 159.103 200.001 159.103 \
+ 200.001 145.049 209.445 145.049 209.445 185.412 \
+ 206.184 185.412 -fill #000000 -outline {} -width 1 -tags logo
+
+ $c create polygon 148.506 261.305 148.506 \
+ 263.554 143.784 263.554 143.784 261.305 143.671 \
+ 260.068 143.334 259.394 142.772 259.056 141.985 \
+ 258.944 141.085 259.056 140.523 259.394 140.074 \
+ 261.755 140.074 263.104 140.523 264.678 141.085 \
+ 265.465 141.985 266.364 146.145 270.637 147.607 \
+ 271.874 148.506 272.998 148.843 274.01 148.956 \
+ 275.359 148.956 277.158 148.843 278.507 148.506 \
+ 279.632 147.944 280.643 147.157 281.43 146.482 \
+ 281.88 145.695 282.218 144.796 282.442 143.784 \
+ 282.667 142.659 282.78 141.535 282.78 140.298 282.78 \
+ 139.286 282.78 138.387 282.667 137.6 282.442 136.925 \
+ 282.218 136.363 281.88 135.576 281.093 135.014 \
+ 280.194 134.564 278.957 134.452 277.608 134.452 \
+ 275.359 139.624 275.359 139.624 277.608 139.736 \
+ 279.069 140.074 279.969 141.535 280.419 142.659 \
+ 280.081 143.334 279.519 143.671 278.62 143.784 \
+ 277.158 143.784 275.809 143.671 275.022 143.334 \
+ 274.235 142.772 273.448 141.985 272.548 137.263 \
+ 267.376 136.251 266.364 135.351 265.465 135.014 \
+ 264.565 134.902 263.554 134.902 261.755 135.014 \
+ 260.518 135.464 259.506 136.026 258.719 136.813 \
+ 257.932 137.488 257.595 138.275 257.145 139.174 \
+ 256.92 140.186 256.695 141.31 256.583 142.435 \
+ 256.583 143.447 256.583 144.458 256.583 145.245 \
+ 256.695 145.92 256.92 147.157 257.482 147.719 \
+ 258.157 148.169 258.944 148.394 260.068 148.506 \
+ 261.305 -fill #000000 -outline {} -width 1 -tags logo
+
+ $c create polygon 165.821 270.187 165.821 \
+ 276.708 165.821 277.833 165.708 278.957 165.483 \
+ 279.856 165.259 280.643 164.921 281.318 164.472 \
+ 281.88 163.909 282.218 163.235 282.555 162.448 \
+ 282.667 161.548 282.78 160.536 282.78 159.3 282.78 \
+ 158.175 282.78 157.051 282.78 156.151 282.667 \
+ 155.364 282.555 154.69 282.218 154.128 281.88 \
+ 153.678 281.318 153.341 280.643 153.116 279.856 \
+ 152.891 278.845 152.778 277.833 152.778 276.708 \
+ 152.778 270.187 152.778 269.063 152.891 268.051 \
+ 153.116 267.264 153.341 266.589 154.128 265.465 \
+ 155.364 264.678 156.151 264.453 157.051 264.228 \
+ 158.063 264.116 159.3 264.116 160.424 264.116 \
+ 161.548 264.228 162.448 264.453 163.235 264.678 \
+ 163.909 265.015 164.472 265.465 164.921 265.915 \
+ 165.483 267.264 165.708 268.051 165.821 269.063 \
+ 165.821 270.187 -fill #000000 -outline {} -width 1 -tags logo
+
+ $c create polygon 177.514 256.583 177.514 \
+ 258.494 177.064 258.494 176.165 258.606 175.715 \
+ 258.944 175.378 259.281 175.265 259.843 175.265 \
+ 264.565 177.514 264.565 177.514 266.927 175.265 \
+ 266.927 175.265 282.78 170.543 282.78 170.543 \
+ 266.927 168.632 266.927 168.632 264.565 170.543 \
+ 264.565 170.543 261.305 170.655 259.843 170.993 \
+ 258.606 171.442 257.707 171.892 257.032 173.579 \
+ 256.358 174.703 256.133 176.165 256.133 176.727 \
+ 256.133 177.064 256.133 177.514 256.583 -fill \
+ #000000 -outline {} -width 1 -tags logo
+
+ $c create polygon 185.946 259.843 185.946 \
+ 264.565 188.757 264.565 188.757 266.927 185.946 \
+ 266.927 185.946 278.62 186.171 279.407 186.509 \
+ 279.969 187.071 280.306 187.858 280.419 188.307 \
+ 280.419 188.757 280.419 188.757 282.78 188.645 \
+ 282.78 188.307 282.78 187.183 282.78 186.509 282.78 \
+ 185.159 282.78 183.923 282.555 182.911 282.33 \
+ 182.236 281.88 181.786 281.206 181.561 280.419 \
+ 181.337 279.407 181.337 278.17 181.337 266.927 \
+ 179.425 266.927 179.425 264.565 181.337 264.565 \
+ 181.337 261.305 185.946 259.843 -fill #000000 \
+ -outline {} -width 1 -tags logo
+
+ $c create polygon 190.219 264.565 194.379 \
+ 264.565 196.29 279.519 196.74 279.519 199.101 \
+ 264.565 204.723 264.565 207.084 279.519 207.534 \
+ 279.519 209.895 264.565 213.605 264.565 209.895 \
+ 282.78 204.723 282.78 201.912 267.376 201.462 \
+ 267.376 199.101 282.78 193.479 282.78 190.219 \
+ 264.565 -fill #000000 -outline {} -width 1 -tags logo
+
+ $c create polygon 229.121 269.175 229.121 282.78 \
+ 224.848 282.78 224.848 280.981 224.061 281.768 \
+ 223.049 282.33 221.925 282.667 220.688 282.78 \
+ 219.564 282.78 218.44 282.555 217.54 282.33 216.866 \
+ 281.88 216.528 281.318 216.191 280.531 216.079 \
+ 279.632 215.966 278.62 215.966 275.359 216.079 \
+ 274.347 216.978 272.998 217.877 272.548 218.44 \
+ 272.211 219.114 271.986 219.789 271.761 220.688 \
+ 271.536 221.588 271.424 222.6 271.311 223.724 \
+ 271.199 224.848 271.087 224.848 269.175 224.736 \
+ 267.826 224.399 266.927 223.612 266.477 222.487 \
+ 266.364 221.7 266.477 221.138 266.927 220.688 \
+ 268.726 220.688 269.175 216.416 269.175 216.528 \
+ 267.938 216.753 266.702 217.203 265.69 217.877 \
+ 265.015 218.44 264.678 219.114 264.453 219.901 \
+ 264.228 220.801 264.116 221.925 264.116 223.049 \
+ 264.116 224.061 264.116 225.073 264.116 225.86 \
+ 264.228 226.535 264.453 227.659 265.015 228.334 \
+ 265.69 228.783 266.702 229.008 267.938 229.121 \
+ 269.175 -fill #000000 -outline {} -width 1 -tags logo
+
+ $c create polygon 243.175 264.565 243.175 \
+ 266.927 242.725 266.927 241.601 266.927 240.701 \
+ 267.151 239.914 267.489 239.352 267.826 239.015 \
+ 268.276 238.678 268.95 238.565 269.737 238.453 \
+ 270.637 238.453 282.78 233.731 282.78 233.731 \
+ 264.565 238.453 264.565 238.453 265.915 239.352 \
+ 265.128 240.364 264.565 242.163 264.116 242.725 \
+ 264.565 243.175 264.565 -fill #000000 -outline {} \
+ -width 1 -tags logo
+
+ $c create polygon 258.129 270.187 258.129 \
+ 274.347 249.696 274.347 249.696 278.17 249.809 \
+ 279.294 250.146 279.969 250.708 280.643 251.607 \
+ 280.981 252.732 280.643 253.406 279.969 253.744 \
+ 279.294 253.969 278.17 253.969 276.708 258.129 \
+ 276.708 258.129 277.608 258.129 278.957 257.904 \
+ 280.081 257.454 281.093 256.779 281.88 256.217 \
+ 282.218 254.643 282.667 253.744 282.78 252.732 \
+ 282.78 251.607 282.78 250.371 282.78 249.359 282.78 \
+ 248.459 282.667 247.672 282.442 246.436 281.88 \
+ 245.986 281.318 245.649 280.643 245.424 279.856 \
+ 245.199 278.957 245.086 277.833 244.974 276.708 \
+ 244.974 270.187 245.086 269.063 245.199 268.051 \
+ 245.311 267.264 245.649 266.589 245.986 265.915 \
+ 246.436 265.465 246.998 265.015 247.672 264.678 \
+ 248.459 264.453 249.359 264.228 250.371 264.116 \
+ 251.607 264.116 252.732 264.116 253.744 264.228 \
+ 254.756 264.453 255.543 264.678 256.217 265.015 \
+ 256.779 265.465 257.229 265.915 257.566 266.589 \
+ 257.791 267.264 258.016 268.051 258.129 269.063 \
+ 258.129 270.187 -fill #000000 -outline {} -width 1 -tags logo
+
+ $c create polygon 272.183 256.583 277.355 \
+ 256.583 277.355 282.78 272.183 282.78 272.183 \
+ 256.583 -fill #000000 -outline {} -width 1 -tags logo
+
+ $c create polygon 295.569 268.726 295.569 282.78 \
+ 290.959 282.78 290.959 269.175 290.847 268.051 \
+ 290.509 267.376 289.947 266.702 289.048 266.364 \
+ 287.923 266.702 287.136 267.376 287.024 268.051 \
+ 287.136 269.175 287.136 282.78 282.527 282.78 \
+ 282.527 264.565 286.687 264.565 287.136 265.915 \
+ 288.036 265.128 289.048 264.565 290.172 264.228 \
+ 291.409 264.116 292.533 264.116 293.433 264.341 \
+ 294.107 264.565 294.669 265.015 295.344 266.477 \
+ 295.569 267.489 295.569 268.726 -fill #000000 \
+ -outline {} -width 1 -tags logo
+
+ $c create polygon 312.434 269.737 312.434 \
+ 270.637 308.274 270.637 308.274 269.175 308.161 \
+ 267.826 307.824 266.927 307.262 266.477 306.363 \
+ 266.364 305.576 266.477 305.013 266.927 304.676 \
+ 267.826 304.564 269.175 304.564 278.17 304.676 \
+ 279.294 305.013 279.969 306.363 280.981 307.262 \
+ 280.643 307.824 279.969 307.937 279.294 307.824 \
+ 278.17 307.824 276.259 312.434 276.259 312.434 \
+ 277.608 312.434 278.957 312.209 280.081 311.759 \
+ 281.093 311.085 281.88 310.523 282.218 309.173 \
+ 282.667 308.386 282.78 307.374 282.78 306.363 282.78 \
+ 305.238 282.78 304.226 282.78 303.327 282.667 \
+ 302.427 282.442 301.753 282.218 301.191 281.88 \
+ 300.853 281.318 300.516 280.643 300.179 279.856 \
+ 299.954 278.957 299.841 277.833 299.841 276.708 \
+ 299.841 270.187 299.841 269.063 299.954 268.051 \
+ 300.179 267.264 300.404 266.589 301.191 265.465 \
+ 302.427 264.678 303.327 264.453 304.226 264.228 \
+ 305.238 264.116 306.363 264.116 307.374 264.116 \
+ 308.386 264.228 309.173 264.453 309.96 264.678 \
+ 310.523 265.015 311.085 265.465 311.759 266.252 \
+ 312.209 267.264 312.434 268.388 312.434 269.737 \
+ -fill #000000 -outline {} -width 1 -tags logo
+
+ $c create polygon 316.706 279.069 320.866 \
+ 279.069 320.866 282.78 316.706 282.78 316.706 \
+ 279.069 -fill #000000 -outline {} -width 1 -tags logo
+
+ $c create polygon 48.215 186.312 48.215 185.412 \
+ 47.766 184.4 47.766 183.501 47.316 183.501 47.316 \
+ 182.601 46.416 181.59 46.416 181.14 45.967 180.24 \
+ 45.405 179.791 44.955 179.228 44.055 178.329 43.606 \
+ 177.879 43.156 177.43 42.144 176.98 41.694 176.418 \
+ 41.245 175.968 38.883 175.068 36.972 174.169 36.522 \
+ 174.169 35.173 173.607 34.723 174.169 31.913 173.607 \
+ 31.913 174.169 29.551 173.607 29.551 174.169 28.54 \
+ 174.169 28.09 174.619 27.19 174.169 27.19 174.619 \
+ 26.741 174.619 25.729 175.068 23.93 175.518 22.918 \
+ 175.068 22.468 175.518 20.669 176.418 19.657 176.418 \
+ 15.048 178.779 14.036 179.228 12.686 180.24 12.237 \
+ 180.69 11.225 181.59 10.775 182.039 10.325 182.601 \
+ 10.775 182.601 10.325 184.4 10.775 184.85 11.225 \
+ 186.312 14.036 188.223 14.485 188.673 16.846 190.022 \
+ 17.296 190.472 17.296 191.034 15.947 191.933 15.048 \
+ 192.383 14.485 192.833 14.036 193.283 13.136 193.845 \
+ 12.237 194.295 12.686 195.644 12.686 196.094 12.237 \
+ 197.555 12.237 198.005 11.675 198.904 12.237 200.816 \
+ 12.237 202.277 12.237 204.526 11.675 205.988 12.237 \
+ 205.988 12.237 206.437 12.237 207.337 12.686 208.349 \
+ 12.686 209.248 13.136 209.698 12.686 211.16 13.136 \
+ 212.509 13.136 213.521 13.586 215.32 13.586 216.781 \
+ 13.586 217.681 14.036 220.492 14.485 222.403 15.048 \
+ 222.853 15.947 222.853 15.947 222.403 16.397 221.953 \
+ 16.846 216.781 17.296 215.32 17.858 211.609 18.308 \
+ 210.71 18.308 210.148 18.308 209.248 17.858 208.798 \
+ 17.858 207.899 18.308 206.437 18.308 205.538 18.308 \
+ 205.088 18.308 203.627 16.846 203.627 15.947 203.177 \
+ 15.947 202.727 15.947 202.277 16.397 201.715 16.846 \
+ 201.715 17.858 201.715 18.308 201.715 18.758 201.265 \
+ 18.308 200.816 17.858 199.916 18.308 198.455 17.858 \
+ 198.455 17.858 193.283 19.208 192.383 20.107 191.933 \
+ 21.569 191.484 22.018 191.484 22.918 192.383 22.918 \
+ 192.833 23.48 192.833 23.93 198.005 23.48 199.467 \
+ 23.93 202.277 25.279 202.277 29.551 202.727 30.001 \
+ 202.277 30.901 202.277 31.913 202.277 35.623 201.265 \
+ 36.522 201.265 36.972 200.816 37.984 200.816 38.883 \
+ 200.816 39.333 200.366 40.345 199.916 40.795 199.916 \
+ 42.594 198.455 44.055 198.005 44.055 197.555 44.505 \
+ 197.105 46.416 195.644 46.416 194.744 46.866 194.295 \
+ 47.316 193.845 47.766 193.283 47.316 192.833 48.215 \
+ 190.472 48.215 190.022 48.215 189.572 48.215 188.673 \
+ 48.215 187.211 48.215 186.762 48.215 186.312 -fill \
+ $bg -outline {} -width 1 -tags logo
+
+ $c create polygon 76.886 142.688 81.046 142.688 \
+ 82.508 142.35 83.407 140.889 83.632 140.327 83.969 \
+ 138.865 84.082 137.965 84.194 137.066 84.307 136.054 \
+ 84.307 134.93 84.307 133.805 84.307 132.456 84.194 \
+ 131.332 84.082 130.208 83.857 129.308 83.632 128.409 \
+ 83.407 127.734 82.395 126.272 81.046 125.823 76.886 \
+ 125.823 76.886 142.688 -fill $bg -outline {} -width \
+ 1 -tags logo
+
+ $c create polygon 97.461 148.309 97.461 149.546 \
+ 97.461 150.783 97.461 152.02 97.574 153.144 97.574 \
+ 154.268 97.686 155.28 97.686 156.405 97.799 157.416 \
+ 97.799 158.316 97.911 159.328 98.023 160.227 98.136 \
+ 161.127 98.361 162.701 98.473 163.488 98.586 164.275 \
+ 98.698 164.949 98.81 165.736 99.373 167.535 99.822 \
+ 169.109 100.497 170.234 101.059 171.133 101.846 \
+ 171.583 102.633 171.808 104.095 171.133 104.769 \
+ 170.234 105.332 169.109 105.894 167.535 106.343 \
+ 165.736 106.456 164.949 106.681 164.275 106.793 \
+ 163.488 106.906 162.701 107.018 161.914 107.243 \
+ 160.227 107.355 159.328 107.355 158.316 107.468 \
+ 157.416 107.58 156.405 107.58 155.28 107.693 154.268 \
+ 107.693 153.144 107.693 152.02 107.693 150.783 \
+ 107.805 149.546 107.805 148.309 107.805 147.073 \
+ 107.693 145.836 107.693 144.711 107.693 143.587 \
+ 107.693 142.463 107.58 141.338 107.58 140.327 \
+ 107.468 139.315 107.355 138.303 107.355 137.403 \
+ 107.243 136.504 107.131 135.604 106.906 133.918 \
+ 106.793 133.131 106.681 132.456 106.456 131.669 \
+ 106.343 130.995 105.894 129.196 105.332 127.622 \
+ 104.769 126.497 104.095 125.598 103.42 125.148 \
+ 102.633 124.923 101.846 125.148 101.059 125.598 \
+ 100.497 126.497 99.822 127.622 99.373 129.196 98.81 \
+ 130.995 98.698 131.669 98.586 132.456 98.473 133.131 \
+ 98.361 133.918 98.248 134.817 98.023 136.504 97.911 \
+ 137.403 97.799 138.303 97.799 139.315 97.686 140.327 \
+ 97.686 141.338 97.574 142.463 97.574 143.587 97.461 \
+ 144.711 97.461 145.836 97.461 147.073 97.461 148.309 \
+ -fill $bg -outline {} -width 1 -tags logo
+
+ $c create polygon 122.309 156.292 126.919 \
+ 156.292 124.67 130.545 122.309 156.292 -fill $bg \
+ -outline {} -width 1 -tags logo
+
+ $c create polygon 142.435 142.688 146.145 \
+ 142.688 147.607 142.35 148.506 140.889 148.731 \
+ 140.327 149.068 138.865 149.181 137.965 149.293 \
+ 137.066 149.405 136.054 149.405 134.93 149.405 \
+ 133.805 149.405 132.456 149.405 131.332 149.405 \
+ 130.208 149.293 129.308 149.181 128.409 148.956 \
+ 127.734 148.056 126.272 146.595 125.823 142.435 \
+ 125.823 142.435 142.688 -fill $bg -outline {} -width \
+ 1 -tags logo
+
+ $c create polygon 111.515 228.924 111.515 \
+ 227.575 111.066 225.664 108.705 221.391 108.255 \
+ 220.042 108.255 219.142 108.255 218.58 108.255 \
+ 218.13 107.805 217.681 106.793 218.58 104.994 \
+ 220.941 104.432 221.953 102.633 224.202 102.183 \
+ 224.764 101.621 225.214 99.822 228.474 97.461 \
+ 233.197 97.461 234.096 97.461 234.995 97.911 235.445 \
+ 98.361 236.007 99.822 236.457 102.633 236.457 \
+ 104.432 235.445 105.894 234.995 106.343 234.546 \
+ 106.793 234.546 107.805 233.646 110.616 230.835 \
+ 111.515 229.824 111.515 229.374 111.515 228.924 \
+ -fill $bg -outline {} -width 1 -tags logo
+
+ $c create polygon 161.211 269.175 160.986 \
+ 267.826 160.649 266.927 160.199 266.477 159.3 \
+ 266.364 158.4 266.477 157.838 266.927 157.613 \
+ 267.826 157.388 269.175 157.388 278.17 157.613 \
+ 279.294 157.838 279.969 159.3 280.981 160.199 \
+ 280.643 160.649 279.969 160.986 279.294 161.211 \
+ 278.17 161.211 269.175 -fill $bg -outline {} -width \
+ 1 -tags logo
+
+ $c create polygon 224.848 273.448 223.836 \
+ 273.448 222.825 273.56 222.15 273.673 221.588 \
+ 273.897 220.913 274.684 220.688 275.809 220.688 \
+ 278.17 220.801 279.294 221.138 279.969 221.7 280.643 \
+ 222.487 280.981 223.612 280.643 224.399 279.969 \
+ 224.736 279.294 224.848 278.17 224.848 273.448 -fill \
+ $bg -outline {} -width 1 -tags logo
+
+ $c create polygon 253.969 269.175 253.744 \
+ 267.826 253.406 266.927 252.732 266.477 251.607 \
+ 266.364 250.708 266.477 250.146 266.927 249.696 \
+ 269.175 249.696 272.548 253.969 272.548 253.969 \
+ 269.175 -fill $bg -outline {} -width 1 -tags logo
+
+}
+
+#***********************************************************************
+# %PROCEDURE: LoadConnectionInfo
+# %ARGUMENTS:
+# None
+# %RETURNS:
+# Nothing
+# %DESCRIPTION:
+# Loads the connection information into the global ConnectionInfo variable
+#***********************************************************************
+proc LoadConnectionInfo {} {
+ global ConnectionInfoFile ConnectionInfo PasswordFile
+ set ConnectionInfo {}
+ if {![file exists $ConnectionInfoFile]} {
+ return
+ }
+ set problem [catch {
+ set fp [open $ConnectionInfoFile "r"]
+ while {1} {
+ if {[gets $fp line] < 0} {
+ break
+ }
+ set line [string trim $line]
+ if {[string match "#*" $line]} {
+ continue
+ }
+ if {"$line" == ""} {
+ continue
+ }
+ set ConnectionInfo $line
+ break
+ }
+ close $fp
+ } err]
+ if {$problem} {
+ tk_dialog .err Error "Error loading configuration file: $err" error 0 OK
+ }
+ # Try loading and merging passwords if the password file is readable
+ if {![file readable $PasswordFile]} {
+ return
+ }
+
+ set fp [open $PasswordFile "r"]
+ while {1} {
+ if {[gets $fp line] < 0} {
+ break
+ }
+ set line [string trim $line]
+ if {[string match "#*" $line]} {
+ continue
+ }
+ if {"$line" == ""} {
+ continue
+ }
+ set passwords $line
+ break
+ }
+ close $fp
+
+ # Merge passwords
+ foreach thing $passwords {
+ set name [value $thing ConnectionName]
+ set password [value $thing Password]
+ set conn [GetConnection $name]
+ if {"$conn" != ""} {
+ lappend conn Password $password
+ ReplaceConnection $conn
+ }
+ }
+}
+
+#***********************************************************************
+# %PROCEDURE: GetConnection
+# %ARGUMENTS:
+# name -- name of connection
+# %RETURNS:
+# key/value pair listing connection configuration, or "" if not found.
+#***********************************************************************
+proc GetConnection { name } {
+ global ConnectionInfo
+ foreach thing $ConnectionInfo {
+ if {[value $thing ConnectionName] == "$name"} {
+ return $thing
+ }
+ }
+ return ""
+}
+
+
+#***********************************************************************
+# %PROCEDURE: DeleteConnection
+# %ARGUMENTS:
+# name -- name of connection
+# %RETURNS:
+# Nothing, but deletes connection named "$name"
+#***********************************************************************
+proc DeleteConnection { name } {
+ global ConnectionInfo ConfigDir
+ set newInfo {}
+ set found 0
+ foreach thing $ConnectionInfo {
+ if {[value $thing ConnectionName] == "$name"} {
+ set found 1
+ } else {
+ lappend newInfo $thing
+ }
+ }
+ if {!$found} {
+ return
+ }
+ set ConnectionInfo $newInfo
+ SaveConnectionInfo
+
+ # Delete the config file
+ set fname [file join $ConfigDir conf.$name]
+ catch { file delete $fname }
+
+ BuildConnectionMenu
+ if {[GetCurrentConnection] == $name} {
+ if {[llength $ConnectionInfo] == 0} {
+ SwitchConnection ""
+ } else {
+ set name [value [lindex $ConnectionInfo 0] ConnectionName]
+ SwitchConnection $name
+ }
+ }
+}
+
+#***********************************************************************
+# %PROCEDURE: ReplaceConnection
+# %ARGUMENTS:
+# conn -- new name/value pairs
+# %RETURNS:
+# Nothing, but replaces connection in ConnectionInfo. If no such
+# connection exists, appends new connection.
+#***********************************************************************
+proc ReplaceConnection { conn } {
+ global ConnectionInfo
+ set name [value $conn ConnectionName]
+ set newInfo {}
+ set found 0
+ foreach thing $ConnectionInfo {
+ if {[value $thing ConnectionName] == "$name"} {
+ lappend newInfo $conn
+ set found 1
+ } else {
+ lappend newInfo $thing
+ }
+ }
+ if {!$found} {
+ lappend newInfo $conn
+ }
+ set ConnectionInfo $newInfo
+}
+
+proc DeletePPPoEConnection {} {
+ set conn [GetCurrentConnection]
+ if {"$conn" == ""} {
+ return
+ }
+ set ans [tk_dialog .confirm "Confirm Deletion - RP-PPPoE" "Are you sure you wish to delete the connection `$conn'?" warning 0 No Yes]
+ if {$ans} {
+ DeleteConnection $conn
+ }
+}
+
+#***********************************************************************
+# %PROCEDURE: CreateMainDialog
+# %ARGUMENTS:
+# None
+# %RETURNS:
+# Nothing
+# %DESCRIPTION:
+# Creates the main window
+#***********************************************************************
+proc CreateMainDialog {} {
+ global ConnectionInfoFile
+ global ConnectionInfo
+ global Admin
+ wm title . "RP-PPPoE"
+ wm iconname . "PPPoE"
+ frame .f1
+ label .l1 -text "Connection: "
+ menubutton .m1 -text "" -indicatoron 1 -menu .m1.menu -relief raised
+ menu .m1.menu -tearoff 0
+ pack .l1 .m1 -in .f1 -side left -expand 0 -fill x
+ canvas .c -width 40 -height 20
+ pack .c -in .f1 -side left -expand 0 -fill none
+
+ # Draw the LED's
+ .c create rectangle 10 1 30 8 -outline "#808080" -fill "#A0A0A0" -tags xmitrect
+ .c create rectangle 10 10 30 18 -outline "#808080" -fill "#A0A0A0" -tags recvrect
+
+ frame .buttons
+ button .start -text "Start" -command "StartPPPoEConnection"
+ button .stop -text "Stop" -command "StopPPPoEConnection"
+ button .exit -text "Exit" -command "exit"
+ canvas .graph -width 1 -height 1
+ if {[file writable $ConnectionInfoFile]} {
+ set Admin 1
+ pack .f1 -side top -expand 1 -fill both
+ pack .buttons -side top -expand 0 -fill x
+ button .delete -text "Delete" -command "DeletePPPoEConnection"
+ button .new -text "New Connection..." -command "NewPPPoEConnection"
+ button .props -text "Properties..." -command "EditConnectionProps"
+ pack .graph -in .f1 -side left -expand 1 -fill both
+ pack .start .stop .delete .props .new .exit -in .buttons -side left -expand 0 -fill none
+ } else {
+ set Admin 0
+ pack .f1 -side top -expand 0 -fill x
+ pack .buttons -side top -expand 1 -fill both
+ pack .start .stop .exit -in .buttons -side left -expand 0 -fill none
+ pack .graph -in .buttons -side left -expand 1 -fill both
+ }
+
+ LoadConnectionInfo
+ BuildConnectionMenu
+ # If no connections exist, pop up new connection dialog
+ if {[llength $ConnectionInfo] == 0} {
+ SwitchConnection ""
+ if {$Admin} {
+ update idletasks
+ NewPPPoEConnection
+ } else {
+ tk_dialog .note Note "Note: There are no connections defined. You must run this program as root to define connections" warning 0 OK
+ }
+ } else {
+ set con [lindex $ConnectionInfo 0]
+ set name [value $con ConnectionName]
+ SwitchConnection $name
+ }
+}
+
+#***********************************************************************
+# %PROCEDURE: GetCurrentConnection
+# %ARGUMENTS:
+# None
+# %RETURNS:
+# The name of the current connection in the GUI.
+#***********************************************************************
+proc GetCurrentConnection {} {
+ .m1 cget -text
+}
+
+#***********************************************************************
+# %PROCEDURE: value
+# %ARGUMENTS:
+# lst -- a list of key/value pairs
+# key -- key we're looking for
+# %RETURNS:
+# value corresponding to $key, or "" if not found.
+#***********************************************************************
+proc value { lst key } {
+ set idx [lsearch -exact $lst $key]
+ if {$idx >= 0} {
+ return [lindex $lst [expr $idx+1]]
+ }
+ return ""
+}
+
+#***********************************************************************
+# %PROCEDURE: SwitchConnection
+# %ARGUMENTS:
+# name -- new connection name
+# %DESCRIPTION:
+# Makes $name the active connection
+#***********************************************************************
+proc SwitchConnection { name } {
+ .m1 configure -text $name
+ SetButtonStates
+ UpdateConnectionState 0
+}
+
+#***********************************************************************
+# %PROCEDURE: EditConnectionProps
+# %ARGUMENTS:
+# None
+# %DESCRIPTION:
+# Pops up edit window for current connection
+#***********************************************************************
+proc EditConnectionProps {} {
+ global ConnectionInfo
+ set conn [GetCurrentConnection]
+ NewPPPoEConnection $conn
+}
+
+#***********************************************************************
+# %PROCEDURE: FillConnectionGui
+# %ARGUMENTS:
+# w -- connection property GUI
+# name -- name of connection
+# %DESCRIPTION:
+# Fills GUI with values corresponding to $name.
+#***********************************************************************
+proc FillConnectionGui { w name } {
+ global ConnectionInfo
+ set found [GetConnection $name]
+ if {"$found" != ""} {
+ ListToSetupGui $w $found
+ }
+}
+
+#***********************************************************************
+# %PROCEDURE: BuildConnectionMenu
+# %ARGUMENTS:
+# None
+# %RETURNS:
+# Nothing
+# %DESCRIPTION:
+# Builds the connection menu
+#***********************************************************************
+proc BuildConnectionMenu {} {
+ global ConnectionInfo
+ .m1.menu delete 0 end
+ foreach connection $ConnectionInfo {
+ set name [value $connection ConnectionName]
+ .m1.menu add command -label $name -command [list SwitchConnection $name]
+ }
+ .m1.menu add separator
+ .m1.menu add command -label "User's Manual" -command Help
+}
+
+#***********************************************************************
+# %PROCEDURE: SetButtonStates
+# %ARGUMENTS:
+# None
+# %RETURNS:
+# Nothing
+# %DESCRIPTION:
+# Enables or disables buttons, as appropriate
+#***********************************************************************
+proc SetButtonStates {} {
+ global Admin
+ set conn [GetCurrentConnection]
+ if {"$conn" == ""} {
+ .start configure -state disabled
+ .stop configure -state disabled
+ catch {
+ .delete configure -state disabled
+ .props configure -state disabled
+ .new configure -state normal
+ }
+ } else {
+ foreach {startstop updown interface} [GetConnectionStatus $conn] {break}
+ if {"$startstop" == "started"} {
+ .start configure -state disabled
+ .stop configure -state normal
+ } else {
+ .start configure -state normal
+ .stop configure -state disabled
+ }
+ catch {
+ .delete configure -state normal
+ .props configure -state normal
+ .new configure -state normal
+ }
+ if {!$Admin} {
+ set ok [value [GetConnection $conn] NonrootOK]
+ if {!$ok} {
+ .start configure -state disabled
+ .stop configure -state disabled
+ }
+ }
+ }
+}
+
+#***********************************************************************
+# %PROCEDURE: GetEthernetInterfaces
+# %ARGUMENTS:
+# None
+# %RETURNS:
+# A list of Ethernet interfaces
+#***********************************************************************
+proc GetEthernetInterfaces {} {
+ set ifs {}
+ set fp [open "|/sbin/ifconfig" "r"]
+ while {[gets $fp line] >= 0} {
+ if {[regexp {^eth[0-9]+} $line eth]} {
+ lappend ifs $eth
+ }
+ }
+ return $ifs
+}
+
+#***********************************************************************
+# %PROCEDURE: StartPPPoEConnection
+# %ARGUMENTS:
+# None
+# %RETURNS:
+# Nothing
+# %DESCRIPTION:
+# Starts currently-selected PPPoE connection.
+#***********************************************************************
+proc StartPPPoEConnection {} {
+ global Wrapper
+ global StartState
+ global UpdateToken
+
+ set conn [GetCurrentConnection]
+ if {"$conn" == ""} {
+ return
+ }
+
+ if {"$UpdateToken" != ""} {
+ after cancel $UpdateToken
+ set UpdateToken ""
+ }
+
+ catch { unset StartState }
+ set StartState(chars) ""
+ set StartState(status) ""
+ set StartState(msg) ""
+ set StartState(flip) 0
+
+ set fp [open "|$Wrapper start $conn" "r"]
+
+ # Set fileevent
+ fileevent $fp readable [list StartFPReadable $fp]
+
+ LockGui $fp
+ vwait StartState(status)
+ UnlockGui
+
+ if {$StartState(status) == "failed"} {
+ tk_dialog .err Error "Error starting connection: $StartState(msg)" error 0 OK
+ }
+ SetButtonStates
+ UpdateConnectionState 0
+}
+
+proc LockGui { fp } {
+ .start configure -state disabled
+ .stop configure -state normal -command [list AbortConnection $fp]
+ .exit configure -state disabled
+ .m1 configure -state disabled
+ grab set .stop
+}
+
+proc UnlockGui {} {
+ .start configure -state normal
+ .stop configure -state disabled -command StopPPPoEConnection
+ .exit configure -state normal
+ .m1 configure -state normal
+ grab release .stop
+}
+
+proc AbortConnection { fp } {
+ global StartState
+ catch { StopPPPoEConnection }
+ catch { close $fp }
+ set StartState(msg) "Connection aborted by user"
+ set StartState(status) "failed"
+}
+
+#***********************************************************************
+# %PROCEDURE: StartFPReadable
+# %ARGUMENTS:
+# fp -- file handle
+# %RETURNS:
+# Nothing
+# %DESCRIPTION:
+# Called when the "adsl-start" file handle is readable.
+#***********************************************************************
+proc StartFPReadable { fp } {
+ global StartState
+ set char [read $fp 1]
+ if {$char == ""} {
+ set uhoh [catch {close $fp} err]
+ if {$uhoh} {
+ set StartState(status) "failed"
+ set StartState(msg) $err
+ } else {
+ set StartState(status) "succeeded"
+ }
+ return
+ }
+ append StartState(chars) $char
+ if {$StartState(flip)} {
+ ConnectionStateDown
+ } else {
+ ConnectionStateOff
+ }
+ set StartState(flip) [expr 1 - $StartState(flip)]
+}
+
+#***********************************************************************
+# %PROCEDURE: StopPPPoEConnection
+# %ARGUMENTS:
+# None
+# %RETURNS:
+# Nothing
+# %DESCRIPTION:
+# Stops currently-selected PPPoE connection.
+#***********************************************************************
+proc StopPPPoEConnection {} {
+ global Wrapper
+ set conn [GetCurrentConnection]
+ if {"$conn" == ""} {
+ return
+ }
+ set fp [open "|$Wrapper stop $conn" "r"]
+ while {1} {
+ set char [read $fp 1]
+ if {"$char" == ""} {
+ break;
+ }
+ }
+ set uhoh [catch {close $fp} err]
+ if {$uhoh} {
+ # Ignore a common error
+ if {![string match "*appears to have died*" $err]} {
+ tk_dialog .err Error "Error stopping connection: $err" error 0 OK
+ }
+ }
+ SetButtonStates
+ UpdateConnectionState 0
+}
+
+#***********************************************************************
+# %PROCEDURE: NewPPPoEConnection
+# %ARGUMENTS:
+# name -- if supplied, we're editing the existing connection "name"
+# %RETURNS:
+# Nothing
+# %DESCRIPTION:
+# Creates a new PPPoE connection
+#***********************************************************************
+proc NewPPPoEConnection {{name ""}} {
+ set w .newcon
+ if {[winfo exists $w]} {
+ wm deiconify $w
+ raise $w
+ return
+ }
+
+ toplevel $w
+ if {"$name" == ""} {
+ wm title $w "New Connection - RP-PPPoE"
+ wm iconname $w "New Connection"
+ } else {
+ wm title $w "Edit Connection - RP-PPPoE"
+ wm iconname $w "Edit Connection"
+ }
+ wm withdraw $w
+
+ tabnotebook_create $w.tn
+ set basic [tabnotebook_page $w.tn "Basic"]
+ set interface [tabnotebook_page $w.tn "NIC and DNS"]
+ set opts [tabnotebook_page $w.tn "Options"]
+ set advanced [tabnotebook_page $w.tn "Advanced"]
+
+ # ----------- BASIC PAGE -------------
+ label $w.lconName -text "Connection Name: " -anchor e
+ if {"$name" != ""} {
+ label $w.conName -text $name -anchor w
+ } else {
+ entry $w.conName -width 15
+ RegisterHelpWindow $w.lconName "Enter a name for this connection. It can contain letters, numbers, undescores and the minus-sign." $w.help
+ RegisterHelpWindow $w.conName "Enter a name for this connection. It can contain letters, numbers, undescores and the minus-sign." $w.help
+ }
+
+ label $w.luser -text "User Name: " -anchor e
+ entry $w.user -width 15
+ RegisterHelpWindow $w.luser "Enter your user name. Do not add a domain-name after the user name." $w.help
+ RegisterHelpWindow $w.user "Enter your user name. Do not add a domain-name after the user name." $w.help
+
+ label $w.lnet -text "Network: " -anchor e
+ entry $w.network -width 15
+ RegisterHelpWindow $w.lnet "Some ISP's require you to enter their domain-name here (e.g. \"sympatico.ca\")." $w.help
+ RegisterHelpWindow $w.network "Some ISP's require you to enter their domain-name here (e.g. \"sympatico.ca\")." $w.help
+
+ label $w.lpass -text "Password: " -anchor e
+ entry $w.pass -width 15 -show "*"
+ RegisterHelpWindow $w.lpass "Enter your password." $w.help
+ RegisterHelpWindow $w.pass "Enter your password." $w.help
+
+ grid $w.lconName $w.conName -in $basic -sticky nsew
+ grid $w.luser $w.user -in $basic -sticky nsew
+ grid $w.lnet $w.network -in $basic -sticky nsew
+ grid $w.lpass $w.pass -in $basic -sticky nsew
+ grid columnconfigure $basic 1 -weight 1
+
+ # ----------- INTERFACES PAGE -------------
+ set ifs {}
+ catch {set ifs [GetEthernetInterfaces]}
+
+ label $w.lifname -text "Ethernet Interface: " -anchor e
+ entry $w.ifname -width 8
+ RegisterHelpWindow $w.lifname "Enter Ethernet interface to which DSL modem is attached." $w.help
+ RegisterHelpWindow $w.ifname "Enter Ethernet interface to which DSL modem is attached." $w.help
+
+ if {[llength $ifs] > 0} {
+ menubutton $w.ifmb -relief raised -text "..." -menu $w.ifmb.menu
+ RegisterHelpWindow $w.ifmb "Browse detected Ethernet interface names." $w.help
+ menu $w.ifmb.menu -tearoff 0
+ foreach if $ifs {
+ $w.ifmb.menu add command -label $if -command "$w.ifname delete 0 end; $w.ifname insert end [list $if]"
+ }
+ grid $w.lifname $w.ifname $w.ifmb -in $interface -sticky nsew
+ } else {
+ grid $w.lifname $w.ifname - -in $interface -sticky nsew
+ }
+
+ label $w.ldns -text "DNS Setup: " -anchor e
+ menubutton $w.dns -text "From Server" -menu $w.dns.menu -relief raised -indicatoron 1
+ menu $w.dns.menu -tearoff 0
+ foreach thing {"From Server" "Specify" "Do not Adjust"} {
+ $w.dns.menu add command -label $thing -command [list SetDNSOption $w $thing]
+ }
+ RegisterHelpWindow $w.ldns "DNS server options:\n'From Server' - Let PPPoE server specify DNS servers\n'Specify' - Enter IP addresses of DNS servers yourself\n'Do not Adjust' - Leave your DNS setup alone." $w.help
+ RegisterHelpWindow $w.dns "DNS server options:\n'From Server' - Let PPPoE server specify DNS servers\n'Specify' - Enter IP addresses of DNS servers yourself\n'Do not Adjust' - Leave your DNS setup alone." $w.help
+
+ label $w.ldns1 -text "Primary DNS: " -anchor e
+ entry $w.dns1 -width 16
+ RegisterHelpWindow $w.ldns1 "Enter the IP address of the primary DNS server." $w.help
+ RegisterHelpWindow $w.dns1 "Enter the IP address of the primary DNS server." $w.help
+ label $w.ldns2 -text "Secondary DNS: " -anchor e
+ entry $w.dns2 -width 16
+ RegisterHelpWindow $w.ldns2 "Enter the IP address of the secondary DNS server." $w.help
+ RegisterHelpWindow $w.dns2 "Enter the IP address of the secondary DNS server." $w.help
+
+ SetDNSOption $w "From Server"
+ grid $w.ldns $w.dns - -in $interface -sticky nsew
+ grid $w.ldns1 $w.dns1 - -in $interface -sticky nsew
+ grid $w.ldns2 $w.dns2 - -in $interface -sticky nsew
+
+ # If only one Ethernet interface, select it by default
+ if {[llength $ifs] == 1} {
+ $w.ifname insert end [lindex $ifs 0]
+ }
+
+ grid columnconfigure $interface 1 -weight 1
+ # ----------- OPTS PAGE -------------
+ checkbutton $w.nonroot -text "Allow use by non-root users" -variable OPTS(nonroot) -anchor w
+ RegisterHelpWindow $w.nonroot "If enabled, ordinary users can start and stop this connection." $w.help
+ checkbutton $w.sync -text "Use synchronous PPP" -variable OPTS(sync) -anchor w
+ RegisterHelpWindow $w.sync "Use synchronous PPP (recommended -- easier on the CPU.)" $w.help
+ label $w.lfw -text "Firewalling: " -anchor e
+ if {[llength $ifs] == 1} {
+ set defaultFW "Stand-Alone"
+ } else {
+ set defaultFW "Masquerading"
+ }
+ menubutton $w.fw -text $defaultFW -menu $w.fw.menu -indicatoron 1 -relief raised
+ menu $w.fw.menu -tearoff 0
+ foreach type {Stand-Alone Masquerading None} {
+ $w.fw.menu add command -label $type -command [list $w.fw configure -text $type]
+ }
+
+ RegisterHelpWindow $w.lfw "Firewalling options:\nStand-Alone - A stand-alone machine.\nMasquerading - A gateway machine used for Internet sharing.\nNone - Use if you already have your own firewall rules or want to run servers." $w.help
+ RegisterHelpWindow $w.fw "Firewalling options:\nStand-Alone - A stand-alone machine.\nMasquerading - A gateway machine used for Internet sharing.\nNone - Use if you already have your own firewall rules or want to run servers." $w.help
+ grid $w.nonroot - -in $opts -sticky nsew
+ grid $w.sync - -in $opts -sticky nsew
+ grid $w.lfw $w.fw -in $opts -sticky nsw
+ grid columnconfigure $opts 1 -weight 1
+
+ # ----------- ADVANCED PAGE -------------
+ label $w.lsn -text "Service-Name: " -anchor e
+ entry $w.servicename -width 24
+
+ label $w.lac -text "AC-Name: " -anchor e
+ entry $w.acname -width 24
+
+ RegisterHelpWindow $w.lac "Enter access concentrator name if required. Most ISPs do not require this; try leaving it blank." $w.help
+ RegisterHelpWindow $w.acname "Enter access concentrator name if required. Most ISPs do not require this; try leaving it blank." $w.help
+ grid $w.lsn $w.servicename -in $advanced -sticky nsew
+ grid $w.lac $w.acname -in $advanced -sticky nsew
+ RegisterHelpWindow $w.lsn "Enter service name if required. Most ISPs do not require this; try leaving it blank." $w.help
+ RegisterHelpWindow $w.servicename "Enter service name if required. Most ISPs do not require this; try leaving it blank." $w.help
+
+ grid columnconfigure $advanced 1 -weight 1
+
+ # ----------- BUTTONS -------------
+ frame $w.buttons
+ button $w.ok -text "OK" -command [list NewPPPoEConnectionOK $name $w]
+ button $w.cancel -text "Cancel" -command [list destroy $w]
+ pack $w.ok $w.cancel -in $w.buttons -expand 0 -fill none -side left
+
+ pack $w.tn -side top -expand 1 -fill both
+
+ text $w.help -width 60 -wrap word -state disabled -height 6
+ pack $w.help -side top -expand 0 -fill both
+ pack $w.buttons -side top -expand 0 -fill x
+
+ # If we're editing existing connection, fill GUI with current values
+ if {"$name" != ""} {
+ FillConnectionGui $w $name
+ }
+ wm deiconify $w
+ update idletasks
+ raise $w
+}
+
+#***********************************************************************
+# %PROCEDURE: SetDNSOption
+# %ARGUMENTS:
+# w -- connection-editing window
+# opt -- value of DNS option
+# %RETURNS:
+# Nothing
+# %DESCRIPTION:
+# Adjusts GUI for specified option
+#***********************************************************************
+proc SetDNSOption { w opt } {
+ $w.dns configure -text $opt
+ if {"$opt" == "Specify"} {
+ $w.dns1 configure -state normal -background white
+ $w.dns2 configure -state normal -background white
+ } else {
+ $w.dns1 configure -state disabled -background "#d9d9d9"
+ $w.dns2 configure -state disabled -background "#d9d9d9"
+ }
+}
+
+# ----------------------------------------------------------------------
+# Tabbed notebook code from "Effective Tcl/Tk Programming"
+# ----------------------------------------------------------------------
+# EXAMPLE: tabnotebook that can dial up pages
+# ----------------------------------------------------------------------
+# Effective Tcl/Tk Programming
+# Mark Harrison, DSC Communications Corp.
+# Michael McLennan, Bell Labs Innovations for Lucent Technologies
+# Addison-Wesley Professional Computing Series
+# ======================================================================
+# Copyright (c) 1996-1997 Lucent Technologies Inc. and Mark Harrison
+# ======================================================================
+
+option add *Tabnotebook.tabs.background #666666 widgetDefault
+option add *Tabnotebook.margin 6 widgetDefault
+option add *Tabnotebook.tabColor #a6a6a6 widgetDefault
+option add *Tabnotebook.activeTabColor #d9d9d9 widgetDefault
+option add *Tabnotebook.tabFont \
+ -*-helvetica-bold-r-normal--*-120-* widgetDefault
+
+proc tabnotebook_create {win} {
+ global tnInfo
+
+ frame $win -class Tabnotebook
+ canvas $win.tabs -highlightthickness 0
+ pack $win.tabs -fill x
+
+ notebook_create $win.notebook
+ pack $win.notebook -expand yes -fill both
+
+ set tnInfo($win-tabs) ""
+ set tnInfo($win-current) ""
+ set tnInfo($win-pending) ""
+ return $win
+}
+
+proc tabnotebook_page {win name} {
+ global tnInfo
+
+ set page [notebook_page $win.notebook $name]
+ lappend tnInfo($win-tabs) $name
+
+ if {$tnInfo($win-pending) == ""} {
+ set id [after idle [list tabnotebook_refresh $win]]
+ set tnInfo($win-pending) $id
+ }
+ return $page
+}
+
+proc tabnotebook_refresh {win} {
+ global tnInfo
+
+ $win.tabs delete all
+
+ set margin [option get $win margin Margin]
+ set color [option get $win tabColor Color]
+ set font [option get $win tabFont Font]
+ set x 2
+ set maxh 0
+
+ foreach name $tnInfo($win-tabs) {
+ set id [$win.tabs create text \
+ [expr $x+$margin+2] [expr -0.5*$margin] \
+ -anchor sw -text $name -font $font \
+ -tags [list $name]]
+
+ set bbox [$win.tabs bbox $id]
+ set wd [expr [lindex $bbox 2]-[lindex $bbox 0]]
+ set ht [expr [lindex $bbox 3]-[lindex $bbox 1]]
+ if {$ht > $maxh} {
+ set maxh $ht
+ }
+
+ $win.tabs create polygon 0 0 $x 0 \
+ [expr $x+$margin] [expr -$ht-$margin] \
+ [expr $x+$margin+$wd] [expr -$ht-$margin] \
+ [expr $x+$wd+2*$margin] 0 \
+ 2000 0 2000 10 0 10 \
+ -outline black -fill $color \
+ -tags [list $name tab tab-$name]
+
+ $win.tabs raise $id
+
+ $win.tabs bind $name <ButtonPress-1> \
+ [list tabnotebook_display $win $name]
+
+ set x [expr $x+$wd+2*$margin]
+ }
+ set height [expr $maxh+2*$margin]
+ $win.tabs move all 0 $height
+
+ $win.tabs configure -width $x -height [expr $height+4]
+
+ if {$tnInfo($win-current) != ""} {
+ tabnotebook_display $win $tnInfo($win-current)
+ } else {
+ tabnotebook_display $win [lindex $tnInfo($win-tabs) 0]
+ }
+ set tnInfo($win-pending) ""
+}
+
+proc tabnotebook_display {win name} {
+ global tnInfo
+
+ notebook_display $win.notebook $name
+
+ set normal [option get $win tabColor Color]
+ $win.tabs itemconfigure tab -fill $normal
+
+ set active [option get $win activeTabColor Color]
+ $win.tabs itemconfigure tab-$name -fill $active
+ $win.tabs raise $name
+
+ set tnInfo($win-current) $name
+}
+
+# ----------------------------------------------------------------------
+# EXAMPLE: simple notebook that can dial up pages
+# ----------------------------------------------------------------------
+# Effective Tcl/Tk Programming
+# Mark Harrison, DSC Communications Corp.
+# Michael McLennan, Bell Labs Innovations for Lucent Technologies
+# Addison-Wesley Professional Computing Series
+# ======================================================================
+# Copyright (c) 1996-1997 Lucent Technologies Inc. and Mark Harrison
+# ======================================================================
+
+option add *Notebook.borderWidth 2 widgetDefault
+option add *Notebook.relief sunken widgetDefault
+
+proc notebook_create {win} {
+ global nbInfo
+
+ frame $win -class Notebook
+ pack propagate $win 0
+
+ set nbInfo($win-count) 0
+ set nbInfo($win-pages) ""
+ set nbInfo($win-current) ""
+ return $win
+}
+
+proc notebook_page {win name} {
+ global nbInfo
+
+ set page "$win.page[incr nbInfo($win-count)]"
+ lappend nbInfo($win-pages) $page
+ set nbInfo($win-page-$name) $page
+
+ frame $page
+
+ if {$nbInfo($win-count) == 1} {
+ after idle [list notebook_display $win $name]
+ }
+ return $page
+}
+
+proc notebook_display {win name} {
+ global nbInfo
+
+ set page ""
+ if {[info exists nbInfo($win-page-$name)]} {
+ set page $nbInfo($win-page-$name)
+ } elseif {[winfo exists $win.page$name]} {
+ set page $win.page$name
+ }
+ if {$page == ""} {
+ error "bad notebook page \"$name\""
+ }
+
+ notebook_fix_size $win
+
+ if {$nbInfo($win-current) != ""} {
+ pack forget $nbInfo($win-current)
+ }
+ pack $page -expand yes -fill both
+ set nbInfo($win-current) $page
+}
+
+proc notebook_fix_size {win} {
+ global nbInfo
+
+ update idletasks
+
+ set maxw 0
+ set maxh 0
+ foreach page $nbInfo($win-pages) {
+ set w [winfo reqwidth $page]
+ if {$w > $maxw} {
+ set maxw $w
+ }
+ set h [winfo reqheight $page]
+ if {$h > $maxh} {
+ set maxh $h
+ }
+ }
+ set bd [$win cget -borderwidth]
+ set maxw [expr $maxw+2*$bd]
+ set maxh [expr $maxh+2*$bd]
+ $win configure -width $maxw -height $maxh
+}
+
+#***********************************************************************
+# %PROCEDURE: SetupGuiToList
+# %ARGUMENTS:
+# w -- the PPPoE connection setup window
+# %RETURNS:
+# A list of (name value) pairs for the connection.
+# %DESCRIPTION:
+# Reads values from the GUI; makes a list.
+#***********************************************************************
+proc SetupGuiToList { w } {
+ global OPTS
+ set ans {}
+ if {[catch {lappend ans ConnectionName [$w.conName get]}]} {
+ lappend ans ConnectionName [$w.conName cget -text]
+ }
+ lappend ans UserName [$w.user get]
+ lappend ans NetworkName [$w.network get]
+ lappend ans Password [$w.pass get]
+ lappend ans Interface [$w.ifname get]
+ lappend ans DNSType [$w.dns cget -text]
+ lappend ans DNS1 [$w.dns1 get]
+ lappend ans DNS2 [$w.dns2 get]
+ lappend ans NonrootOK $OPTS(nonroot)
+ lappend ans Sync $OPTS(sync)
+ lappend ans FirewallType [$w.fw cget -text]
+ lappend ans ServiceName [$w.servicename get]
+ lappend ans ACName [$w.acname get]
+
+ # Validate
+ set name [value $ans ConnectionName]
+ if {![regexp -nocase {^[-a-z0-9_]+$} $name]} {
+ error "Connection name must be non-blank and contain only letters, digits, `_' and `-'"
+ }
+
+ # Check DNS
+ set type [value $ans DNSType]
+ if {"$type" == "Specify"} {
+ set dns [value $ans DNS1]
+ if {![regexp {[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+} "$dns"]} {
+ error "Primary DNS entry must consist of four dot-separated decimal numbers"
+ }
+ set dns [value $ans DNS2]
+ if {"$dns" != "" && ![regexp {[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+} "$dns"]} {
+ error "Secondary DNS entry must consist of four dot-separated decimal numbers"
+ }
+ }
+ return $ans
+}
+
+#***********************************************************************
+# %PROCEDURE: ListToSetupGui
+# %ARGUMENTS:
+# w -- the PPPoE connection setup window
+# lst -- a list of name/value pairs
+# %RETURNS:
+# Nothing
+# %DESCRIPTION:
+# Updates GUI to reflect lst
+#***********************************************************************
+proc ListToSetupGui { w lst } {
+ global OPTS
+ foreach {key value} $lst {
+ switch -exact -- $key {
+ ConnectionName {
+ catch {
+ $w.conName delete 0 end
+ $w.conName insert end $value
+ }
+ catch {
+ $w.conName configure -text $value
+ }
+ }
+ UserName {
+ $w.user delete 0 end
+ $w.user insert end $value
+ }
+ NetworkName {
+ $w.network delete 0 end
+ $w.network insert end $value
+ }
+ Password {
+ $w.pass delete 0 end
+ $w.pass insert end $value
+ }
+ Interface {
+ $w.ifname delete 0 end
+ $w.ifname insert end $value
+ }
+ DNSType {
+ SetDNSOption $w $value
+ }
+ DNS1 {
+ set oldstate [$w.dns1 cget -state]
+ $w.dns1 configure -state normal
+ $w.dns1 delete 0 end
+ $w.dns1 insert end $value
+ $w.dns1 configure -state $oldstate
+ }
+ DNS2 {
+ set oldstate [$w.dns2 cget -state]
+ $w.dns2 configure -state normal
+ $w.dns2 delete 0 end
+ $w.dns2 insert end $value
+ $w.dns2 configure -state $oldstate
+ }
+ NonrootOK {
+ set OPTS(nonroot) $value
+ }
+ Sync {
+ set OPTS(sync) $value
+ }
+ FirewallType {
+ $w.fw configure -text $value
+ }
+ ServiceName {
+ $w.servicename delete 0 end
+ $w.servicename insert end $value
+ }
+ ACName {
+ $w.acname delete 0 end
+ $w.acname insert end $value
+ }
+ }
+ }
+}
+
+proc NewPPPoEConnectionOK { name w } {
+ if {[catch {set conn [SetupGuiToList $w]} err]} {
+ tk_dialog .err "Invalid Parameters" "$err" error 0 OK
+ return
+ }
+ if {"$name" == ""} {
+ set name [value $conn ConnectionName]
+ set tmp [GetConnection $name]
+ if {"$tmp" != ""} {
+ tk_dialog .err "Connection Exists" "The connection `$name' already exists. Pick another name." error 0 OK
+ return
+ }
+ }
+ ReplaceConnection $conn
+ SaveConnectionInfo
+ BuildConnectionMenu
+ SwitchConnection $name
+ destroy $w
+}
+
+proc SaveConnectionInfo {} {
+ global ConnectionInfo ConnectionInfoFile PasswordFile
+ set fp [open "$ConnectionInfoFile.new" "w"]
+ puts $fp "# RP-PPPoE GUI Configuration Information."
+ puts $fp "# This file may *look* human-editable, but it is NOT."
+ puts $fp "# So, you with the text editor: Keep away from this file."
+ puts $fp "#"
+ set expunged {}
+ set passwords {}
+ foreach thing $ConnectionInfo {
+ set name [value $thing ConnectionName]
+ set password [value $thing Password]
+ set pwindex [lsearch -exact $thing Password]
+ set safe [lreplace $thing $pwindex [expr $pwindex+1]]
+ set pwd [list ConnectionName $name Password $password]
+ lappend expunged $safe
+ lappend passwords $pwd
+ }
+ puts $fp $expunged
+ close $fp
+ set fp [open "$PasswordFile.new" "w"]
+ exec chmod 600 "$PasswordFile.new"
+ puts $fp "# RP-PPPoE GUI Configuration Information."
+ puts $fp "# This file may *look* human-editable, but it is NOT."
+ puts $fp "# So, you with the text editor: Keep away from this file."
+ puts $fp "#"
+ puts $fp $passwords
+ close $fp
+ file rename -force "$ConnectionInfoFile.new" "$ConnectionInfoFile"
+ file rename -force "$PasswordFile.new" "$PasswordFile"
+
+ # Generate config files for adsl-start for each connection
+ foreach thing $ConnectionInfo {
+ GenerateConfigFile $thing
+ }
+
+ # Now update /etc/ppp/pap-secrets and /etc/ppp/chap-secrets
+ foreach thing $ConnectionInfo {
+ GenerateSecretsEntry $thing
+ }
+}
+
+#***********************************************************************
+# %PROCEDURE: ReadShellEscapedWord
+# %ARGUMENTS:
+# str -- a string
+# %RETURNS:
+# A two-element list -- the first element is a shell-escaped word
+# extracted from $str, just the way pppd parses /etc/ppp/pap-secrets.
+# The second element is the remaining portion of $str
+#***********************************************************************
+proc ReadShellEscapedWord { str } {
+ set ans {}
+ set rest $str
+
+ # Chew up leading spaces
+ set rest [string trimleft $rest]
+
+ # If first char is a quote, read until a quote
+ if {"[string index $rest 0]" == "\""} {
+ set rest [string range $rest 1 end]
+ set nextquote [string first "\"" $rest]
+ # If no following quote, pretend we haven't seen a quote, I guess.
+ if {$nextquote >= 0} {
+ set ans [string range $rest 0 [expr $nextquote-1]]
+ set rest [string range $rest [expr $nextquote+1] end]
+ return [list $ans $rest]
+ }
+ }
+
+ # Not a quote; chew through the string until an unescaped space
+ while {[string length $rest] > 0} {
+ set char [string index $rest 0]
+ set rest [string range $rest 1 end]
+ # Sneaky test for whitespace in Tcl 8.0
+ if {"[string trim $char]" == ""} {
+ return [list $ans $rest]
+ }
+ if {"$char" == "\\"} {
+ set char [string index $rest 0]
+ set rest [string range $rest 1 end]
+ }
+ append ans $char
+ }
+ return [list $ans $rest]
+}
+
+
+#***********************************************************************
+# %PROCEDURE: GenerateSecretsEntry
+# %ARGUMENTS:
+# conn -- a connection key/value list
+# %RETURNS:
+# Nothing
+# %DESCRIPTION:
+# Adds entries to /etc/ppp/pap-secrets and /etc/ppp/chap-secrets.
+#***********************************************************************
+proc GenerateSecretsEntry { conn } {
+ set user [value $conn UserName]
+ set net [value $conn NetworkName]
+ set password [value $conn Password]
+ if {"$net" != ""} {
+ set user "$user@$net"
+ }
+ GenerateSecretsEntryForFile $user $password "/etc/ppp/pap-secrets"
+ GenerateSecretsEntryForFile $user $password "/etc/ppp/chap-secrets"
+}
+
+#***********************************************************************
+# %PROCEDURE: GenerateSecretsEntryForFile
+# %ARGUMENTS:
+# user -- user name
+# password -- password
+# fname -- file to add entry to.
+# %RETURNS:
+# Nothing
+# %DESCRIPTION:
+# Adds entries to /etc/ppp/pap-secrets or /etc/ppp/chap-secrets.
+#***********************************************************************
+proc GenerateSecretsEntryForFile { user password fname } {
+ # Copy $fname to $fname.new
+ set out [open "$fname.new" "w"]
+ exec chmod go-rwx "$fname.new"
+ if {[file exists $fname]} {
+ set in [open $fname "r"]
+ while {[gets $in line] >= 0} {
+ set trimmed [string trim $line]
+ if {"$trimmed" == ""} {
+ puts $out $line
+ continue
+ }
+ if {[string match "#*" $trimmed]} {
+ puts $out $line
+ continue
+ }
+
+ # Read the user name off the line; copy it unless it's our
+ # user name.
+ foreach {word dummy} [ReadShellEscapedWord $line] {break}
+ if {$word != $user} {
+ puts $out $line
+ }
+ }
+ close $in
+ }
+
+ # Now add our line
+ set user [ShellEscape $user]
+ set password [ShellEscape $password]
+ puts $out "$user\t*\t$password\t*"
+ close $out
+ file rename -force $fname.new $fname
+}
+
+#***********************************************************************
+# %PROCEDURE: ShellEscape
+# %ARGUMENTS:
+# str
+# %RETURNS:
+# A version of $str with shell meta-characters escaped
+#***********************************************************************
+proc ShellEscape { str } {
+ set ans ""
+ foreach char [split $str ""] {
+ if {[string first $char "01234567890ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_+=-@./"] >= 0} {
+ append ans $char
+ } else {
+ append ans "\\$char"
+ }
+ }
+ return $ans
+}
+
+
+#***********************************************************************
+# %PROCEDURE: GenerateConfigFile
+# %ARGUMENTS:
+# conn -- a connection key/value list
+# %RETURNS:
+# Nothing
+# %DESCRIPTION:
+# Generates a configuration file for adsl-start and friends under
+# /etc/ppp/rp-pppoe-gui
+#***********************************************************************
+proc GenerateConfigFile { conn } {
+ global ConfigDir
+ set name [value $conn ConnectionName]
+ set fname [file join $ConfigDir conf.$name]
+ set fp [open "$fname.new" w]
+ puts $fp "# Configuration file for connection `$name'."
+ puts $fp "# Automatically generated. Do not edit by hand."
+ puts $fp ""
+ foreach {var val} $conn {
+ switch -exact $var {
+ UserName {
+ set net [value $conn NetworkName]
+ if {"$net" != ""} {
+ set user "$val@$net"
+ } else {
+ set user "$val"
+ }
+ puts $fp [ShellEscape "USER=$user"]
+ }
+ Interface {
+ puts $fp [ShellEscape "ETH=$val"]
+ }
+ DNSType {
+ if {"$val" == "From Server"} {
+ puts $fp "DNSTYPE=SERVER"
+ puts $fp "USEPEERDNS=yes"
+ } elseif {"$val" == "Specify"} {
+ puts $fp "DNSTYPE=SPECIFY"
+ puts $fp "USEPEERDNS=no"
+ } else {
+ puts $fp "DNSTYPE=NOCHANGE"
+ puts $fp "USEPEERDNS=no"
+ }
+ }
+ DNS1 {
+ puts $fp [ShellEscape "DNS1=$val"]
+ }
+ DNS2 {
+ puts $fp [ShellEscape "DNS2=$val"]
+ }
+ NonrootOK {
+ if {$val} {
+ puts $fp "NONROOT=OK"
+ }
+ }
+ ACName {
+ puts $fp [ShellEscape "ACNAME=$val"]
+ }
+ ServiceName {
+ puts $fp [ShellEscape "SERVICENAME=$val"]
+ }
+ FirewallType {
+ if {"$val" == "None"} {
+ puts $fp "FIREWALL=NONE"
+ } elseif {"$val" == "Masquerading"} {
+ puts $fp "FIREWALL=MASQUERADE"
+ } else {
+ puts $fp "FIREWALL=STANDALONE"
+ }
+ }
+ Sync {
+ if {$val} {
+ puts $fp "SYNCHRONOUS=yes"
+ } else {
+ puts $fp "SYNCHRONOUS=no"
+ }
+ }
+ }
+ }
+ puts $fp "CONNECT_TIMEOUT=30"
+ puts $fp "CONNECT_POLL=1"
+ puts $fp "FORCEPING=\".\""
+ puts $fp "PIDFILE=/var/run/adsl-$name.pid"
+ puts $fp "CLAMPMSS=1412"
+ puts $fp "LCP_INTERVAL=20"
+ puts $fp "LCP_FAILURE=3"
+ puts $fp "PPPOE_TIMEOUT=80"
+ puts $fp "LINUX_PLUGIN="
+ puts $fp "DEMAND=no"
+ close $fp
+ file rename -force "$fname.new" "$fname"
+}
+
+#***********************************************************************
+# %PROCEDURE: GetConnectionStatus
+# %ARGUMENTS:
+# conn -- connection name
+# %RETURNS:
+# A three-element list:
+# {started/stopped up/down if}
+# If first element is "started", then connection has been started.
+# If second element is "up", then connection is up.
+# If connection is up, third element is PPP interface.
+#***********************************************************************
+proc GetConnectionStatus { conn } {
+ set pidfile "/var/run/adsl-$conn.pid"
+
+ # Check for PID file
+ if {![file readable $pidfile]} {
+ return {stopped down ""}
+ }
+ set fp [open $pidfile "r"]
+ gets $fp pid
+ close $fp
+
+ # Check if process is dead
+ if {![file exists "/proc/$pid"]} {
+ # The pppd might still be running... doh...
+ if {![file readable "$pidfile.pppd"]} {
+ return {stopped down ""}
+ }
+ set fp [open "$pidfile.pppd" "r"]
+ gets $fp pid
+ close $fp
+ if {![file exists "/proc/$pid"]} {
+ return {stopped down ""}
+ }
+ }
+
+ # Now get PID of pppd
+ if {![file readable "$pidfile.pppd"]} {
+ return {started down ""}
+ }
+ set fp [open "$pidfile.pppd" "r"]
+ gets $fp pid
+ close $fp
+
+ # Find interface to which it corresponds
+ set pppdfiles [glob -nocomplain "/var/run/ppp*.pid"]
+ set found {}
+ foreach file $pppdfiles {
+ set fp [open $file "r"]
+ gets $fp ifpid
+ close $fp
+ if {$ifpid == $pid} {
+ set found [file rootname [file tail $file]]
+ break
+ }
+ }
+ if {"$found" == ""} {
+ return {started down ""}
+ }
+ return [list started up $found]
+}
+
+#***********************************************************************
+# %PROCEDURE: UpdateConnectionState
+# %ARGUMENTS:
+# fromAfter -- if 1, was called from an "after" callback.
+# %RETURNS:
+# Nothing
+# %DESCRIPTION:
+# Updates the "LED" displays; periodically reschedules itself to keep
+# updating display.
+#***********************************************************************
+proc UpdateConnectionState {{fromAfter 1}} {
+ global UpdateToken
+ global Packets
+ global Bytes
+ global UpdateInterval
+ global MeasureTime
+ if {$fromAfter} {
+ set UpdateToken ""
+ }
+
+ set conn [GetCurrentConnection]
+ if {"$conn" == ""} {
+ ConnectionStateOff
+ ResetGraph
+ if {"$UpdateToken" != ""} {
+ after cancel $UpdateToken
+ set UpdateToken {}
+ }
+ return
+ }
+
+ foreach {startstop updown interface} [GetConnectionStatus $conn] {break}
+ if {"$startstop" == "stopped"} {
+ ConnectionStateOff
+ ResetGraph
+ } elseif {"$updown" == "down"} {
+ ConnectionStateDown
+ ResetGraph
+ } else {
+ # Get the packet counts
+ set found 0
+ set fp [open "/proc/net/dev" "r"]
+ while {[gets $fp line] >= 0} {
+ if {![string match "*$interface:*" $line]} {
+ continue
+ }
+ set colon [string first ":" $line]
+ if {$colon < 0} {
+ continue
+ }
+ set line [string range $line [expr $colon+1] end]
+ set found 1
+ set MeasureTime [clock seconds]
+ break
+ }
+ close $fp
+ if {$found} {
+ foreach {rbytes rpacks rerrs rdrop rfifo rframe rcomp rmulti tbytes tpacks} $line {break}
+ if {!$fromAfter} {
+ set Packets(in) $rpacks
+ set Packets(out) $tpacks
+ set Bytes(in) $rbytes
+ set Bytes(out) $tbytes
+ ConnectionStateUp
+ ResetGraph
+ } else {
+ if {$rpacks != $Packets(in)} {
+ ConnectionReceiveActive
+ } else {
+ ConnectionReceiveUp
+ }
+ if {$tpacks != $Packets(out)} {
+ ConnectionTransmitActive
+ } else {
+ ConnectionTransmitUp
+ }
+ set Packets(in) $rpacks
+ set Packets(out) $tpacks
+ set Bytes(in) $rbytes
+ set Bytes(out) $tbytes
+ UpdateGraph
+ }
+ } else {
+ ConnectionStateUp
+ ResetGraph
+ }
+ }
+ if {"$UpdateToken" == ""} {
+ set UpdateToken [after $UpdateInterval UpdateConnectionState]
+ }
+ if {$fromAfter} {
+ SetButtonStates
+ }
+}
+
+proc ConnectionStateOff {} {
+ .c itemconfigure xmitrect -fill "#A0A0A0"
+ .c itemconfigure recvrect -fill "#A0A0A0"
+}
+
+proc ConnectionStateDown {} {
+ .c itemconfigure xmitrect -fill "#A00000"
+ .c itemconfigure recvrect -fill "#A00000"
+}
+
+proc ConnectionStateUp {} {
+ .c itemconfigure xmitrect -fill "#00D000"
+ .c itemconfigure recvrect -fill "#00D000"
+}
+
+proc ConnectionTransmitActive {} {
+ .c itemconfigure xmitrect -fill "#FFFF00"
+}
+
+proc ConnectionTransmitUp {} {
+ .c itemconfigure xmitrect -fill "#00D000"
+}
+
+proc ConnectionReceiveActive {} {
+ .c itemconfigure recvrect -fill "#FFFF00"
+}
+
+proc ConnectionReceiveUp {} {
+ .c itemconfigure recvrect -fill "#00D000"
+}
+
+proc ResetGraph {} {
+ global GraphPoints
+ set GraphPoints(in) {}
+ set GraphPoints(out) {}
+ set GraphPoints(times) {}
+ .graph delete all
+ UpdateGraph
+}
+
+proc UpdateGraph {} {
+ global GraphPoints Bytes UpdateInterval MeasureTime
+ lappend GraphPoints(times) $MeasureTime
+ lappend GraphPoints(in) $Bytes(in)
+ lappend GraphPoints(out) $Bytes(out)
+
+ set w [winfo width .graph]
+ set w2 [expr $w/2]
+
+ set h [winfo height .graph]
+ set toChop [expr [llength $GraphPoints(in)] - $w2 - 1]
+ if {$toChop > 0} {
+ set GraphPoints(in) [lrange $GraphPoints(in) $toChop end]
+ }
+ set toChop [expr [llength $GraphPoints(out)] - $w2 - 1]
+ if {$toChop > 0} {
+ set GraphPoints(out) [lrange $GraphPoints(out) $toChop end]
+ }
+ set toChop [expr [llength $GraphPoints(times)] - $w2 - 1]
+ if {$toChop > 0} {
+ set GraphPoints(times) [lrange $GraphPoints(times) $toChop end]
+ }
+
+ set prev [lindex $GraphPoints(in) 0]
+ set incoords {}
+ set outcoords {}
+ set inmax 0
+ set outmax 0
+ foreach thing [lrange $GraphPoints(in) 1 end] {
+ set diff [expr $thing - $prev]
+ set prev $thing
+ lappend incoords $diff
+ if {$diff > $inmax} {
+ set inmax $diff
+ }
+ }
+
+ set prev [lindex $GraphPoints(out) 0]
+ foreach thing [lrange $GraphPoints(out) 1 end] {
+ set diff [expr $thing - $prev]
+ set prev $thing
+ lappend outcoords $diff
+ if {$diff > $outmax} {
+ set outmax $diff
+ }
+ }
+
+ if {$inmax == 0} { set inmax 1 }
+ if {$outmax == 0} { set outmax 1 }
+ # Draw the transmit line
+ set x 0
+ set hh [expr $h-4]
+ set scaled {}
+ foreach thing $outcoords {
+ lappend scaled $x [expr double($h) - 2 - (double($hh) * double($thing) / double($outmax))]
+ incr x
+ }
+
+ .graph delete all
+ if {[llength $scaled] >= 4} {
+ eval ".graph create line $scaled -fill #A00000"
+ set bits [expr 8.0 * ([lindex $GraphPoints(out) end] - [lindex $GraphPoints(out) 0])]
+ set timediff [expr [lindex $GraphPoints(times) end] - [lindex $GraphPoints(times) 0]]
+ if {$timediff != 0} {
+ set bps [Pretty [expr double($bits) / $timediff]]
+ .graph create text 2 2 -anchor nw -font fixed -text "$bps"
+ }
+ }
+
+ # Draw the receive line
+ set x $w2
+ set scaled {}
+ foreach thing $incoords {
+ lappend scaled $x [expr double($h) - 2 - (double($hh) * double($thing) / double($inmax))]
+ incr x
+ }
+
+ if {[llength $scaled] >= 4} {
+ eval ".graph create line $scaled -fill #00A000"
+ set bits [expr 8.0 * ([lindex $GraphPoints(in) end] - [lindex $GraphPoints(in) 0])]
+ set timediff [expr [lindex $GraphPoints(times) end] - [lindex $GraphPoints(times) 0]]
+ if {$timediff != 0} {
+ set bps [Pretty [expr double($bits) / $timediff]]
+ .graph create text [expr $w2+2] 2 -anchor nw -font fixed -text "$bps"
+ }
+ }
+}
+
+proc Pretty { n } {
+ if {$n < 0} {
+ return "***"
+ }
+ if {$n < 1000} {
+ return [format "%.1f" $n]
+ }
+ set n [expr $n/1000.0]
+ if {$n < 1000} {
+ return [format "%.1fk" $n]
+ }
+ set n [expr $n/1000.0]
+ if {$n < 1000} {
+ return [format "%.1fM" $n]
+ }
+ set n [expr $n/1000.0]
+ return [format "%.1fG" $n]
+}
+
+#***********************************************************************
+# %PROCEDURE: Help
+# %ARGUMENTS:
+# None
+# %RETURNS:
+# Nothing
+# %DESCRIPTION:
+# Opens help page
+#***********************************************************************
+proc Help {} {
+ if {![file readable /usr/share/rp-pppoe-gui/tkpppoe.html]} {
+ tk_dialog .err Error "Help file '/usr/share/rp-pppoe-gui/tkpppoe.html' is not installed" error 0 OK
+ return
+ }
+ catch { exec /bin/sh -c "netscape -remote 'openURL(/usr/share/rp-pppoe-gui/tkpppoe.html)' || netscape /usr/share/rp-pppoe-gui/tkpppoe.html" > /dev/null 2>/dev/null & }
+}
+
+
+
+#***********************************************************************
+# %PROCEDURE: doLogo
+# %ARGUMENTS:
+# None
+# %RETURNS:
+# Nothing
+# %DESCRIPTION:
+# Does the logo thing
+#***********************************************************************
+proc doLogo {} {
+ global AlreadyRunFile ConfigDir
+ if {[file exists $AlreadyRunFile]} {
+ return
+ }
+ catch { file mkdir $ConfigDir }
+ catch { close [open $AlreadyRunFile "w"] }
+ canvas .c -width 374 -height 286 -bg #FFFFCC
+ pack .c
+ drawLogo .c #FFFFCC
+
+ # Funky effect
+ .c create text 4 4 -anchor nw -text "Welcome to RP-PPPoE" \
+ -fill red -font {-family times -size -24 -weight bold} -tags pppoe
+ .c lower pppoe
+
+ .c move logo -300 0
+
+ update idletasks
+
+ for {set i 0} {$i < 15} {incr i} {
+ .c move logo 20 0
+ update idletasks
+ after 25
+ }
+
+ .c create text 4 28 -anchor nw -text "http://www.roaringpenguin.com" \
+ -fill red -font {-family courier -size -14 -weight bold}
+ update idletasks
+ after 2500
+}
+
+doLogo
+catch { destroy .c }
+
+# Try creating an empty config file if none exists
+if {![file readable $ConnectionInfoFile]} {
+ catch { file mkdir $ConfigDir }
+ catch {
+ set fp [open $ConnectionInfoFile "w"]
+ close $fp
+ }
+}
+
+CreateMainDialog
diff --git a/mdk-stage1/rp-pppoe/gui/wrapper.c b/mdk-stage1/rp-pppoe/gui/wrapper.c
new file mode 100644
index 000000000..901ed9005
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/gui/wrapper.c
@@ -0,0 +1,234 @@
+/* -*-Mode: C;-*- */
+
+/***********************************************************************
+*
+* wrapper.c
+*
+* C wrapper designed to run SUID root for controlling PPPoE connections.
+*
+* Copyright (C) 2001 by Roaring Penguin Software Inc.
+*
+***********************************************************************/
+
+static char const RCSID[] =
+"$Id: wrapper.c 195724 2001-06-11 13:49:39Z gc $";
+
+#define _SVID_SOURCE 1 /* For putenv */
+#define _POSIX_SOURCE 1 /* For fileno */
+#define _BSD_SOURCE 1 /* For setreuid */
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#define CONN_NAME_LEN 64
+#define LINELEN 512
+
+static char const *adsl_start = ADSL_START_PATH;
+static char const *adsl_stop = ADSL_STOP_PATH;
+static char const *adsl_status = ADSL_STATUS_PATH;
+
+/**********************************************************************
+ *%FUNCTION: PathOK
+ *%ARGUMENTS:
+ * fname -- a file name.
+ *%RETURNS:
+ * 1 if path to fname is secure; 0 otherwise.
+ *%DESCRIPTION:
+ * Makes sure ownership/permissions of file and parent directories
+ * are safe.
+ **********************************************************************/
+static int
+PathOK(char const *fname)
+{
+ char path[LINELEN];
+ struct stat buf;
+ char const *slash;
+
+ if (strlen(fname) > LINELEN) {
+ fprintf(stderr, "Pathname '%s' too long\n", fname);
+ return 0;
+ }
+
+ /* Must be absolute path */
+ if (*fname != '/') {
+ fprintf(stderr, "Unsafe path '%s' not absolute\n", fname);
+ return 0;
+ }
+
+ /* Check root directory */
+ if (stat("/", &buf) < 0) {
+ perror("stat");
+ return 0;
+ }
+ if (buf.st_uid) {
+ fprintf(stderr, "SECURITY ALERT: Root directory (/) not owned by root\n");
+ return 0;
+ }
+ if (buf.st_mode & (S_IWGRP | S_IWOTH)) {
+ fprintf(stderr, "SECURITY ALERT: Root directory (/) writable by group or other\n");
+ return 0;
+ }
+
+ /* Check each component */
+ slash = fname;
+
+ while(*slash) {
+ slash = strchr(slash+1, '/');
+ if (!slash) {
+ slash = fname + strlen(fname);
+ }
+ memcpy(path, fname, slash-fname);
+ path[slash-fname] = 0;
+ if (stat(path, &buf) < 0) {
+ perror("stat");
+ return 0;
+ }
+ if (buf.st_uid) {
+ fprintf(stderr, "SECURITY ALERT: '%s' not owned by root\n", path);
+ return 0;
+ }
+
+ if (buf.st_mode & (S_IWGRP | S_IWOTH)) {
+ fprintf(stderr, "SECURITY ALERT: '%s' writable by group or other\n",
+ path);
+ return 0;
+ }
+ }
+ return 1;
+}
+
+/**********************************************************************
+ *%FUNCTION: CleanEnvironment
+ *%ARGUMENTS:
+ * envp -- environment passed to main
+ *%RETURNS:
+ * Nothing
+ *%DESCRIPTION:
+ * Deletes all environment variables; makes safe environment
+ **********************************************************************/
+static void
+CleanEnvironment(char *envp[])
+{
+ envp[0] = NULL;
+ putenv("PATH=/bin:/usr/bin:/sbin:/usr/sbin");
+}
+
+/**********************************************************************
+ *%FUNCTION: main
+ *%ARGUMENTS:
+ * argc, argv -- usual suspects
+ * Usage: pppoe-wrapper {start|stop|status} {connection_name}
+ *%RETURNS:
+ * Whatever adsl-start, adsl-stop or adsl-status returns.
+ *%DESCRIPTION:
+ * Runs adsl-start, adsl-stop or adsl-status on given connection if
+ * non-root users are allowed to do it.
+ **********************************************************************/
+int
+main(int argc, char *argv[])
+{
+ int amRoot;
+ char *cp;
+ char fname[64+CONN_NAME_LEN];
+ char line[LINELEN+1];
+ int allowed = 0;
+
+ FILE *fp;
+
+ extern char **environ;
+
+ /* Clean out environment */
+ CleanEnvironment(environ);
+
+ /* Are we root? */
+ amRoot = (getuid() == 0);
+
+ /* Validate arguments */
+ if (argc != 3) {
+ fprintf(stderr, "Usage: %s {start|stop|status} connection_name\n",
+ argv[0]);
+ exit(1);
+ }
+
+ if (strcmp(argv[1], "start") &&
+ strcmp(argv[1], "stop") &&
+ strcmp(argv[1], "status")) {
+ fprintf(stderr, "Usage: %s {start|stop|status} connection_name\n",
+ argv[0]);
+ exit(1);
+ }
+
+ /* Connection name can be at most CONN_NAME_LEN chars; alpha, num, underscore */
+ if (strlen(argv[2]) > CONN_NAME_LEN) {
+ fprintf(stderr, "%s: Connection name '%s' too long.\n",
+ argv[0], argv[2]);
+ exit(1);
+ }
+
+ for (cp = argv[2]; *cp; cp++) {
+ if (!strchr("abcdefghijklmnopqrstuvwxyz"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "0123456789_-", *cp)) {
+ fprintf(stderr, "%s: Connection name '%s' contains illegal character '%c'\n", argv[0], argv[2], *cp);
+ exit(1);
+ }
+ }
+
+ /* Open the connection file */
+ sprintf(fname, "/etc/ppp/rp-pppoe-gui/conf.%s", argv[2]);
+ /* Check path sanity */
+ if (!PathOK(fname)) {
+ exit(1);
+ }
+
+ fp = fopen(fname, "r");
+ if (!fp) {
+ fprintf(stderr, "%s: Could not open '%s': %s\n",
+ argv[0], fname, strerror(errno));
+ exit(1);
+ }
+
+ /* Check if non-root users can control it */
+ if (amRoot) {
+ allowed = 1;
+ } else {
+ while (!feof(fp)) {
+ if (!fgets(line, LINELEN, fp)) {
+ break;
+ }
+ if (!strcmp(line, "NONROOT=OK\n")) {
+ allowed = 1;
+ break;
+ }
+ }
+ }
+ fclose(fp);
+
+ if (!allowed) {
+ fprintf(stderr, "%s: Non-root users are not permitted to control connection '%s'\n", argv[0], argv[2]);
+ exit(1);
+ }
+
+ /* Become root with setuid() to defeat is-root checks in shell scripts */
+ if (setreuid(0, 0) < 0) {
+ perror("setreuid");
+ exit(1);
+ }
+
+ /* It's OK -- do it. */
+ if (!strcmp(argv[1], "start")) {
+ if (!PathOK(adsl_start)) exit(1);
+ execl(adsl_start, "adsl-start", fname, NULL);
+ } else if (!strcmp(argv[1], "stop")) {
+ if (!PathOK(adsl_stop)) exit(1);
+ execl(adsl_stop, "adsl-stop", fname, NULL);
+ } else {
+ if (!PathOK(adsl_status)) exit(1);
+ execl(adsl_status, "adsl-status", fname, NULL);
+ }
+ fprintf(stderr, "%s: execl: %s\n", argv[0], strerror(errno));
+ exit(1);
+}
diff --git a/mdk-stage1/rp-pppoe/man/adsl-connect.8 b/mdk-stage1/rp-pppoe/man/adsl-connect.8
new file mode 100644
index 000000000..1ace558d0
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/man/adsl-connect.8
@@ -0,0 +1,66 @@
+.\" $Id: adsl-connect.8 195724 2001-06-11 13:49:39Z gc $
+.TH ADSL-CONNECT 8 "21 February 2000"
+.UC 4
+.SH NAME
+adsl-connect \- Shell script to manage a PPPoE link
+
+.SH SYNOPSIS
+.B adsl-connect \fR[\fIconfig_file\fR]
+.P
+.B adsl-connect \fR\fIinterface user\fR [\fIconfig_file\fR]
+
+
+.SH DESCRIPTION
+\fBadsl-connect\fR is a shell script which manages an ADSL connection
+using the Roaring Penguin user-space PPPoE client. If you omit
+\fIconfig_file\fR, the default file \fB/etc/ppp/pppoe.conf\fR is used.
+If you supply \fIinterface\fR and \fIuser\fR, then they override the
+Ethernet interface and user-name settings in the configuration file.
+.P
+Note that normally, you should \fInot\fR invoke \fBadsl-connect\fR
+directly. Instead, use \fBadsl-start\fR to bring up the ADSL connection.
+.P
+\fBadsl-connect\fR first reads a configuration file. It then brings
+up a PPPoE connection. If the connection ever drops, a message is logged
+to syslog, and \fBadsl-connect\fR re-establishes the connection. In addition,
+each time the connection is dropped or cannot be established,
+\fBadsl-connect\fR executes the script \fB/etc/ppp/adsl-lost\fR if it
+exists and is executable.
+
+.P
+The shell script \fBadsl-stop\fR causes \fBadsl-connect\fR to break out
+of its loop, bring the connection down, and exit.
+
+.SH TECHNICAL DETAILS
+\fBadsl-connect\fR uses the following shell variables from the
+configuration file:
+
+.TP
+.B ETH
+The Ethernet interface connected to the ADSL modem (for example, eth0).
+
+.TP
+.B USER
+The ADSL user-id (for example, b1xxnxnx@sympatico.ca).
+
+.TP
+.B PIDFILE
+A file in which to write the process-ID of the adsl-connect process
+(for example, \fB/var/run/pppoe.pid\fR). Two additional files
+($PIDFILE.pppd and $PIDFILE.pppoe) hold the process-ID's of the
+\fBpppd\fR and \fBpppoe\fR processes, respectively.
+
+.P
+By using different configuration files with different PIDFILE
+settings, you can manage multiple PPPoE connections. Just specify the
+configuration file as an argument to \fBadsl-start\fR and
+\fBadsl-stop\fR.
+
+.SH AUTHOR
+\fBadsl-connect\fR was written by David F. Skoll <dfs@roaringpenguin.com>.
+
+The \fBpppoe\fR home page is \fIhttp://www.roaringpenguin.com/pppoe/\fR.
+
+.SH SEE ALSO
+pppoe(8), adsl-start(8), adsl-stop(8), pppd(8), pppoe.conf(5), adsl-setup(8), adsl-status(8), pppoe-sniff(8), pppoe-server(8), pppoe-relay(8)
+
diff --git a/mdk-stage1/rp-pppoe/man/adsl-setup.8 b/mdk-stage1/rp-pppoe/man/adsl-setup.8
new file mode 100644
index 000000000..f4a620af8
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/man/adsl-setup.8
@@ -0,0 +1,23 @@
+.\" $Id: adsl-setup.8 195724 2001-06-11 13:49:39Z gc $
+.TH ADSL-SETUP 8 "21 February 2000"
+.UC 4
+.SH NAME
+adsl-setup \- Shell script to configure Roaring Penguin PPPoE client
+.SH SYNOPSIS
+.B adsl-setup
+
+.SH DESCRIPTION
+\fBadsl-setup\fR is a shell script which prompts you for various pieces
+of information and sets up an /etc/ppp/pppoe.conf configuration script
+for the \fBadsl-start\fR, \fBadsl-stop\fR and \fBadsl-connect\fR scripts.
+
+.SH AUTHOR
+\fBadsl-setup\fR was written by David F. Skoll <dfs@roaringpenguin.com>.
+
+The \fBpppoe\fR home page is \fIhttp://www.roaringpenguin.com/pppoe/\fR.
+
+.SH SEE ALSO
+pppoe(8), adsl-start(8), adsl-stop(8), adsl-connect(8), pppd(8),
+pppoe.conf(5), adsl-status(8), pppoe-sniff(8), pppoe-relay(8),
+pppoe-server(8)
+
diff --git a/mdk-stage1/rp-pppoe/man/adsl-start.8 b/mdk-stage1/rp-pppoe/man/adsl-start.8
new file mode 100644
index 000000000..13a23ba14
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/man/adsl-start.8
@@ -0,0 +1,27 @@
+.\" $Id: adsl-start.8 195724 2001-06-11 13:49:39Z gc $
+.TH ADSL-START 8 "21 February 2000"
+.UC 4
+.SH NAME
+adsl-start \- Shell script to bring up a PPPoE link
+.SH SYNOPSIS
+.B adsl-start \fR[\fIconfig_file\fR]
+.P
+.B adsl-start \fR\fIinterface user\fR [\fIconfig_file\fR]
+
+.SH DESCRIPTION
+\fBadsl-start\fR is a shell script which starts the Roaring Penguin
+user-space PPPoE client. If you omit \fIconfig_file\fR, the default
+file \fB/etc/ppp/pppoe.conf\fR is used. If you supply
+\fIinterface\fR and \fIuser\fR, then they override the Ethernet interface
+and user-name settings in the configuration file.
+
+.SH AUTHOR
+\fBadsl-start\fR was written by David F. Skoll <dfs@roaringpenguin.com>.
+
+The \fBpppoe\fR home page is \fIhttp://www.roaringpenguin.com/pppoe/\fR.
+
+.SH SEE ALSO
+pppoe(8), adsl-stop(8), adsl-connect(8), pppd(8), pppoe.conf(5),
+adsl-setup(8), adsl-status(8), pppoe-sniff(8), pppoe-relay(8),
+pppoe-server(8)
+
diff --git a/mdk-stage1/rp-pppoe/man/adsl-status.8 b/mdk-stage1/rp-pppoe/man/adsl-status.8
new file mode 100644
index 000000000..44f2093e1
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/man/adsl-status.8
@@ -0,0 +1,25 @@
+.\" $Id: adsl-status.8 195724 2001-06-11 13:49:39Z gc $
+.TH ADSL-STATUS 8 "16 March 2000"
+.UC 4
+.SH NAME
+adsl-status \- Shell script to report on status of PPPoE link
+.SH SYNOPSIS
+.B adsl-status \fR[\fIconfig_file\fR]
+
+.SH DESCRIPTION
+\fBadsl-status\fR is a shell script which checks the status of the
+PPPoE link established by the Roaring Penguin user-space PPPoE client.
+If you omit \fIconfig_file\fR, the default file
+\fB/etc/ppp/pppoe.conf\fR is used.
+
+.SH AUTHOR
+\fBadsl-status\fR was written by David F. Skoll <dfs@roaringpenguin.com>.
+
+The \fBpppoe\fR home page is \fIhttp://www.roaringpenguin.com/pppoe/\fR.
+
+.SH SEE ALSO
+pppoe(8), adsl-start(8), adsl-connect(8), pppd(8), pppoe.conf(5),
+adsl-setup(8), adsl-stop(8), pppoe-sniff(8), pppoe-relay(8),
+pppoe-server(8)
+
+
diff --git a/mdk-stage1/rp-pppoe/man/adsl-stop.8 b/mdk-stage1/rp-pppoe/man/adsl-stop.8
new file mode 100644
index 000000000..776d95d12
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/man/adsl-stop.8
@@ -0,0 +1,21 @@
+.\" $Id: adsl-stop.8 195724 2001-06-11 13:49:39Z gc $
+.TH ADSL-STOP 8 "21 February 2000"
+.UC 4
+.SH NAME
+adsl-stop \- Shell script to shut down a PPPoE link
+.SH SYNOPSIS
+.B adsl-stop \fR[\fIconfig_file\fR]
+
+.SH DESCRIPTION
+\fBadsl-stop\fR is a shell script which stops the Roaring Penguin
+user-space PPPoE client. If you omit \fIconfig_file\fR, the default
+file \fB/etc/ppp/pppoe.conf\fR is used.
+
+.SH AUTHOR
+\fBadsl-stop\fR was written by David F. Skoll <dfs@roaringpenguin.com>.
+
+The \fBpppoe\fR home page is \fIhttp://www.roaringpenguin.com/pppoe/\fR.
+
+.SH SEE ALSO
+pppoe(8), adsl-start(8), adsl-connect(8), pppd(8), pppoe.conf(5), adsl-setup(8), adsl-status(8), pppoe-sniff(8), pppoe-relay(8), pppoe-server(8)
+
diff --git a/mdk-stage1/rp-pppoe/man/pppoe-relay.8 b/mdk-stage1/rp-pppoe/man/pppoe-relay.8
new file mode 100644
index 000000000..6a458fbd6
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/man/pppoe-relay.8
@@ -0,0 +1,124 @@
+.\" $Id: pppoe-relay.8 195724 2001-06-11 13:49:39Z gc $
+.TH PPPOE-RELAY 8 "26 January 2001"
+.\""
+.UC 4
+.SH NAME
+pppoe-relay \- user-space PPPoE relay agent.
+.SH SYNOPSIS
+.B pppoe-relay \fR[\fIoptions\fR]
+
+.SH DESCRIPTION
+\fBpppoe-relay\fR is a user-space relay agent for PPPoE
+(Point-to-Point Protocol over Ethernet) for Linux. \fBpppoe-relay\fR
+works in concert with the \fBpppoe\fR client and \fBpppoe-server\fR
+server. See the OPERATION section later in this manual for
+details on how \fBpppoe-relay\fR works.
+
+.SH OPTIONS
+.TP
+.B \-S \fIinterface\fR
+Adds the Ethernet interface \fIinterface\fR to the list of interfaces
+managed by \fBpppoe-relay\fR. Only PPPoE servers may be connected to
+this interface.
+
+.TP
+.B \-C \fIinterface\fR
+Adds the Ethernet interface \fIinterface\fR to the list of interfaces
+managed by \fBpppoe-relay\fR. Only PPPoE clients may be connected to
+this interface.
+
+.TP
+.B \-B \fIinterface\fR
+Adds the Ethernet interface \fIinterface\fR to the list of interfaces
+managed by \fBpppoe-relay\fR. Both PPPoE clients and servers may be
+connected to this interface.
+
+.TP
+.B \-n \fInum\fR
+Allows at most \fInum\fR concurrent PPPoE sessions. If not specified,
+the default is 5000. \fInum\fR can range from 1 to 65534.
+
+.TP
+.B \-i \fItimeout\fR
+Specifies the session idle timeout. If both peers in a session are idle
+for more than \fItimeout\fR seconds, the session is terminated.
+If \fItimeout\fR is specified as zero, sessions will never be terminated
+because of idleness.
+
+Note that the idle-session expiry routine is never run more frequently than
+every 30 seconds, so the timeout is approximate. The default value for
+\fItimeout\fR is 600 seconds (10 minutes.)
+
+.TP
+.B \-F
+The \fB\-F\fR option causes \fBpppoe-relay\fR \fInot\fR to fork into the
+background; instead, it remains in the foreground.
+
+.TP
+.B \-h
+The \fB\-h\fR option prints a brief usage message and exits.
+
+.SH OPERATION
+
+\fBpppoe-relay\fR listens for incoming PPPoE PADI frames on all interfaces
+specified with \fB-B\fR or \fB-C\fR options. When a PADI frame appears,
+\fBpppoe-relay\fR adds a Relay-Session-ID tag and broadcasts the PADI
+on all interfaces specified with \fB-B\fR or \fB-S\fR options (except the
+interface on which the frame arrived.)
+
+Any PADO frames received are relayed back to the client which sent the
+PADI (assuming they contain valid Relay-Session-ID tags.) Likewise,
+PADR frames from clients are relayed back to the matching access
+concentrator.
+
+When a PADS frame is received, \fBpppoe-relay\fR enters the two peers'
+MAC addresses and session-ID's into a hash table. (The session-ID seen
+by the access concentrator may be different from that seen by the client;
+\fBpppoe-relay\fR must renumber sessions to avoid the possibility of duplicate
+session-ID's.) Whenever either peer sends a session frame, \fBpppoe-relay\fR
+looks up the session entry in the hash table and relays the frame to
+the correct peer.
+
+When a PADT frame is received, \fBpppoe-relay\fR relays it to the peer
+and deletes the session entry from its hash table.
+
+If a client and server crash (or frames are lost), PADT frames may never
+be sent, and \fBpppoe-relay\fR's hash table can fill up with stale sessions.
+Therefore, a session-cleaning routine runs periodically, and removes old
+sessions from the hash table. A session is considered "old" if no traffic
+has been seen within \fItimeout\fR seconds. When a session is deleted because
+of a timeout, a PADT frame is sent to each peer to make certain that they
+are aware the session has been killed.
+
+.SH EXAMPLE INVOCATIONS
+
+.nf
+pppoe-relay -C eth0 -S eth1
+.fi
+
+The example above relays frames between PPPoE clients on the eth0 network
+and PPPoE servers on the eth1 network.
+
+.nf
+pppoe-relay -B eth0 -B eth1
+.fi
+
+This example is a transparent relay -- frames are relayed between any mix
+of clients and servers on the eth0 and eth1 networks.
+
+.nf
+pppoe-relay -S eth0 -C eth1 -C eth2 -C eth3
+.fi
+
+This example relays frames between servers on the eth0 network and
+clients on the eth1, eth2 and eth3 networks.
+
+.SH AUTHORS
+\fBpppoe-relay\fR was written by David F. Skoll <dfs@roaringpenguin.com>.
+
+The \fBpppoe\fR home page is \fIhttp://www.roaringpenguin.com/pppoe/\fR.
+
+.SH SEE ALSO
+adsl-start(8), adsl-stop(8), adsl-connect(8), pppd(8), pppoe.conf(5),
+pppoe(8), adsl-setup(8), adsl-status(8), pppoe-sniff(8), pppoe-server(8)
+
diff --git a/mdk-stage1/rp-pppoe/man/pppoe-server.8 b/mdk-stage1/rp-pppoe/man/pppoe-server.8
new file mode 100644
index 000000000..8e7c3f794
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/man/pppoe-server.8
@@ -0,0 +1,123 @@
+.\" $Id: pppoe-server.8 195724 2001-06-11 13:49:39Z gc $
+.TH PPPOE-SERVER 8 "3 July 2000"
+.\""
+.UC 4
+.SH NAME
+pppoe-server \- user-space PPPoE server
+.SH SYNOPSIS
+.B pppoe-server \fR[\fIoptions\fR]
+
+.SH DESCRIPTION
+\fBpppoe-server\fR is a user-space server for PPPoE (Point-to-Point Protocol
+over Ethernet) for Linux and other UNIX systems. \fBpppoe-server\fR works in
+concert with the \fBpppoe\fR client to respond to PPPoE discovery packets
+and set up PPPoE sessions.
+
+.SH OPTIONS
+.TP
+.B \-F
+The \fB\-F\fR option causes \fBpppoe-server\fR not to fork and become a
+daemon. The default is to fork and become a daemon.
+
+.TP
+.B \-I \fIinterface\fR
+The \fB\-I\fR option specifies the Ethernet interface to use. Under Linux,
+it is typically \fIeth0\fR or \fIeth1\fR. The interface should be "up"
+before you start \fBpppoe-server\fR, but should \fInot\fR be configured to have
+an IP address.
+
+.TP
+.B \-T \fItimeout\fR
+This option is passed directly to \fBpppoe\fR; see \fBpppoe\fR(8) for
+details.
+
+.TP
+.B \-C \fIac_name\fR
+Specifies which name to report as the access concentrator name. If not
+supplied, the host name is used.
+
+.TP
+.B \-m \fIMSS\fR
+This option is passed directly to \fBpppoe\fR; see \fBpppoe\fR(8) for
+details.
+
+.TP
+.B \-s
+This option is passed directly to \fBpppoe\fR; see \fBpppoe\fR(8) for
+details. In addition, it causes \fBpppd\fR to be invoked with the
+\fIsync\fR option.
+
+.TP
+.B \-L \fIip\fR
+Sets the local IP address. This is passed to spawned \fBpppd\fR processes.
+If not specified, the default is 10.0.0.1.
+
+.TP
+.B \-R \fIip\fR
+Sets the starting remote IP address. As sessions are established,
+IP addresses are assigned starting from \fIip\fR. \fBpppoe-server\fR
+automatically keeps track of the pool of addresses and passes a
+valid remote IP address to \fBpppd\fR. If not specified, a starting address
+of 10.67.15.1 is used.
+
+.TP
+.B \-N \fInum\fR
+Allows at most \fInum\fR concurrent PPPoE sessions. If not specified,
+the default is 64.
+
+.TP
+.B \-p \fIfname\fR
+Reads the specified file \fIfname\fR which is a text file consisting of
+one IP address per line. These IP addresses will be assigned to clients.
+The number of sessions allowed will equal the number of addresses found
+in the file. The \fB\-p\fR option overrides both \fB\-R\fR and \fB\-N\fR.
+
+.TP
+.B \-o \fIoffset\fR
+Instead of numbering PPPoE sessions starting at 1, they will be numbered
+starting at \fIoffset\fR+1. This allows you to run multiple servers on
+a given machine; just make sure that their session numbers do not
+overlap.
+
+.TP
+.B \-f disc:sess
+The \fB\-f\fR option sets the Ethernet frame types for PPPoE discovery
+and session frames. The types are specified as hexadecimal numbers
+separated by a colon. Standard PPPoE uses frame types 8863:8864.
+\fIYou should not use this option\fR unless you are absolutely sure
+the peer you are dealing with uses non-standard frame types.
+
+.TP
+.B \-h
+The \fB\-h\fR option prints a brief usage message and exits.
+
+.SH OPERATION
+
+\fBpppoe-server\fR listens for incoming PPPoE discovery packets. When
+a session is established, it spawns a \fBpppd\fR process. The following
+options are passed to \fBpppd\fR:
+
+.nf
+nodetach noaccomp nobsdcom nodeflate nopcomp novj novjccomp
+default-asyncmap
+.fi
+
+In addition, the local and remote IP address are set based on the
+\fB\-L\fR and \fB\-R\fR options. The \fBpty\fR option is supplied along
+with a \fBpppoe\fR command to initiate the PPPoE session. Finally,
+additional \fBpppd\fR options can be placed in the file
+\fB/etc/ppp/pppoe-server-options\fR (which must exist, even if it is just
+empty!)
+
+Note that \fBpppoe-server\fR is meant mainly for testing PPPoE clients.
+It is \fInot\fR a high-performance server meant for production use.
+
+.SH AUTHORS
+\fBpppoe-server\fR was written by David F. Skoll <dfs@roaringpenguin.com>.
+
+The \fBpppoe\fR home page is \fIhttp://www.roaringpenguin.com/pppoe/\fR.
+
+.SH SEE ALSO
+adsl-start(8), adsl-stop(8), adsl-connect(8), pppd(8), pppoe.conf(5),
+pppoe(8), adsl-setup(8), adsl-status(8), pppoe-sniff(8), pppoe-relay(8)
+
diff --git a/mdk-stage1/rp-pppoe/man/pppoe-sniff.8 b/mdk-stage1/rp-pppoe/man/pppoe-sniff.8
new file mode 100644
index 000000000..2568d77f6
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/man/pppoe-sniff.8
@@ -0,0 +1,77 @@
+.\" $Id: pppoe-sniff.8 195724 2001-06-11 13:49:39Z gc $
+.TH PPPOE-SNIFF 8 "3 July 2000"
+.\""
+.UC 4
+.SH NAME
+pppoe-sniff \- examine network for non-standard PPPoE frames
+.SH SYNOPSIS
+.B pppoe-sniff \fR[\fIoptions\fR]
+
+.SH DESCRIPTION
+\fBpppoe-sniff\fR listens for likely-looking PPPoE PADR and session frames
+and deduces extra options required for \fBpppoe(8)\fR to work.
+
+Some DSL providers seem to use non-standard frame types for PPPoE frames,
+and/or require a certain value in the Service-Name field. It is often
+easier to sniff those values from a machine which can successfully connect
+rather than try to pry them out of the DSL provider.
+
+To use \fBpppoe-sniff\fR, you need two computers, a DSL modem and
+an Ethernet hub (\fInot\fR an Ethernet switch.)
+
+If the DSL modem normally connects directly to your computer's
+Ethernet card, connect it to the "uplink" port on the Ethernet hub.
+Plug two computers into normal ports on the hub. On one computer, run
+whatever software the DSL provider gave you on whatever operating
+system the DSL provider supports. On the other computer, run Linux and
+log in as root.
+
+On the Linux machine, put the Ethernet interface into promiscuous mode
+and start \fBpppoe-sniff\fR. If the ethernet interface is \fIeth0\fR,
+for example, type these commands:
+
+.nf
+ ifconfig eth0 promisc
+ pppoe-sniff -I eth0
+.fi
+
+On the other machine, start your DSL connection as usual. After a short
+time, \fBpppoe-sniff\fR should print recommendations for the value
+of \fBPPPOE_EXTRA\fR. Set this value in \fB/etc/ppp/pppoe.conf\fR.
+If \fBpppoe-sniff\fR indicates that something special is required in
+\fBPPPOE_EXTRA\fR, please e-mail this to \fBpppoe@roaringpenguin.com\fR
+along with the name of your ISP and the manufacturer and model number of
+your DSL modem. This information will be collated and provided on the
+PPPoE web page for users who do not have two computers.
+
+After \fBpppoe-sniff\fR finishes (or you stop it if it seems hung),
+remember to turn off promiscuous mode:
+
+.nf
+ ifconfig eth0 -promisc
+.fi
+
+.SH OPTIONS
+.TP
+.B \-I \fIinterface\fR
+The \fB\-I\fR option specifies the Ethernet interface to use. Under Linux,
+it is typically \fIeth0\fR or \fIeth1\fR. The interface should be "up"
+and in promiscuous mode before you start \fBpppoe-sniff\fR.
+
+.TP
+.B \-V
+The \fB\-V\fR option causes \fBpppoe-sniff\fR to print its version number and
+exit.
+
+.SH BUGS
+\fBpppoe-sniff\fR only works on Linux.
+
+.SH AUTHORS
+\fBpppoe-sniff\fR was written by David F. Skoll <dfs@roaringpenguin.com>.
+
+The \fBpppoe\fR home page is \fIhttp://www.roaringpenguin.com/pppoe/\fR.
+
+.SH SEE ALSO
+adsl-start(8), adsl-stop(8), adsl-connect(8), pppd(8), pppoe.conf(5),
+pppoe(8), adsl-setup(8), adsl-status(8), pppoe-server(8), pppoe-relay(8)
+
diff --git a/mdk-stage1/rp-pppoe/man/pppoe.8 b/mdk-stage1/rp-pppoe/man/pppoe.8
new file mode 100644
index 000000000..831245693
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/man/pppoe.8
@@ -0,0 +1,236 @@
+.\" $Id: pppoe.8 195724 2001-06-11 13:49:39Z gc $
+.TH PPPOE 8 "3 July 2000"
+.UC 4
+.SH NAME
+pppoe \- user-space PPPoE client.
+.SH SYNOPSIS
+.B pppd pty 'pppoe \fR[\fIpppoe_options\fR]\fB' \fR[\fIpppd_options\fR]
+.P
+.B pppoe -A \fR[\fIpppoe_options\fR]
+.SH DESCRIPTION
+\fBpppoe\fR is a user-space client for PPPoE (Point-to-Point Protocol
+over Ethernet) for Linux and other UNIX systems. \fBpppoe\fR works in
+concert with the \fBpppd\fR PPP daemon to provide a PPP connection
+over Ethernet, as is used by many ADSL service providers.
+
+.SH OPTIONS
+.TP
+.B \-I \fIinterface\fR
+The \fB\-I\fR option specifies the Ethernet interface to use. Under Linux,
+it is typically \fIeth0\fR or \fIeth1\fR. The interface should be "up"
+before you start \fBpppoe\fR, but should \fInot\fR be configured to have
+an IP address.
+
+.TP
+.B \-T \fItimeout\fR
+The \fB\-T\fR option causes \fBpppoe\fR to exit if no session traffic
+is detected for \fItimeout\fR seconds. I recommend that you use this
+option as an extra safety measure, but if you do, you should make sure
+that PPP generates enough traffic so the timeout will normally not be
+triggered. The best way to do this is to use the
+\fIlcp-echo-interval\fR option to \fBpppd\fR. You should set the
+PPPoE timeout to be about four times the LCP echo interval.
+
+.TP
+.B \-D \fIfile_name\fR
+The \fB\-D\fR option causes every packet to be dumped to the specified
+\fIfile_name\fR. This is intended for debugging only; it produces huge
+amounts of output and greatly reduces performance.
+
+.TP
+.B \-V
+The \fB\-V\fR option causes \fBpppoe\fR to print its version number and
+exit.
+
+.TP
+.B \-A
+The \fB\-A\fR option causes \fBpppoe\fR to send a PADI packet and then print
+the names of access concentrators in each PADO packet it receives. Do not
+use this option in conjunction with \fBpppd\fR; the \fB\-A\fR option is
+meant to be used interactively to give interesting information about the
+access concentrator.
+
+.TP
+.B \-S \fIservice_name\fR
+Specifies the desired service name. \fBpppoe\fR will only initiate sessions
+with access concentrators which can provide the specified service. In
+most cases, you should \fInot\fR specify this option. Use it only if you
+know that there are multiple access concentrators or know that you need a
+specific service name.
+
+.TP
+.B \-C \fIac_name\fR
+Specifies the desired access concentrator name. \fBpppoe\fR will only
+initiate sessions with the specified access concentrator. In
+most cases, you should \fInot\fR specify this option. Use it only if you
+know that there are multiple access concentrators. If both the
+\fB\-S\fR and \fB\-C\fR options are specified, they must \fIboth\fR match
+for \fBpppoe\fR to initiate a session.
+
+.TP
+.B \-U
+Causes \fBpppoe\fR to use the Host-Uniq tag in its discovery packets. This
+lets you run multiple \fBpppoe\fR daemons without having their discovery
+packets interfere with one another. You must supply this option to
+\fIall\fR \fBpppoe\fR daemons if you intend to run multiple daemons
+simultaneously.
+
+.TP
+.B \-s
+Causes \fBpppoe\fR to use \fIsynchronous\fR PPP encapsulation. If you
+use this option, then you \fImust\fR use the \fBsync\fR option with
+\fBpppd\fR. You are encouraged to use this option if it works, because
+it greatly reduces the CPU overhead of \fBpppoe\fR. However, it
+MAY be unreliable on slow machines -- there is a race condition between
+pppd writing data and pppoe reading it. For this reason, the default
+setting is asynchronous. If you encounter bugs or crashes with Synchronous
+PPP, turn it off -- don't e-mail me for support!
+
+.TP
+.B \-m \fIMSS\fR
+Causes \fBpppoe\fR to \fIclamp\fR the TCP maximum segment size at the specified
+value. Because of PPPoE overhead, the maximum segment size for PPPoE is
+smaller than for normal Ethernet encapsulation. This could cause problems
+for machines on a LAN behind a gateway using PPPoE. If you have a LAN
+behind a gateway, and the gateway connects to the Internet using PPPoE,
+you are strongly recommended to use a \fB\-m 1412\fR option. This avoids
+having to set the MTU on all the hosts on the LAN.
+
+.TP
+.B \-p \fIfile\fR
+Causes \fBpppoe\fR to write its process-ID to the specified file. This
+can be used to locate and kill \fBpppoe\fR processes.
+
+.TP
+.B \-e \fIsess:mac\fR
+Causes \fBpppoe\fR to skip the discovery phase and move directly to the
+session phase. The session is given by \fIsess\fR and the MAC address of
+the peer by \fImac\fR. This mode is \fInot\fR meant for normal use; it
+is designed only for \fBpppoe-server\fR(8).
+
+.TP
+.B \-n
+Causes \fBpppoe\fR not to open a discovery socket. This mode is
+\fInot\fR meant for normal use; it is designed only for
+\fBpppoe-server\fR(8).
+
+.TP
+.B \-k
+Causes \fBpppoe\fR to terminate an existing session by sending a PADT frame,
+and then exit. You must use the \fB\-e\fR option in conjunction with this
+option to specify the session to kill. This may be useful for killing
+sessions when a buggy peer does not realize the session has ended.
+
+.TP
+.B \-d
+Causes \fBpppoe\fR to perform discovery and then exit, after printing
+session information to standard output. The session information is printed
+in exactly the format expected by the \fB\-e\fR option. This option lets
+you initiate a PPPoE discovery, perform some other work, and then start
+the actual PPP session. \fIBe careful\fR; if you use this option in a loop,
+you can create many sessions, which may annoy your peer.
+
+.TP
+.B \-f disc:sess
+The \fB\-f\fR option sets the Ethernet frame types for PPPoE discovery
+and session frames. The types are specified as hexadecimal numbers
+separated by a colon. Standard PPPoE uses frame types 8863:8864.
+\fIYou should not use this option\fR unless you are absolutely sure
+the peer you are dealing with uses non-standard frame types. If your
+ISP uses non-standard frame types, complain!
+
+.TP
+.B \-h
+The \fB\-h\fR option causes \fBpppoe\fR to print usage information and
+exit.
+
+.SH PPPOE BACKGROUND
+
+PPPoE (Point-to-Point Protocol over Ethernet) is described in RFC 2516
+and is a protocol which allows the session abstraction to be maintained
+over bridged Ethernet networks.
+
+PPPoE works by encapsulating PPP frames in Ethernet frames. The protocol
+has two distinct stages: The \fIdiscovery\fR and the \fIsession\fR stage.
+
+In the discovery stage, the host broadcasts a special PADI (PPPoE
+Active Discovery Initiation) frame to discover any \fIaccess
+concentrators\fR. The access concentrators (typically, only one
+access concentrator) reply with PADO (PPPoE Active Discovery Offer)
+packets, announcing their presence and the services they offer. The
+host picks one of the access concentrators and transmits a PADR (PPPoE
+Active Discovery Request) packet, asking for a session. The access
+concentrator replies with a PADS (PPPoE Active Discovery
+Session-Confirmation) packet. The protocol then moves to the session stage.
+
+In the session stage, the host and access concentrator exchange PPP frames
+embedded in Ethernet frames. The normal Ethernet MTU is 1500 bytes, but
+the PPPoE overhead plus two bytes of overhead for the encapsulated PPP
+frame mean that the MTU of the PPP interface is at most 1492 bytes.
+This causes \fIall kinds of problems\fR if you are using a Linux machine
+as a firewall and interfaces behind the firewall have an MTU greater than
+1492. In fact, to be safe, I recommend setting the MTU of machines
+behind the firewall to 1412, to allow for worst-case TCP and IP options
+in their respective headers.
+
+Normally, PPP uses the Link Control Protocol (LCP) to shut down a PPP
+link. However, the PPPoE specification allows the link to be shut down
+with a special PADT (PPPoE Active Discovery Terminate) packet. This client
+recognizes this packet and will correctly terminate if a terminate request
+is received for the PPP session.
+
+.SH DESIGN GOALS
+
+My design goals for this PPPoE client were as follows, in descending order
+of importance:
+
+.TP
+.B o
+It must work.
+
+.TP
+.B o
+It must be a user-space program and not a kernel patch.
+
+.TP
+.B o
+The code must be easy to read and maintain.
+
+.TP
+.B o
+It must be fully compliant with RFC 2516, the proposed PPPoE standard.
+
+.TP
+.B o
+It must never hang up forever -- if the connection is broken, it must
+detect this and exit, allowing a wrapper script to restart the connection.
+
+.TP
+.B o
+It must be fairly efficient.
+
+.P
+I believe I have achieved all of these goals, but (of course) am open
+to suggestions, patches and ideas. See my home page,
+http://www.roaringpenguin.com, for contact information.
+
+.SH NOTES
+
+For best results, you must give \fBpppd\fR an mtu option of
+1492. I have observed problems with excessively-large frames
+unless I set this option. Also, if \fBpppoe\fR is running on a firewall
+machine, all machines behind the firewall should have MTU's of 1412.
+
+If you have problems, check your system logs. \fBpppoe\fR logs interesting
+things to syslog. You may have to turn on logging of \fIdebug\fR-level
+messages for complete diagnosis.
+
+.SH AUTHORS
+\fBpppoe\fR was written by David F. Skoll <dfs@roaringpenguin.com>,
+with much inspiration from an earlier version by Luke Stras.
+
+The \fBpppoe\fR home page is \fIhttp://www.roaringpenguin.com/pppoe/\fR.
+
+.SH SEE ALSO
+adsl-start(8), adsl-stop(8), adsl-connect(8), pppd(8), pppoe.conf(5), adsl-setup(8), adsl-status(8), pppoe-sniff(8), pppoe-server(8), pppoe-relay(8)
+
diff --git a/mdk-stage1/rp-pppoe/man/pppoe.conf.5 b/mdk-stage1/rp-pppoe/man/pppoe.conf.5
new file mode 100644
index 000000000..36c4a388e
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/man/pppoe.conf.5
@@ -0,0 +1,168 @@
+.\" $Id: pppoe.conf.5 195724 2001-06-11 13:49:39Z gc $
+.\""
+.TH PPPOE.CONF 5 "21 February 2000"
+.UC 4
+.SH NAME
+pppoe.conf \- Configuration file used by \fBadsl-start\fR(8),
+\fBadsl-stop\fR(8), \fBadsl-status(8)\fR and \fBadsl-connect\fR(8).
+
+.SH DESCRIPTION
+\fB/etc/ppp/pppoe.conf\fR is a shell script which contains configuration
+information for Roaring Penguin's ADSL scripts. Note that \fBpppoe.conf\fR
+is used only by the various adsl-* shell scripts, not by \fBpppoe\fR
+itself.
+
+\fBpppoe.conf\fR consists of a sequence of shell variable assignments.
+The variables and their meanings are:
+
+.TP
+.B ETH
+The Ethernet interface connected to the ADSL modem (for example, eth0).
+
+.TP
+.B USER
+The ADSL user-id (for example, b1xxnxnx@sympatico.ca).
+
+.TP
+.B SERVICENAME
+If this is not blank, then it is passed with the \fB\-S\fR option to
+\fBpppoe\fR. It specifies a service name to ask for. Usually, you
+should leave it blank.
+
+.TP
+.B ACNAME
+If this is not blank, then it is passed with the \fB\-C\fR option to
+\fBpppoe\fR. It specifies the name of the access concentrator to connect
+to. Usually, you should leave it blank.
+
+.TP
+.B DEMAND
+If set to a number, the link is activated on demand and brought down
+after after \fBDEMAND\fR seconds. If set to \fBno\fR, the link is kept
+up all the time rather than being activated on demand.
+
+.TP
+.B DNSTYPE
+One of \fBNOCHANGE\fR, \fBSPECIFY\fR or \fBSERVER\fR. If
+set to NOCHANGE, \fBadsl-connect\fR will not adjust the DNS setup in
+any way. If set to SPECIFY, it will re-write /etc/resolv.conf with
+the values of DNS1 and DNS2. If set to \fBSERVER\fR, it will
+supply the \fIusepeerdns\fR option to \fBpppd\fR, and make a symlink
+from /etc/resolv.conf to /etc/ppp/resolv.conf.
+
+.TP
+.B DNS1, DNS2
+IP addresses of DNS servers if you use DNSTYPE=SPECIFY.
+
+.TP
+.B NONROOT
+If the line \fBNONROOT=OK\fR (exactly like that; no whitespace or comments)
+appears in the configuration file, then \fBpppoe-wrapper\fR will allow
+non-root users to bring the conneciton up or down. The wrapper is installed
+only if you installed the rp-pppoe-gui package.
+
+.TP
+.B USEPEERDNS
+If set to "yes", then \fBadsl-connect\fR will supply the \fIusepeerdns\fR
+option to \fBpppd\fR, which causes it to obtain DNS server addresses
+from the peer and create a new \fB/etc/resolv.conf\fR file. Otherwise,
+\fBadsl-connect\fR will not supply this option, and \fBpppd\fR will not
+modify \fB/etc/resolv.conf\fR.
+
+.TP
+.B CONNECT_POLL
+How often (in seconds) \fBadsl-start\fR should check to see if a new PPP
+interface has come up. If this is set to 0, the \fBadsl-start\fR simply
+initiates the PPP session, but does not wait to see if it comes up
+successfully.
+
+.TP
+.B CONNECT_TIMEOUT
+How long (in seconds) \fBadsl-start\fR should wait for a new PPP interface
+to come up before concluding that \fBadsl-connect\fR has failed and killing
+the session.
+
+.TP
+.B PING
+A character which is echoed every \fBCONNECT_POLL\fR seconds while
+\fBadsl-start\fR is waiting for the PPP interface to come up.
+
+.TP
+.B FORCEPING
+A character which is echoed every \fBCONNECT_POLL\fR seconds while
+\fBadsl-start\fR is waiting for the PPP interface to come up. Similar
+to \fBPING\fR, but the character is echoed even if \fBadsl-start\fR's
+standard output is not a tty.
+
+.TP
+.B PIDFILE
+A file in which to write the process-ID of the adsl-connect process
+(for example, \fB/var/run/pppoe.pid\fR). Two additional files
+($PIDFILE.pppd and $PIDFILE.pppoe) hold the process-ID's of the
+\fBpppd\fR and \fBpppoe\fR processes, respectively.
+
+.TP
+.B SYNCHRONOUS
+An indication of whether or not to use synchronous PPP (\fByes\fR or
+\fBno\fR). Synchronous PPP is safe on Linux machines with the n_hdlc
+line discipline. (If you have a file called "n_hdlc.o" in your
+modules directory, you have the line discipline.) It is \fInot
+recommended\fR on other machines or on Linux machines without the
+n_hdlc line discipline due to some known and unsolveable race
+conditions in a user-mode client.
+
+.TP
+.B CLAMPMSS
+The value at which to "clamp" the advertised MSS for TCP sessions. The
+default of 1412 should be fine.
+
+.TP
+.B LCP_INTERVAL
+How often (in seconds) \fBpppd\fR sends out LCP echo-request packets.
+
+.TP
+.B LCP_FAILURE
+How many unanswered LCP echo-requests must occur before \fBpppd\fR
+concludes the link is dead.
+
+.TP
+.B PPPOE_TIMEOUT
+If this many seconds elapse without any activity seen by \fBpppoe\fR,
+then \fBpppoe\fR exits.
+
+.TP
+.B FIREWALL
+One of NONE, STANDALONE or MASQUERADE. If NONE, then \fBadsl-connect\fR does
+not add any firewall rules. If STANDALONE, then it clears existing firewall
+rules and sets up basic rules for a standalone machine. If MASQUERADE, then
+it clears existing firewall rules and sets up basic rules for an Internet
+gateway. If you run services on your machine, these simple firewall scripts
+are inadequate; you'll have to make your own firewall rules and set FIREWALL
+to NONE.
+
+.TP
+.B PPPOE_EXTRA
+Any extra arguments to pass to \fBpppoe\fR
+
+.TP
+.B PPPD_EXTRA
+Any extra arguments to pass to \fBpppd\fR
+
+.TP
+.B LINUX_PLUGIN
+If non-blank, the full path of the Linux kernel-mode PPPoE plugin
+(typically \fB/etc/ppp/plugins/rp-pppoe.so\fR.) This forces
+\fBadsl-connect\fR to use kernel-mode PPPoE on Linux 2.4.x systems.
+This code is experimental and unsupported. Use of the plugin causes
+\fBadsl-connect\fR to ignore CLAMPMSS, PPPOE_EXTRA, SYNCHRONOUS and
+PPPOE_TIMEOUT.
+
+.P
+By using different configuration files with different PIDFILE
+settings, you can manage multiple PPPoE connections. Just specify the
+configuration file as an argument to \fBadsl-start\fR and \fBadsl-stop\fR.
+
+.SH SEE ALSO
+pppoe(8), adsl-connect(8), adsl-start(8), adsl-stop(8), pppd(8), adsl-setup(8),
+pppoe-wrapper(8)
+
diff --git a/mdk-stage1/rp-pppoe/rp-pppoe-gui.spec b/mdk-stage1/rp-pppoe/rp-pppoe-gui.spec
new file mode 100644
index 000000000..3222a602e
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/rp-pppoe-gui.spec
@@ -0,0 +1,98 @@
+Summary: PPP Over Ethernet (xDSL support)
+Name: rp-pppoe-gui
+Version: 3.0
+%if %(%{expand:test %{_vendor} != mandrake ; echo $?})
+Release: 1mdk
+%else
+Release: 1
+%endif
+Copyright: GPL
+Group: System Environment/Daemons
+Source: http://www.roaringpenguin.com/pppoe/rp-pppoe-3.0.tar.gz
+Url: http://www.roaringpenguin.com/pppoe/
+Packager: David F. Skoll <dfs@roaringpenguin.com>
+BuildRoot: /tmp/pppoe-build
+Vendor: Roaring Penguin Software Inc.
+Requires: ppp >= 2.3.7
+Requires: rp-pppoe >= 3.0
+
+%description
+This is a graphical wrapper around the rp-pppoe PPPoE client. PPPoE is
+a protocol used by many DSL Internet Service Providers.
+
+%prep
+umask 022
+mkdir -p $RPM_BUILD_ROOT
+cd $RPM_BUILD_ROOT
+rm -rf $RPM_BUILD_ROOT/rp-pppoe-%{version}
+zcat $RPM_SOURCE_DIR/rp-pppoe-%{version}.tar.gz | tar xvf -
+cd $RPM_BUILD_ROOT/rp-pppoe-%{version}/src
+./configure --mandir=%{_mandir}
+
+%build
+cd $RPM_BUILD_ROOT/rp-pppoe-%{version}/gui
+make
+
+%install
+cd $RPM_BUILD_ROOT/rp-pppoe-%{version}/gui
+make install RPM_INSTALL_ROOT=$RPM_BUILD_ROOT
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+%post
+# Install entry in KDE menu
+if test -n "$KDEDIR" ; then
+ mkdir -p "$KDEDIR/share/applnk/Internet"
+ cat <<EOF > "$KDEDIR/share/applnk/Internet/tkpppoe.kdelnk"
+# KDE Config File
+[KDE Desktop Entry]
+Name=TkPPPoE
+Comment=Start/Stop ADSL connections
+Exec=tkpppoe
+Terminal=0
+Type=Application
+EOF
+fi
+
+# Install entry in GNOME menus
+GNOMEDIR=`gnome-config --datadir 2>/dev/null`
+if test -n "$GNOMEDIR" ; then
+ mkdir -p "$GNOMEDIR/gnome/apps/Internet"
+cat <<EOF > "$GNOMEDIR/gnome/apps/Internet/tkpppoe.desktop"
+[Desktop Entry]
+Name=TkPPPoE
+Comment=Start/Stop ADSL connections
+Exec=tkpppoe
+Terminal=0
+Type=Application
+EOF
+fi
+
+%postun
+# Remove KDE menu entry
+if test -n "$KDEDIR" ; then
+ rm -f "$KDEDIR/share/applnk/Internet/tkpppoe.kdelnk"
+fi
+
+# Remove GNOME menu entry
+GNOMEDIR=`gnome-config --datadir 2>/dev/null`
+if test -n "$GNOMEDIR" ; then
+ rm -f "$GNOMEDIR/gnome/apps/Internet/tkpppoe.desktop"
+fi
+
+%files
+%defattr(-,root,root)
+%dir /etc/ppp/rp-pppoe-gui
+/usr/sbin/pppoe-wrapper
+/usr/bin/tkpppoe
+%{_mandir}/man1/tkpppoe.1*
+%{_mandir}/man1/pppoe-wrapper.1*
+/usr/share/rp-pppoe-gui/tkpppoe.html
+/usr/share/rp-pppoe-gui/mainwin-busy.png
+/usr/share/rp-pppoe-gui/mainwin-nonroot.png
+/usr/share/rp-pppoe-gui/mainwin.png
+/usr/share/rp-pppoe-gui/props-advanced.png
+/usr/share/rp-pppoe-gui/props-basic.png
+/usr/share/rp-pppoe-gui/props-nic.png
+/usr/share/rp-pppoe-gui/props-options.png
diff --git a/mdk-stage1/rp-pppoe/rp-pppoe.spec b/mdk-stage1/rp-pppoe/rp-pppoe.spec
new file mode 100644
index 000000000..622e3bb80
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/rp-pppoe.spec
@@ -0,0 +1,71 @@
+Summary: PPP Over Ethernet (xDSL support)
+Name: rp-pppoe
+Version: 3.0
+%if %(%{expand:test %{_vendor} != mandrake ; echo $?})
+Release: 1mdk
+%else
+Release: 1
+%endif
+Copyright: GPL
+Group: System Environment/Daemons
+Source: http://www.roaringpenguin.com/pppoe/rp-pppoe-3.0.tar.gz
+Url: http://www.roaringpenguin.com/pppoe/
+Packager: David F. Skoll <dfs@roaringpenguin.com>
+BuildRoot: /tmp/pppoe-build
+Vendor: Roaring Penguin Software Inc.
+Requires: ppp >= 2.3.7
+
+%description
+PPPoE (Point-to-Point Protocol over Ethernet) is a protocol used by
+many ADSL Internet Service Providers. Roaring Penguin has a free
+client for Linux systems to connect to PPPoE service providers.
+
+The client is a user-mode program and does not require any kernel
+modifications. It is fully compliant with RFC 2516, the official PPPoE
+specification.
+
+%prep
+%setup
+cd src
+./configure --mandir=%{_mandir}
+
+%build
+cd src
+make
+
+%install
+cd src
+make install RPM_INSTALL_ROOT=$RPM_BUILD_ROOT
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+%files
+%defattr(-,root,root)
+%doc doc/CHANGES doc/HOW-TO-CONNECT doc/LICENSE doc/KERNEL-MODE-PPPOE README
+%config /etc/ppp/pppoe.conf
+%config /etc/ppp/pppoe-server-options
+%config /etc/ppp/firewall-masq
+%config /etc/ppp/firewall-standalone
+/etc/ppp/plugins/*
+/usr/sbin/pppoe
+/usr/sbin/pppoe-server
+/usr/sbin/pppoe-sniff
+/usr/sbin/pppoe-relay
+/usr/sbin/adsl-connect
+/usr/sbin/adsl-start
+/usr/sbin/adsl-stop
+/usr/sbin/adsl-setup
+/usr/sbin/adsl-status
+%{_mandir}/man5/pppoe.conf.5*
+%{_mandir}/man8/pppoe.8*
+%{_mandir}/man8/pppoe-server.8*
+%{_mandir}/man8/pppoe-relay.8*
+%{_mandir}/man8/pppoe-sniff.8*
+%{_mandir}/man8/adsl-connect.8*
+%{_mandir}/man8/adsl-start.8*
+%{_mandir}/man8/adsl-stop.8*
+%{_mandir}/man8/adsl-status.8*
+%{_mandir}/man8/adsl-setup.8*
+/etc/rc.d/init.d/adsl
+
diff --git a/mdk-stage1/rp-pppoe/scripts/adsl-connect.in b/mdk-stage1/rp-pppoe/scripts/adsl-connect.in
new file mode 100755
index 000000000..26b6f0507
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/scripts/adsl-connect.in
@@ -0,0 +1,278 @@
+#!/bin/sh
+# @configure_input@
+#***********************************************************************
+#
+# adsl-connect
+#
+# Shell script to connect to an ADSL provider using PPPoE
+#
+# Copyright (C) 2000 Roaring Penguin Software Inc.
+#
+# $Id: adsl-connect.in 195724 2001-06-11 13:49:39Z gc $
+#
+# This file may be distributed under the terms of the GNU General
+# Public License.
+#
+# Usage: adsl-connect [config_file]
+# adsl-connect interface user [config_file]
+# Second form overrides USER and ETH from config file.
+# If config_file is omitted, defaults to /etc//ppp/pppoe.conf
+#
+#***********************************************************************
+
+# From AUTOCONF
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+localstatedir=/var
+
+# Paths to programs
+IFCONFIG=/sbin/ifconfig
+PPPD=@PPPD@
+SETSID=@SETSID@
+PPPOE=@sbindir@/pppoe
+LOGGER="/usr/bin/logger -t `basename $0`"
+
+# Must be root
+if test "`@ID@ -u`" != 0 ; then
+ echo "$0: You must be root to run this script" >& 2
+ exit 1
+fi
+
+if test "$SETSID" != "" -a ! -x "$SETSID"; then
+ SETSID=""
+fi
+
+CONFIG=/etc//ppp/pppoe.conf
+USER=""
+ETH=""
+
+# Sort out command-line arguments
+case "$#" in
+ 1)
+ CONFIG="$1"
+ ;;
+ 3)
+ CONFIG="$3"
+ ;;
+esac
+
+if test ! -f "$CONFIG" -o ! -r "$CONFIG" ; then
+ echo "$0: Cannot read configuration file '$CONFIG'" >& 2
+ exit 1
+fi
+
+. $CONFIG
+
+PPPOE_PIDFILE="$PIDFILE.pppoe"
+PPPD_PIDFILE="$PIDFILE.pppd"
+
+# Check for command-line overriding of ETH and USER
+case "$#" in
+ 2|3)
+ ETH="$1"
+ USER="$2"
+ ;;
+esac
+
+# Check that config file is sane
+if test "$USER" = "" ; then
+ echo "$0: Check '$CONFIG' -- no setting for USER" >& 2
+ exit 1
+fi
+if test "$ETH" = "" ; then
+ echo "$0: Check '$CONFIG' -- no setting for ETH" >& 2
+ exit 1
+fi
+
+PPPD_PID=0
+
+# Catch common error
+if test "$DEBUG" = "1" ; then
+ echo "*** If you want to use DEBUG, invoke adsl-start, not adsl-connect."
+ exit 1
+fi
+
+if test "$DEBUG" != "" ; then
+ if test "$LINUX_PLUGIN" != "" ; then
+ echo "Cannot use DEBUG mode and LINUX_PLUGIN at the same time."
+ echo "Kernel-mode PPPoE is experimental and unsupported."
+ exit 1
+ fi
+ echo "* The following section identifies your Ethernet interface" >> $DEBUG
+ echo "* and user name. Some ISP's need 'username'; others" >> $DEBUG
+ echo "* need 'username@isp.com'. Try both" >> $DEBUG
+ echo "ETH=$ETH; USER=$USER" >> $DEBUG
+ echo "---------------------------------------------" >> $DEBUG
+fi
+
+# MTU of Ethernet card attached to modem MUST be 1500. This apparently
+# fails on some *BSD's, so we'll only do it under Linux
+
+if test `uname -s` = Linux ; then
+ $IFCONFIG $ETH up mtu 1500
+ # For 2.4 kernels. Will fail on 2.2.x, but who cares?
+ modprobe ppp_generic > /dev/null 2>&1
+ modprobe ppp_async > /dev/null 2>&1
+ modprobe ppp_synctty > /dev/null 2>&1
+ if test -n "$LINUX_PLUGIN" ; then
+ modprobe pppox > /dev/null 2>&1
+ modprobe pppoe > /dev/null 2>&1
+ fi
+fi
+
+if test "$SYNCHRONOUS" = "yes" ; then
+ PPPOE_SYNC=-s
+ PPPD_SYNC=sync
+ # Increase the chances of it working on Linux...
+ if test `uname -s` = Linux ; then
+ modprobe n_hdlc > /dev/null 2>&1
+ fi
+else
+ PPPOE_SYNC=""
+ PPPD_SYNC=""
+fi
+
+if test -n "$ACNAME" ; then
+ ACNAME="-C $ACNAME"
+fi
+
+if test -n "$SERVICENAME" ; then
+ SERVICENAME="-S $SERVICENAME"
+fi
+
+if test "$CLAMPMSS" = "no" ; then
+ CLAMPMSS=""
+else
+ CLAMPMSS="-m $CLAMPMSS"
+fi
+
+# If DNSTYPE is SERVER, we must use "usepeerdns" option to pppd.
+if test "$DNSTYPE" = "SERVER" ; then
+ USEPEERDNS=yes
+fi
+
+if test "$USEPEERDNS" = "yes" ; then
+ USEPEERDNS="usepeerdns"
+else
+ USEPEERDNS=""
+fi
+
+# Backward config file compatibility
+if test "$DEMAND" = "" ; then
+ DEMAND=no
+fi
+
+if test "$DEMAND" = "no" ; then
+ DEMAND=""
+else
+ DEMAND="demand persist idle $DEMAND 10.112.112.112:10.112.112.113 ipcp-accept-remote ipcp-accept-local connect true noipdefault ktune"
+fi
+
+case "$FIREWALL" in
+ STANDALONE)
+ . /etc/ppp/firewall-standalone
+ ;;
+ MASQUERADE)
+ . /etc/ppp/firewall-masq
+ ;;
+esac
+
+# If we're using kernel-mode PPPoE on Linux...
+if test "$LINUX_PLUGIN" != "" ; then
+ PLUGIN_OPTS="plugin $LINUX_PLUGIN $ETH"
+ modprobe pppoe > /dev/null 2>&1
+fi
+
+# Standard PPP options we always use
+PPP_STD_OPTIONS="$PLUGIN_OPTS noipdefault noauth default-asyncmap defaultroute hide-password nodetach $USEPEERDNS local mtu 1492 mru 1492 noaccomp noccp nobsdcomp nodeflate nopcomp novj novjccomp user $USER lcp-echo-interval $LCP_INTERVAL lcp-echo-failure $LCP_FAILURE $PPPD_EXTRA"
+
+# Jigger DNS if required...
+if test "$DNSTYPE" = "SERVER" ; then
+ # Sorry, dude...
+ rm -f /etc/resolv.conf
+ ln -s /etc/ppp/resolv.conf /etc/resolv.conf
+elif test "$DNSTYPE" = "SPECIFY" ; then
+ # Sorry, dude...
+ rm -f /etc/resolv.conf
+ echo "nameserver $DNS1" > /etc/resolv.conf
+ if test -n "$DNS2" ; then
+ echo "nameserver $DNS2" >> /etc/resolv.conf
+ fi
+fi
+
+# PPPoE invocation
+PPPOE_CMD="$PPPOE -p $PPPOE_PIDFILE -I $ETH -T $PPPOE_TIMEOUT -U $PPPOE_SYNC $CLAMPMSS $ACNAME $SERVICENAME $PPPOE_EXTRA"
+if test "$DEBUG" != "" ; then
+ if test "$DEMAND" != "" ; then
+ echo "(Turning off DEMAND for debugging purposes)"
+ DEMAND=""
+ fi
+ echo "* The following section shows the pppd command we will invoke" >> $DEBUG
+ echo "pppd invocation" >> $DEBUG
+ echo "$SETSID $PPPD pty '$PPPOE_CMD' $PPP_STD_OPTIONS $PPPD_SYNC debug" >> $DEBUG
+ echo "---------------------------------------------" >> $DEBUG
+ $SETSID $PPPD pty "$PPPOE_CMD -D $DEBUG-0" \
+ $PPP_STD_OPTIONS \
+ $PPPD_SYNC \
+ debug >> $DEBUG 2>&1
+ echo "---------------------------------------------" >> $DEBUG
+ echo "* The following section is an extract from your log." >> $DEBUG
+ echo "* Look for error messages from pppd, such as" >> $DEBUG
+ echo "* a lack of kernel support for PPP, authentication failure" >> $DEBUG
+ echo "* etc." >> $DEBUG
+ echo "Extract from /var/log/messages" >> $DEBUG
+ grep 'ppp' /var/log/messages | tail -150 >> $DEBUG
+ date >> $DEBUG
+ echo "---------------------------------------------" >> $DEBUG
+ echo "* The following section is a dump of the packets" >> $DEBUG
+ echo "* sent and received by rp-pppoe. If you don't see" >> $DEBUG
+ echo "* any output, it's an Ethernet driver problem. If you only" >> $DEBUG
+ echo "* see three PADI packets and nothing else, check your cables" >> $DEBUG
+ echo "* and modem. Make sure the modem lights flash when you try" >> $DEBUG
+ echo "* to connect. Check that your Ethernet card is in" >> $DEBUG
+ echo "* half-duplex, 10Mb/s mode. If all else fails," >> $DEBUG
+ echo "* try using pppoe-sniff." >> $DEBUG
+ echo "rp-pppoe debugging dump" >> $DEBUG
+ cat $DEBUG-0 >> $DEBUG
+ rm -f $DEBUG-0
+ for i in 1 2 3 4 5 6 7 8 9 10 ; do
+ echo ""
+ echo ""
+ echo ""
+ done
+ echo "*** Finished debugging run. Please review the file"
+ echo "*** '$DEBUG' and try to"
+ echo "*** figure out what is going on."
+ echo "***"
+ echo "*** Unfortunately, we can NO LONGER accept debugging"
+ echo "*** output for analysis. Please do not send this to"
+ echo "*** Roaring Penguin; it is too time-consuming for"
+ echo "*** us to deal with all the analyses we have been sent."
+ exit 0
+fi
+
+echo $$ > $PIDFILE
+
+while [ true ] ; do
+ if test "$LINUX_PLUGIN" != "" ; then
+ $SETSID $PPPD $PPP_STD_OPTIONS $DEMAND &
+ echo "$!" > $PPPD_PIDFILE
+ else
+ $SETSID $PPPD pty "$PPPOE_CMD" \
+ $PPP_STD_OPTIONS \
+ $DEMAND \
+ $PPPD_SYNC &
+ echo "$!" > $PPPD_PIDFILE
+ fi
+ wait
+
+ # Run /etc/ppp/adsl-lost if it exists
+ test -x /etc/ppp/adsl-lost && /etc/ppp/adsl-lost
+
+ # Re-establish the connection
+ $LOGGER -p daemon.notice \
+ "ADSL connection lost; attempting re-connection."
+
+ # Wait a bit in case a problem causes tons of log messages :-)
+ sleep 5
+done
diff --git a/mdk-stage1/rp-pppoe/scripts/adsl-init-suse.in b/mdk-stage1/rp-pppoe/scripts/adsl-init-suse.in
new file mode 100755
index 000000000..936f5fba7
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/scripts/adsl-init-suse.in
@@ -0,0 +1,62 @@
+#!/bin/sh
+#
+# adsl This script starts or stops an ADSL connection
+#
+# chkconfig: 2345 99 01
+# description: Connects to ADSL provider
+#
+# Copyright (C) 2000 Roaring Penguin Software Inc. This software may
+# be distributed under the terms of the GNU General Public License, version
+# 2 or any later version.
+# Modifed to work with SuSE 6.4 linux by Gary Cameron.
+#
+# Source function library.
+#. /etc/rc.d/init.d/functions # For red hat?
+. /etc/rc.config # For SuSE, enables setting from /etc/rc.config
+
+#Tweak this
+restart_time=120
+
+# From AUTOCONF
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+
+# Paths to programs
+START=@sbindir@/adsl-start
+STOP=@sbindir@/adsl-stop
+STATUS=@sbindir@/adsl-status
+
+test "$ADSL_START" = "yes" || exit 0
+
+# The echo return value for success (defined in /etc/rc.config).
+return=$rc_done
+case "$1" in
+ start)
+ echo -n "Bringing up ADSL link"
+ $START > /dev/null 2>&1 || return=$rc_failed
+ echo -e "$return"
+ ;;
+
+ stop)
+ echo -n "Shutting down ADSL link"
+ $STOP > /dev/null 2>&1 || return=$rc_failed
+ echo -e "$return"
+ ;;
+
+ restart)
+ $0 stop
+ echo "Waiting" $restart_time "seconds for the host to reset itself"
+ sleep $restart_time #Note: Need time for host to reset itself
+ $0 start
+ ;;
+
+ status)
+ $STATUS
+ ;;
+
+ *)
+ echo "Usage: adsl {start|stop|restart|status}"
+ exit 1
+esac
+
+exit 0
diff --git a/mdk-stage1/rp-pppoe/scripts/adsl-init-turbolinux.in b/mdk-stage1/rp-pppoe/scripts/adsl-init-turbolinux.in
new file mode 100755
index 000000000..3b22f1345
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/scripts/adsl-init-turbolinux.in
@@ -0,0 +1,62 @@
+#!/bin/sh
+#
+# adsl This script starts or stops an ADSL connection
+#
+# chkconfig: 2345 99 01
+# description: Connects to ADSL provider
+#
+# Copyright (C) 2000 Roaring Penguin Software Inc. This software may
+# be distributed under the terms of the GNU General Public License, version
+# 2 or any later version.
+
+# Source function library if it exists
+test -r /etc/rc.d/init.d/functions && . /etc/rc.d/init.d/functions
+
+# From AUTOCONF
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+
+# Paths to programs
+START=@sbindir@/adsl-start
+STOP=@sbindir@/adsl-stop
+STATUS=@sbindir@/adsl-status
+case "$1" in
+ start)
+ echo -n "Bringing up ADSL link: "
+
+ $START
+ if [ $? = 0 ] ; then
+ echo success
+ touch /var/lock/subsys/adsl
+ else
+ echo failure
+ fi
+ ;;
+
+ stop)
+ echo -n "Shutting down ADSL link: "
+
+ $STOP > /dev/null 2>&1
+ if [ $? = 0 ] ; then
+ echo success
+ rm -f /var/lock/subsys/adsl
+ else
+ echo failure
+ fi
+ ;;
+
+ restart)
+ $0 stop
+ $0 start
+ ;;
+
+ status)
+ $STATUS
+ ;;
+
+ *)
+ echo "Usage: adsl {start|stop|restart|status}"
+ exit 1
+esac
+
+exit 0
diff --git a/mdk-stage1/rp-pppoe/scripts/adsl-init.in b/mdk-stage1/rp-pppoe/scripts/adsl-init.in
new file mode 100755
index 000000000..ab9146fd3
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/scripts/adsl-init.in
@@ -0,0 +1,64 @@
+#!/bin/sh
+#
+# adsl This script starts or stops an ADSL connection
+#
+# chkconfig: 2345 99 01
+# description: Connects to ADSL provider
+#
+# Copyright (C) 2000 Roaring Penguin Software Inc. This software may
+# be distributed under the terms of the GNU General Public License, version
+# 2 or any later version.
+
+# Source function library if it exists
+test -r /etc/rc.d/init.d/functions && . /etc/rc.d/init.d/functions
+
+# From AUTOCONF
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+
+# Paths to programs
+START=@sbindir@/adsl-start
+STOP=@sbindir@/adsl-stop
+STATUS=@sbindir@/adsl-status
+case "$1" in
+ start)
+ echo -n "Bringing up ADSL link"
+
+ $START
+ if [ $? = 0 ] ; then
+ touch /var/lock/subsys/adsl
+ echo_success
+ else
+ echo_failure
+ fi
+ echo ""
+ ;;
+
+ stop)
+ echo -n "Shutting down ADSL link"
+
+ $STOP > /dev/null 2>&1
+ if [ $? = 0 ] ; then
+ rm -f /var/lock/subsys/adsl
+ echo_success
+ else
+ echo_failure
+ fi
+ echo ""
+ ;;
+
+ restart)
+ $0 stop
+ $0 start
+ ;;
+
+ status)
+ $STATUS
+ ;;
+
+ *)
+ echo "Usage: adsl {start|stop|restart|status}"
+ exit 1
+esac
+
+exit 0
diff --git a/mdk-stage1/rp-pppoe/scripts/adsl-setup.in b/mdk-stage1/rp-pppoe/scripts/adsl-setup.in
new file mode 100755
index 000000000..98e922378
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/scripts/adsl-setup.in
@@ -0,0 +1,346 @@
+#!/bin/sh
+#***********************************************************************
+#
+# adsl-setup
+#
+# All-purpose slicing/dicing shell script to configure rp-pppoe.
+#
+# Copyright (C) 2000 Roaring Penguin Software Inc.
+#
+# $Id: adsl-setup.in 195724 2001-06-11 13:49:39Z gc $
+#***********************************************************************
+
+# From AUTOCONF
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+
+# Paths to programs
+IFCONFIG=/sbin/ifconfig
+PPPD=@PPPD@
+PPPOE=@sbindir@/pppoe
+ECHO=@ECHO@
+LOGGER="/usr/bin/logger -t `basename $0`"
+
+CONFIG=/etc/ppp/pppoe.conf
+
+# Protect created files
+umask 077
+
+copy() {
+ cp $1 $2
+ if [ "$?" != 0 ] ; then
+ $ECHO "*** Error copying $1 to $2"
+ $ECHO "*** Quitting."
+ exit 1
+ fi
+}
+
+$ECHO "Welcome to the Roaring Penguin ADSL client setup. First, I will run"
+$ECHO "some checks on your system to make sure the PPPoE client is installed"
+$ECHO "properly..."
+$ECHO ""
+
+# Must be root
+if [ "`@ID@ -u`" != 0 ] ; then
+ $ECHO "$0: Sorry, you must be root to run this script"
+ exit 1
+fi
+
+# Prototype config file must exist
+if [ ! -r "$CONFIG" ] ; then
+ $ECHO "Oh, dear, I don't see the file '$CONFIG' anywhere. Please"
+ $ECHO "re-install the PPPoE client."
+ exit 1
+fi
+
+# Must have pppd
+if [ ! -x $PPPD ] ; then
+ $ECHO "Oops, I can't execute the program '$PPPD'. You"
+ $ECHO "must install the PPP software suite, version 2.3.10 or later."
+ exit 1
+fi
+
+. $CONFIG
+
+if [ "$DEMAND" = "" ] ; then
+ DEMAND=no
+fi
+
+# pppoe must exist
+if [ ! -x "$PPPOE" ] ; then
+ $ECHO "Oh, dear, I can't execute the program '$PPPOE'. Please"
+ $ECHO "re-install the rp-pppoe client."
+ exit 1
+fi
+
+$ECHO "Looks good! Now, please enter some information:"
+
+while [ true ] ; do
+ $ECHO ""
+ $ECHO "USER NAME"
+ $ECHO ""
+ $ECHO -n ">>> Enter your PPPoE user name (default $USER): "
+ read U
+
+ if [ "$U" = "" ] ; then
+ U="$USER"
+ fi
+
+ # Under Linux, "fix" the default interface if eth1 is not available
+ if test `uname -s` = "Linux" ; then
+ $IFCONFIG $ETH > /dev/null 2>&1 || ETH=eth0
+ fi
+ $ECHO ""
+ $ECHO "INTERFACE"
+ $ECHO ""
+ $ECHO ">>> Enter the Ethernet interface connected to the ADSL modem"
+ $ECHO "For Solaris, this is likely to be something like /dev/hme0."
+ $ECHO "For Linux, it will be ethn, where 'n' is a number."
+ $ECHO -n "(default $ETH): "
+ read E
+
+ if [ "$E" = "" ] ; then
+ E="$ETH"
+ fi
+
+ $ECHO ""
+ $ECHO "Do you want the link to come up on demand, or stay up continuously?"
+ $ECHO "If you want it to come up on demand, enter the idle time in seconds"
+ $ECHO "after which the link should be dropped. If you want the link to"
+ $ECHO "stay up permanently, enter 'no' (two letters, lower-case.)"
+ $ECHO "NOTE: Demand-activated links do not interact well with dynamic IP"
+ $ECHO "addresses. You may have some problems with demand-activated links."
+ $ECHO -n ">>> Enter the demand value (default $DEMAND): "
+ read D
+ if [ "$D" = "" ] ; then
+ D=$DEMAND
+ fi
+
+ $ECHO ""
+ $ECHO "DNS"
+ $ECHO ""
+ $ECHO "Please enter the IP address of your ISP's primary DNS server."
+ $ECHO "If your ISP claims that 'the server will provide DNS addresses',"
+ $ECHO "enter 'server' (all lower-case) here."
+ $ECHO "If you just press enter, I will assume you know what you are"
+ $ECHO "doing and not modify your DNS setup."
+ $ECHO -n ">>> Enter the DNS information here: "
+
+ read DNS1
+
+
+ if [ "$DNS1" != "" ] ; then
+ if [ "$DNS1" != "server" ] ; then
+ $ECHO "Please enter the IP address of your ISP's secondary DNS server."
+ $ECHO "If you just press enter, I will assume there is only one DNS server."
+ $ECHO -n ">>> Enter the secondary DNS server address here: "
+ read DNS2
+ fi
+ fi
+
+ while [ true ] ; do
+ $ECHO ""
+ $ECHO "PASSWORD"
+ $ECHO ""
+ stty -echo
+ $ECHO -n ">>> Please enter your PPPoE password: "
+ read PWD1
+ $ECHO ""
+ $ECHO -n ">>> Please re-enter your PPPoE password: "
+ read PWD2
+ $ECHO ""
+ stty echo
+ if [ "$PWD1" = "$PWD2" ] ; then
+ break
+ fi
+
+ $ECHO -n ">>> Sorry, the passwords do not match. Try again? (y/n)"
+ read ANS
+ case "$ANS" in
+ N|No|NO|Non|n|no|non)
+ $ECHO "OK, quitting. Bye."
+ exit 1
+ esac
+ done
+
+ # Firewalling
+ $ECHO ""
+ $ECHO "FIREWALLING"
+ $ECHO ""
+ if test `uname -s` != "Linux" ; then
+ $ECHO "Sorry, firewalling is only supported under Linux. Consult"
+ $ECHO "your operating system manuals for details on setting up"
+ $ECHO "packet filters for your system."
+ FIREWALL=NONE
+ else
+ $ECHO "Please choose the firewall rules to use. Note that these rules are"
+ $ECHO "very basic. You are strongly encouraged to use a more sophisticated"
+ $ECHO "firewall setup; however, these will provide basic security. If you"
+ $ECHO "are running any servers on your machine, you must choose 'NONE' and"
+ $ECHO "set up firewalling yourself. Otherwise, the firewall rules will deny"
+ $ECHO "access to all standard servers like Web, e-mail, ftp, etc. If you"
+ $ECHO "are using SSH, the rules will block outgoing SSH connections which"
+ $ECHO "allocate a privileged source port."
+ $ECHO ""
+ while [ true ] ; do
+ $ECHO "The firewall choices are:"
+ $ECHO "0 - NONE: This script will not set any firewall rules. You are responsible"
+ $ECHO " for ensuring the security of your machine. You are STRONGLY"
+ $ECHO " recommended to use some kind of firewall rules."
+ $ECHO "1 - STANDALONE: Appropriate for a basic stand-alone web-surfing workstation"
+ $ECHO "2 - MASQUERADE: Appropriate for a machine acting as an Internet gateway"
+ $ECHO " for a LAN"
+ $ECHO -n ">>> Choose a type of firewall (0-2): "
+ read a
+ if [ "$a" = 0 -o "$a" = 1 -o "$a" = 2 ] ; then
+ break
+ fi
+ $ECHO "Please enter a number from 0 to 2"
+ done
+
+ case "$a" in
+ 0)
+ FIREWALL=NONE
+ ;;
+ 1)
+ FIREWALL=STANDALONE
+ ;;
+ 2)
+ FIREWALL=MASQUERADE
+ ;;
+ esac
+ fi
+
+ $ECHO ""
+ $ECHO "** Summary of what you entered **"
+ $ECHO ""
+ $ECHO "Ethernet Interface: $E"
+ $ECHO "User name: $U"
+ if [ "$D" = "no" ] ; then
+ $ECHO "Activate-on-demand: No"
+ else
+ $ECHO "Activate-on-demand: Yes; idle timeout = $D seconds"
+ fi
+
+ if [ "$DNS1" != "" ] ; then
+ if [ "$DNS1" = "server" ] ; then
+ $ECHO "DNS addresses: Supplied by ISP's server"
+ else
+ $ECHO "Primary DNS: $DNS1"
+ if [ "$DNS2" != "" ] ; then
+ $ECHO "Secondary DNS: $DNS2"
+ fi
+ fi
+ else
+ $ECHO "DNS: Do not adjust"
+ fi
+ $ECHO "Firewalling: $FIREWALL"
+ $ECHO ""
+ while [ true ] ; do
+ $ECHO -n '>>> Accept these settings and adjust configuration files (y/n)? '
+ read ANS
+ case "ANS" in
+ Y|y|yes|Yes|oui|Oui)
+ ANS=y
+ ;;
+ N|n|no|No|non|Non)
+ ANS=n
+ ;;
+ esac
+ if [ "$ANS" = "y" -o "$ANS" = "n" ] ; then
+ break
+ fi
+ done
+ if [ "$ANS" = "y" ] ; then
+ break
+ fi
+done
+
+# Adjust configuration files. First to $CONFIG
+
+$ECHO "Adjusting $CONFIG"
+
+copy $CONFIG $CONFIG-bak
+if [ "$DNS1" = "server" ] ; then
+ DNSTYPE=SERVER
+ DNS1=""
+ USEPEERDNS=yes
+else
+ USEPEERDNS=no
+ if [ "$DNS1" = "" ] ; then
+ DNSTYPE=NOCHANGE
+ else
+ DNSTYPE=SPECIFY
+ fi
+fi
+
+# Where is pppd likely to put its pid?
+if [ -d /var/run ] ; then
+ VARRUN=/var/run
+else
+ VARRUN=/etc/ppp
+fi
+
+# Some #$(*& ISP's use a slash in the user name...
+sed -e "s&^USER=.*&USER='$U'&" \
+ -e "s&^ETH=.*&ETH='$E'&" \
+ -e "s&^PIDFILE=.*&PIDFILE=\"$VARRUN/\$CF_BASE-adsl.pid\"&" \
+ -e "s/^FIREWALL=.*/FIREWALL=$FIREWALL/" \
+ -e "s/^DEMAND=.*/DEMAND=$D/" \
+ -e "s/^DNSTYPE=.*/DNSTYPE=$DNSTYPE/" \
+ -e "s/^DNS1=.*/DNS1=$DNS1/" \
+ -e "s/^DNS2=.*/DNS2=$DNS2/" \
+ -e "s/^USEPEERDNS=.*/USEPEERDNS=$USEPEERDNS/" \
+ < $CONFIG-bak > $CONFIG
+
+if [ $? != 0 ] ; then
+ $ECHO "** Error modifying $CONFIG"
+ $ECHO "** Quitting"
+ exit 1
+fi
+
+if [ "$DNS1" != "" ] ; then
+ if [ "$DNS1" != "server" ] ; then
+ $ECHO "Adjusting /etc/resolv.conf"
+ if [ -r /etc/resolv.conf ] ; then
+ grep -s "MADE-BY-RP-PPPOE" /etc/resolv.conf > /dev/null 2>&1
+ if [ "$?" != 0 ] ; then
+ $ECHO " (But first backing it up to /etc/resolv.conf-bak)"
+ copy /etc/resolv.conf /etc/resolv.conf-bak
+ fi
+ fi
+ $ECHO "# MADE-BY-RP-PPPOE" > /etc/resolv.conf
+ $ECHO "nameserver $DNS1" >> /etc/resolv.conf
+ if [ "$DNS2" != "" ] ; then
+ $ECHO "nameserver $DNS2" >> /etc/resolv.conf
+ fi
+ fi
+fi
+
+$ECHO "Adjusting /etc/ppp/pap-secrets and /etc/ppp/chap-secrets"
+if [ -r /etc/ppp/pap-secrets ] ; then
+ $ECHO " (But first backing it up to /etc/ppp/pap-secrets-bak)"
+ copy /etc/ppp/pap-secrets /etc/ppp/pap-secrets-bak
+else
+ cp /dev/null /etc/ppp/pap-secrets-bak
+fi
+if [ -r /etc/ppp/chap-secrets ] ; then
+ $ECHO " (But first backing it up to /etc/ppp/chap-secrets-bak)"
+ copy /etc/ppp/chap-secrets /etc/ppp/chap-secrets-bak
+else
+ cp /dev/null /etc/ppp/chap-secrets-bak
+fi
+
+egrep -v "^$U|^\"$U\"" /etc/ppp/pap-secrets-bak > /etc/ppp/pap-secrets
+$ECHO "\"$U\" * \"$PWD1\"" >> /etc/ppp/pap-secrets
+egrep -v "^$U|^\"$U\"" /etc/ppp/chap-secrets-bak > /etc/ppp/chap-secrets
+$ECHO "\"$U\" * \"$PWD1\"" >> /etc/ppp/chap-secrets
+
+$ECHO ""
+$ECHO ""
+$ECHO ""
+$ECHO "Congratulations, it should be all set up!"
+$ECHO ""
+$ECHO "Type 'adsl-start' to bring up your ADSL link and 'adsl-stop' to bring"
+$ECHO "it down. Type 'adsl-status' to see the link status."
+exit 0
diff --git a/mdk-stage1/rp-pppoe/scripts/adsl-start.in b/mdk-stage1/rp-pppoe/scripts/adsl-start.in
new file mode 100755
index 000000000..023809eb5
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/scripts/adsl-start.in
@@ -0,0 +1,186 @@
+#!/bin/sh
+# @configure_input@
+#***********************************************************************
+#
+# adsl-start
+#
+# Shell script to bring up an ADSL connection
+#
+# Copyright (C) 2000 Roaring Penguin Software Inc.
+#
+# $Id: adsl-start.in 195724 2001-06-11 13:49:39Z gc $
+#
+# This file may be distributed under the terms of the GNU General
+# Public License.
+#
+# Usage: adsl-start [config_file]
+# adsl-start interface user [config_file]
+# Second form overrides USER and ETH from config file.
+# If config_file is omitted, defaults to /etc/ppp/pppoe.conf
+#
+#***********************************************************************
+
+# From AUTOCONF
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+
+# Paths to programs
+CONNECT=@sbindir@/adsl-connect
+ECHO=@ECHO@
+IFCONFIG=/sbin/ifconfig
+
+# Defaults
+CONFIG=/etc/ppp/pppoe.conf
+USER=""
+ETH=""
+ME=`basename $0`
+# Must be root
+if [ "`@ID@ -u`" != 0 ] ; then
+ $ECHO "$ME: You must be root to run this script" >& 2
+ exit 1
+fi
+
+# Debugging
+if [ "$DEBUG" = "1" ] ; then
+ $ECHO "*** Running in debug mode... please be patient..."
+ DEBUG=/tmp/pppoe-debug-$$
+ export DEBUG
+ mkdir $DEBUG
+ if [ "$?" != 0 ] ; then
+ $ECHO "Could not create directory $DEBUG... exiting"
+ exit 1
+ fi
+ DEBUG=$DEBUG/pppoe-debug.txt
+
+ # Initial debug output
+ $ECHO "---------------------------------------------" > $DEBUG
+ $ECHO "* The following section contains information about your system" >> $DEBUG
+ date >> $DEBUG
+ $ECHO "Output of uname -a" >> $DEBUG
+ uname -a >> $DEBUG
+ $ECHO "---------------------------------------------" >> $DEBUG
+ $ECHO "* The following section contains information about your network" >> $DEBUG
+ $ECHO "* interfaces. The one you chose for PPPoE should contain the words:" >> $DEBUG
+ $ECHO "* 'UP' and 'RUNNING'. If it does not, you probably have an Ethernet" >> $DEBUG
+ $ECHO "* driver problem." >> $DEBUG
+ $ECHO "Output of ifconfig -a" >> $DEBUG
+ $IFCONFIG -a >> $DEBUG
+ $ECHO "---------------------------------------------" >> $DEBUG
+ if [ "`uname -s`" = "Linux" ] ; then
+ $ECHO "* The following section contains information about kernel modules" >> $DEBUG
+ $ECHO "* If the module for your Ethernet card is 'tulip', you might" >> $DEBUG
+ $ECHO "* want to look for an updated version at http://www.scyld.com" >> $DEBUG
+ $ECHO "Output of lsmod" >> $DEBUG
+ lsmod >> $DEBUG
+ $ECHO "---------------------------------------------" >> $DEBUG
+ fi
+ $ECHO "* The following section lists your routing table." >> $DEBUG
+ $ECHO "* If you have an entry which starts with '0.0.0.0', you probably" >> $DEBUG
+ $ECHO "* have defined a default route and gateway, and pppd will" >> $DEBUG
+ $ECHO "* not create a default route using your ISP. Try getting" >> $DEBUG
+ $ECHO "* rid of this route." >> $DEBUG
+ $ECHO "Output of netstat -n -r" >> $DEBUG
+ netstat -n -r >> $DEBUG
+ $ECHO "---------------------------------------------" >> $DEBUG
+ $ECHO "Contents of /etc/resolv.conf" >> $DEBUG
+ $ECHO "* The following section lists DNS setup." >> $DEBUG
+ $ECHO "* If you can browse by IP address, but not name, suspect" >> $DEBUG
+ $ECHO "* a DNS problem." >> $DEBUG
+ cat /etc/resolv.conf >> $DEBUG
+ $ECHO "---------------------------------------------" >> $DEBUG
+ $ECHO "* The following section lists /etc/ppp/options." >> $DEBUG
+ $ECHO "* You should have NOTHING in that file." >> $DEBUG
+ $ECHO "Contents of /etc/ppp/options" >> $DEBUG
+ cat /etc/ppp/options >> $DEBUG 2>/dev/null
+ $ECHO "---------------------------------------------" >> $DEBUG
+else
+ DEBUG=""
+fi
+
+# Sort out command-line arguments
+case "$#" in
+ 1)
+ CONFIG="$1"
+ ;;
+ 3)
+ CONFIG="$3"
+ ;;
+esac
+
+if [ ! -f "$CONFIG" -o ! -r "$CONFIG" ] ; then
+ $ECHO "$ME: Cannot read configuration file '$CONFIG'" >& 2
+ exit 1
+fi
+
+. $CONFIG
+
+# Check for command-line overriding of ETH and USER
+case "$#" in
+ 2|3)
+ ETH="$1"
+ USER="$2"
+ ;;
+esac
+
+# Check for pidfile
+if [ -r "$PIDFILE" ] ; then
+ PID=`cat "$PIDFILE"`
+ # Check if still running
+ kill -0 $PID > /dev/null 2>&1
+ if [ $? = 0 ] ; then
+ $ECHO "$ME: There already seems to be an ADSL connection up (PID $PID)" >& 2
+ exit 1
+ fi
+ # Delete bogus PIDFILE
+ rm -f "$PIDFILE" "$PIDFILE.pppd" "$PIDFILE.pppoe" "$PIDFILE.start"
+fi
+
+echo $$ > $PIDFILE.start
+
+# Start the connection in the background unless we're debugging
+if [ "$DEBUG" != "" ] ; then
+ $CONNECT "$@"
+ exit 0
+fi
+
+$CONNECT "$@" > /dev/null 2>&1 &
+CONNECT_PID=$!
+
+if [ "$CONNECT_TIMEOUT" = "" -o "$CONNECT_TIMEOUT" = 0 ] ; then
+ exit 0
+fi
+
+# Don't monitor connection if dial-on-demand
+if [ "$DEMAND" != "" -a "$DEMAND" != "no" ] ; then
+ exit 0
+fi
+
+# Monitor connection
+TIME=0
+while [ true ] ; do
+ @sbindir@/adsl-status $CONFIG > /dev/null 2>&1
+
+ # Looks like the interface came up
+ if [ $? = 0 ] ; then
+ # Print newline if standard input is a TTY
+ tty -s && $ECHO " Connected!"
+ exit 0
+ fi
+
+ if test -n "$FORCEPING" ; then
+ $ECHO -n "$FORCEPING"
+ else
+ tty -s && $ECHO -n "$PING"
+ fi
+ sleep $CONNECT_POLL
+ TIME=`expr $TIME + $CONNECT_POLL`
+ if [ $TIME -gt $CONNECT_TIMEOUT ] ; then
+ break
+ fi
+done
+
+$ECHO "TIMED OUT" >& 2
+# Timed out! Kill the adsl-connect process and quit
+kill $CONNECT_PID > /dev/null 2>&1
+exit 1
+
diff --git a/mdk-stage1/rp-pppoe/scripts/adsl-status b/mdk-stage1/rp-pppoe/scripts/adsl-status
new file mode 100755
index 000000000..e76a65014
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/scripts/adsl-status
@@ -0,0 +1,82 @@
+#!/bin/sh
+#***********************************************************************
+#
+# adsl-status
+#
+# Shell script to report on status of ADSL connection
+#
+# Copyright (C) 2000-2001 Roaring Penguin Software Inc.
+#
+# $Id: adsl-status 195724 2001-06-11 13:49:39Z gc $
+#
+# This file may be distributed under the terms of the GNU General
+# Public License.
+#
+# Usage: adsl-status [config_file]
+# If config_file is omitted, defaults to /etc/ppp/pppoe.conf
+#
+#***********************************************************************
+
+# Defaults
+CONFIG=/etc/ppp/pppoe.conf
+
+case "$#" in
+ 1)
+ CONFIG="$1"
+ ;;
+esac
+
+if [ ! -f "$CONFIG" -o ! -r "$CONFIG" ] ; then
+ echo "$0: Cannot read configuration file '$CONFIG'" >& 2
+ exit 1
+fi
+
+. $CONFIG
+
+PPPOE_PIDFILE="$PIDFILE.pppoe"
+PPPD_PIDFILE="$PIDFILE.pppd"
+
+if [ "$DEMAND" != "no" ] ; then
+ echo "Note: You have enabled demand-connection; adsl-status may be inaccurate."
+fi
+
+# If no PPPOE_PIDFILE, connection is down, unless we're using the Linux plugin
+if [ "$LINUX_PLUGIN" = "" ] ; then
+ if [ ! -r "$PPPOE_PIDFILE" ] ; then
+ echo "adsl-status: Link is down (can't read pppoe PID file $PPPOE_PIDFILE)"
+ exit 1
+ fi
+fi
+
+# If no PPPD_PIDFILE, something fishy!
+if [ ! -r "$PPPD_PIDFILE" ] ; then
+ echo "adsl-status: Link is down (can't read pppd PID file $PPPD_PIDFILE)"
+ exit 1
+fi
+
+PPPD_PID=`cat "$PPPD_PIDFILE"`
+
+# Sigh. Some versions of pppd put PID files in /var/run; others put them
+# in /etc/ppp. Since it's too messy to figure out what pppd does, we
+# try both locations.
+for i in /etc/ppp/ppp*.pid /var/run/ppp*.pid ; do
+ if [ -r $i ] ; then
+ PID=`cat $i`
+ if [ "$PID" = "$PPPD_PID" ] ; then
+ IF=`basename $i .pid`
+ netstat -rn | grep " ${IF}\$" > /dev/null
+ # /sbin/ifconfig $IF | grep "UP.*POINTOPOINT" > /dev/null
+ if [ "$?" != "0" ] ; then
+ echo "adsl-status: Link is attached to $IF, but $IF is down"
+ exit 1
+ fi
+ echo "adsl-status: Link is up and running on interface $IF"
+ /sbin/ifconfig $IF
+ exit 0
+ fi
+ fi
+done
+
+echo "adsl-status: Link is down -- could not find interface corresponding to"
+echo "pppd pid $PPPD_PID"
+exit 1 \ No newline at end of file
diff --git a/mdk-stage1/rp-pppoe/scripts/adsl-stop.in b/mdk-stage1/rp-pppoe/scripts/adsl-stop.in
new file mode 100755
index 000000000..055d08a01
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/scripts/adsl-stop.in
@@ -0,0 +1,84 @@
+#!/bin/sh
+# @configure_input@
+#***********************************************************************
+#
+# adsl-stop
+#
+# Shell script to bring down an ADSL connection
+#
+# Copyright (C) 2000 Roaring Penguin Software Inc.
+#
+# $Id: adsl-stop.in 195724 2001-06-11 13:49:39Z gc $
+#
+# This file may be distributed under the terms of the GNU General
+# Public License.
+#
+# Usage: adsl-stop [config_file]
+# If config_file is omitted, defaults to /etc/ppp/pppoe.conf
+#
+#***********************************************************************
+
+ME="`basename $0`"
+LOGGER="/usr/bin/logger -t $ME"
+CONFIG="$1"
+if [ "$CONFIG" = "" ] ; then
+ CONFIG=/etc/ppp/pppoe.conf
+fi
+
+if [ ! -f "$CONFIG" -o ! -r "$CONFIG" ] ; then
+ echo "$ME: Cannot read configuration file '$CONFIG'" >& 2
+ exit 1
+fi
+
+. $CONFIG
+
+PPPOE_PIDFILE="$PIDFILE.pppoe"
+PPPD_PIDFILE="$PIDFILE.pppd"
+STARTPID="$PIDFILE.start"
+
+# Backward config file compatibility
+if test "$DEMAND" = "" ; then
+ DEMAND=no
+fi
+
+# Ignore SIGTERM
+trap "" 15
+
+# Check for pidfile
+if [ -r "$PIDFILE" ] ; then
+ PID=`cat $PIDFILE`
+
+ # Check if still running
+ kill -0 $PID > /dev/null 2>&1
+ if [ $? != 0 ] ; then
+ echo "$ME: The adsl-connect script (PID $PID) appears to have died" >& 2
+ fi
+
+ # Kill pppd, which should in turn kill pppoe
+ if [ -r "$PPPD_PIDFILE" ] ; then
+ PPPD_PID=`cat "$PPPD_PIDFILE"`
+ $LOGGER -p daemon.notice "Killing pppd"
+ echo "Killing pppd ($PPPD_PID)"
+ kill $PPPD_PID > /dev/null 2>&1 || exit 1
+ fi
+
+ # Kill adsl-start
+ PIDS=`cat $STARTPID`
+ kill -0 $PIDS > /dev/null 2>&1
+ if [ $? = 0 ] ; then
+ $LOGGER -p daemon.notice "Killing adsl-connect"
+ kill $PIDS > /dev/null 2>&1
+ fi
+
+ # Kill adsl-connect
+ $LOGGER -p daemon.notice "Killing adsl-connect"
+ echo "Killing adsl-connect ($PID)"
+ kill $PID > /dev/null 2>&1
+
+ rm -f "$PIDFILE" "$PPPD_PIDFILE" "$PPPOE_PIDFILE" "$STARTPID"
+else
+ echo "$ME: No ADSL connection appears to be running" >&2
+ exit 1
+fi
+
+exit 0
diff --git a/mdk-stage1/rp-pppoe/src/Makefile b/mdk-stage1/rp-pppoe/src/Makefile
new file mode 100644
index 000000000..b618e12a9
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/src/Makefile
@@ -0,0 +1,45 @@
+ #******************************************************************************
+ #
+ # Guillaume Cottenceau (gc@mandrakesoft.com)
+ #
+ # Copyright 2000 Mandrakesoft
+ #
+ # This software may be freely redistributed under the terms of the GNU
+ # public license.
+ #
+ # 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.
+ #
+ #*****************************************************************************
+
+top_dir = ../..
+
+include $(top_dir)/Makefile.common
+
+
+TARGETS = pppoe
+
+BINTARGET = ../../pppoe
+
+
+all: $(TARGETS)
+
+clean:
+ rm -f *.o *.a $(BINTARGET) pppoe
+
+FLAGS = -Wall -Werror -Os -fomit-frame-pointer '-DPPPOE_PATH="/sbin/pppoe"' '-DPPPD_PATH="/sbin/pppd"' '-DVERSION="3.0-stg1"'
+
+ifeq (GLIBC, $(L))
+EXTRA_LDFLAGS = -static
+endif
+
+OBJS = pppoe.o if.o debug.o common.o ppp.o discovery.o
+
+pppoe: $(OBJS)
+ $(DIET) gcc -o $@ $^ $(EXTRA_LDFLAGS)
+ $(STRIPCMD) $@
+ cp -f $@ $(BINTARGET)
+
+$(OBJS): %.o: %.c
+ $(DIET) gcc $(FLAGS) $(INCLUDES) $(INCS) -c $< -o $@
diff --git a/mdk-stage1/rp-pppoe/src/Makefile.in b/mdk-stage1/rp-pppoe/src/Makefile.in
new file mode 100644
index 000000000..91322233c
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/src/Makefile.in
@@ -0,0 +1,257 @@
+# @configure_input@
+#***********************************************************************
+#
+# Makefile
+#
+# Makefile for Roaring Penguin's Linux user-space PPPoE client.
+#
+# Copyright (C) 2000 Roaring Penguin Software Inc.
+#
+# This program may be distributed according to the terms of the GNU
+# General Public License, version 2 or (at your option) any later version.
+#
+# $Id: Makefile.in 195724 2001-06-11 13:49:39Z gc $
+#***********************************************************************
+
+# Version is set ONLY IN THE MAKEFILE! Don't delete this!
+VERSION=3.0
+
+DEFINES=
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+mandir=@mandir@
+docdir=@prefix@/doc/rp-pppoe-$(VERSION)
+install=@INSTALL@
+install_dir=@INSTALL@ -d
+sbindir=@sbindir@
+
+# Plugin for pppd on Linux
+LINUX_KERNELMODE_PLUGIN=@LINUX_KERNELMODE_PLUGIN@
+PPPD_INCDIR=@PPPD_INCDIR@
+
+# PPPoE relay -- currently only supported on Linux
+PPPOE_RELAY=@PPPOE_RELAY@
+
+# Program paths
+PPPOE_PATH=$(sbindir)/pppoe
+PPPD_PATH=@PPPD@
+
+# Kernel-mode plugin gets installed here.
+PLUGIN_DIR=/etc/ppp/plugins
+PLUGIN_PATH=$(PLUGIN_DIR)/rp-pppoe.so
+
+# Configuration file paths
+PPPOESERVER_PPPD_OPTIONS=/etc/ppp/pppoe-server-options
+
+PATHS='-DPPPOE_PATH="$(PPPOE_PATH)"' '-DPPPD_PATH="$(PPPD_PATH)"' \
+ '-DPLUGIN_PATH="$(PLUGIN_PATH)"' \
+ '-DPPPOE_SERVER_OPTIONS="$(PPPOESERVER_PPPD_OPTIONS)"'
+
+CFLAGS= @CFLAGS@ $(DEFINES) $(PATHS)
+TARGETS=@TARGETS@
+
+all: $(TARGETS)
+ @echo ""
+ @echo "Type 'make install' as root to install the software."
+
+pppoe-sniff: pppoe-sniff.o if.o common.o debug.o
+ @CC@ -o pppoe-sniff pppoe-sniff.o if.o common.o debug.o $(LIBS)
+
+pppoe-server: pppoe-server.o if.o debug.o common.o md5.o
+ @CC@ -o pppoe-server pppoe-server.o if.o debug.o common.o md5.o $(LIBS)
+
+pppoe: pppoe.o if.o debug.o common.o ppp.o discovery.o
+ @CC@ -o pppoe pppoe.o if.o debug.o common.o ppp.o discovery.o $(LIBS)
+
+pppoe-relay: relay.o if.o debug.o common.o
+ @CC@ -o pppoe-relay relay.o if.o debug.o common.o $(LIBS)
+
+pppoe.o: pppoe.c pppoe.h
+ @CC@ $(CFLAGS) '-DVERSION="$(VERSION)"' -c -o pppoe.o pppoe.c
+
+discovery.o: discovery.c pppoe.h
+ @CC@ $(CFLAGS) '-DVERSION="$(VERSION)"' -c -o discovery.o discovery.c
+
+ppp.o: ppp.c pppoe.h
+ @CC@ $(CFLAGS) '-DVERSION="$(VERSION)"' -c -o ppp.o ppp.c
+
+md5.o: md5.c md5.h
+ @CC@ $(CFLAGS) '-DVERSION="$(VERSION)"' -c -o md5.o md5.c
+
+pppoe-server.o: pppoe-server.c pppoe.h
+ @CC@ $(CFLAGS) '-DVERSION="$(VERSION)"' -c -o pppoe-server.o pppoe-server.c
+
+pppoe-sniff.o: pppoe-sniff.c pppoe.h
+ @CC@ $(CFLAGS) '-DVERSION="$(VERSION)"' -c -o pppoe-sniff.o pppoe-sniff.c
+
+if.o: if.c pppoe.h
+ @CC@ $(CFLAGS) '-DVERSION="$(VERSION)"' -c -o if.o if.c
+
+common.o: common.c pppoe.h
+ @CC@ $(CFLAGS) '-DVERSION="$(VERSION)"' -c -o common.o common.c
+
+debug.o: debug.c pppoe.h
+ @CC@ $(CFLAGS) '-DVERSION="$(VERSION)"' -c -o debug.o debug.c
+
+relay.o: relay.c relay.h pppoe.h
+ @CC@ $(CFLAGS) '-DVERSION="$(VERSION)"' -c -o relay.o relay.c
+
+# Linux-specific plugin
+rp-pppoe.so: plugin/libplugin.a plugin/plugin.o
+ @CC@ -o rp-pppoe.so -shared plugin/plugin.o plugin/libplugin.a
+
+plugin/plugin.o: plugin.c
+ @CC@ '-DVERSION="$(VERSION)"' -I$(PPPD_INCDIR) -c -o plugin/plugin.o -fPIC plugin.c
+
+plugin/libplugin.a: plugin/discovery.o plugin/if.o plugin/common.o plugin/debug.o
+ ar -rc $@ $^
+
+plugin/discovery.o: discovery.c
+ @CC@ $(CFLAGS) '-DVERSION="$(VERSION)"' -c -o plugin/discovery.o -fPIC discovery.c
+
+plugin/if.o: if.c
+ @CC@ $(CFLAGS) '-DVERSION="$(VERSION)"' -c -o plugin/if.o -fPIC if.c
+
+plugin/debug.o: debug.c
+ @CC@ $(CFLAGS) '-DVERSION="$(VERSION)"' -c -o plugin/debug.o -fPIC debug.c
+
+plugin/common.o: common.c
+ @CC@ $(CFLAGS) '-DVERSION="$(VERSION)"' -c -o plugin/common.o -fPIC common.c
+
+install: all
+ -mkdir -p $(RPM_INSTALL_ROOT)$(sbindir)
+ $(install) -m 755 -s pppoe $(RPM_INSTALL_ROOT)$(sbindir)
+ $(install) -m 755 -s pppoe-server $(RPM_INSTALL_ROOT)$(sbindir)
+ if test -x pppoe-relay ; then $(install) -m 755 -s pppoe-relay $(RPM_INSTALL_ROOT)$(sbindir); fi
+ $(install) -m 755 -s pppoe-sniff $(RPM_INSTALL_ROOT)$(sbindir)
+ $(install) -m 755 ../scripts/adsl-connect $(RPM_INSTALL_ROOT)$(sbindir)
+ $(install) -m 755 ../scripts/adsl-start $(RPM_INSTALL_ROOT)$(sbindir)
+ $(install) -m 755 ../scripts/adsl-status $(RPM_INSTALL_ROOT)$(sbindir)
+ $(install) -m 755 ../scripts/adsl-stop $(RPM_INSTALL_ROOT)$(sbindir)
+ $(install) -m 755 ../scripts/adsl-setup $(RPM_INSTALL_ROOT)$(sbindir)
+ -mkdir -p $(RPM_INSTALL_ROOT)$(docdir)
+ $(install) -m 644 ../doc/CHANGES $(RPM_INSTALL_ROOT)$(docdir)
+ $(install) -m 644 ../doc/KERNEL-MODE-PPPOE $(RPM_INSTALL_ROOT)$(docdir)
+ $(install) -m 644 ../doc/HOW-TO-CONNECT $(RPM_INSTALL_ROOT)$(docdir)
+ $(install) -m 644 ../doc/LICENSE $(RPM_INSTALL_ROOT)$(docdir)
+ $(install) -m 644 ../README $(RPM_INSTALL_ROOT)$(docdir)
+ $(install) -m 644 ../configs/pap-secrets $(RPM_INSTALL_ROOT)$(docdir)
+ -mkdir -p $(RPM_INSTALL_ROOT)$(mandir)/man8
+ for i in $(TARGETS) ; do \
+ if test -f ../man/$$i.8 ; then \
+ $(install) -m 644 ../man/$$i.8 $(RPM_INSTALL_ROOT)$(mandir)/man8 || exit 1; \
+ fi; \
+ done
+ $(install) -m 644 ../man/adsl-start.8 $(RPM_INSTALL_ROOT)$(mandir)/man8
+ $(install) -m 644 ../man/adsl-stop.8 $(RPM_INSTALL_ROOT)$(mandir)/man8
+ $(install) -m 644 ../man/adsl-status.8 $(RPM_INSTALL_ROOT)$(mandir)/man8
+ $(install) -m 644 ../man/adsl-connect.8 $(RPM_INSTALL_ROOT)$(mandir)/man8
+ $(install) -m 644 ../man/adsl-setup.8 $(RPM_INSTALL_ROOT)$(mandir)/man8
+ -mkdir -p $(RPM_INSTALL_ROOT)$(mandir)/man5
+ $(install) -m 644 ../man/pppoe.conf.5 $(RPM_INSTALL_ROOT)$(mandir)/man5
+ -mkdir -p $(RPM_INSTALL_ROOT)/etc/ppp
+ -mkdir -p $(RPM_INSTALL_ROOT)$(PLUGIN_DIR)
+ -echo "# Directory created by rp-pppoe for kernel-mode plugin" > $(RPM_INSTALL_ROOT)$(PLUGIN_DIR)/README
+ @if test -r rp-pppoe.so; then $(install) -m 755 rp-pppoe.so $(RPM_INSTALL_ROOT)$(PLUGIN_DIR); fi
+ @for i in pppoe.conf firewall-standalone firewall-masq ; do \
+ if [ ! -f $(RPM_INSTALL_ROOT)/etc/ppp/$$i ] ; then \
+ $(install) -m 644 ../configs/$$i $(RPM_INSTALL_ROOT)/etc/ppp ; \
+ else \
+ echo "NOT overwriting existing $(RPM_INSTALL_ROOT)/etc/ppp/$$i" ;\
+ $(install) -m 644 ../configs/$$i $(RPM_INSTALL_ROOT)/etc/ppp/$$i-$(VERSION) ;\
+ fi ;\
+ done
+ @if [ ! -f $(RPM_INSTALL_ROOT)$(PPPOESERVER_PPPD_OPTIONS) ] ; then \
+ $(install) -m 644 ../configs/pppoe-server-options $(RPM_INSTALL_ROOT)$(PPPOESERVER_PPPD_OPTIONS) ; \
+ else \
+ echo "NOT overwriting existing $(RPM_INSTALL_ROOT)$(PPPOESERVER_PPPD_OPTIONS)"; \
+ $(install) -m 644 ../configs/pppoe-server-options $(RPM_INSTALL_ROOT)$(PPPOESERVER_PPPD_OPTIONS)-example ; \
+ fi
+ @if [ -f /etc/redhat-release ] ; then \
+ echo "Looks like a Red Hat system; installing $(RPM_INSTALL_ROOT)/etc/rc.d/init.d/adsl" ; \
+ mkdir -p $(RPM_INSTALL_ROOT)/etc/rc.d/init.d ;\
+ $(install) -m 755 ../scripts/adsl-init $(RPM_INSTALL_ROOT)/etc/rc.d/init.d/adsl ; \
+ fi
+ @if [ -f /etc/turbolinux-release ] ; then \
+ echo "Looks like a TurboLinux system; installing $(RPM_INSTALL_ROOT)/etc/rc.d/init.d/adsl" ; \
+ mkdir -p $(RPM_INSTALL_ROOT)/etc/rc.d/init.d ;\
+ $(install) -m 755 adsl-init-turbolinux $(RPM_INSTALL_ROOT)/etc/rc.d/init.d/adsl ; \
+ fi
+ @if [ -f /etc/SuSE-release ] ; then \
+ echo "Looks like a SuSE Linux system; installing $(RPM_INSTALL_ROOT)/etc/rc.d/init.d/adsl" ; \
+ mkdir -p $(RPM_INSTALL_ROOT)/etc/rc.d/init.d ;\
+ $(install) -m 755 ../scripts/adsl-init-suse $(RPM_INSTALL_ROOT)/etc/rc.d/init.d/adsl ; \
+ fi
+ @echo ""
+ @echo "Type 'adsl-setup' to configure the software."
+
+distro:
+ cd ..; \
+ rm -rf rp-pppoe-$(VERSION) ; \
+ mkdir rp-pppoe-$(VERSION) || exit 1; \
+ for i in README go go-gui rp-pppoe.spec rp-pppoe-gui.spec; do \
+ cp $$i rp-pppoe-$(VERSION) || exit 1; \
+ done ; \
+ mkdir rp-pppoe-$(VERSION)/gui || exit 1; \
+ for i in Makefile.in tkpppoe.in wrapper.c tkpppoe.1 pppoe-wrapper.1 ; do \
+ cp gui/$$i rp-pppoe-$(VERSION)/gui || exit 1; \
+ done; \
+ mkdir rp-pppoe-$(VERSION)/gui/html || exit 1; \
+ for i in mainwin-busy.png mainwin-nonroot.png mainwin.png props-advanced.png props-basic.png props-nic.png props-options.png tkpppoe.html ; do \
+ cp gui/html/$$i rp-pppoe-$(VERSION)/gui/html || exit 1; \
+ done; \
+ mkdir rp-pppoe-$(VERSION)/configs || exit 1; \
+ for i in firewall-masq firewall-standalone pap-secrets pppoe-server-options pppoe.conf ; do \
+ cp configs/$$i rp-pppoe-$(VERSION)/configs || exit 1; \
+ done ; \
+ mkdir rp-pppoe-$(VERSION)/doc || exit 1; \
+ for i in CHANGES KERNEL-MODE-PPPOE HOW-TO-CONNECT LICENSE PROBLEMS ; do \
+ cp doc/$$i rp-pppoe-$(VERSION)/doc || exit 1; \
+ done; \
+ mkdir rp-pppoe-$(VERSION)/man || exit 1; \
+ for i in adsl-connect.8 adsl-setup.8 adsl-start.8 adsl-status.8 adsl-stop.8 pppoe-server.8 pppoe-sniff.8 pppoe.8 pppoe-relay.8 pppoe.conf.5 ; do \
+ cp man/$$i rp-pppoe-$(VERSION)/man || exit 1; \
+ done; \
+ mkdir rp-pppoe-$(VERSION)/scripts || exit 1; \
+ for i in adsl-connect.in adsl-init-suse.in adsl-init-turbolinux.in adsl-init.in adsl-setup.in adsl-start.in adsl-stop.in adsl-status ; do \
+ cp scripts/$$i rp-pppoe-$(VERSION)/scripts || exit 1; \
+ done; \
+ mkdir rp-pppoe-$(VERSION)/src || exit 1; \
+ for i in Makefile.in install-sh common.c config.h.in configure configure.in debug.c discovery.c if.c md5.c md5.h ppp.c pppoe-server.c pppoe-sniff.c pppoe.c pppoe.h plugin.c relay.c relay.h ; do \
+ cp src/$$i rp-pppoe-$(VERSION)/src || exit 1; \
+ done; \
+ mkdir rp-pppoe-$(VERSION)/src/plugin || exit 1; \
+ tar cvf rp-pppoe-$(VERSION).tar rp-pppoe-$(VERSION)/* ; \
+ gzip -f -v -9 rp-pppoe-$(VERSION).tar ; \
+
+rpms: distro
+ cp ../rp-pppoe-$(VERSION).tar.gz /usr/src/redhat/SOURCES
+ cd ..; \
+ rpm -ba rp-pppoe.spec; \
+ rpm -ba rp-pppoe-gui.spec
+
+clean:
+ rm -f *.o pppoe pppoe-sniff pppoe-server core rp-pppoe.so plugin/*.o plugin/libplugin.a *~
+
+distclean: clean
+ rm -f Makefile config.h config.cache config.log config.status
+ rm -f ../scripts/adsl-connect ../scripts/adsl-start ../scripts/adsl-stop ../scripts/adsl-init ../scripts/adsl-setup ../scripts/adsl-init-suse ../scripts/adsl-init-turbolinux
+
+update-version:
+ sed -e 's/^Version: .*$$/Version: $(VERSION)/' ../rp-pppoe.spec > ../rp-pppoe.spec.new && mv ../rp-pppoe.spec.new ../rp-pppoe.spec
+ sed -e 's+^Source: .*$$+Source: http://www.roaringpenguin.com/pppoe/rp-pppoe-$(VERSION).tar.gz+' ../rp-pppoe.spec > ../rp-pppoe.spec.new && mv ../rp-pppoe.spec.new ../rp-pppoe.spec
+ sed -e 's/^Version: .*$$/Version: $(VERSION)/' ../rp-pppoe-gui.spec > ../rp-pppoe-gui.spec.new && mv ../rp-pppoe-gui.spec.new ../rp-pppoe-gui.spec
+ sed -e 's+^Source: .*$$+Source: http://www.roaringpenguin.com/pppoe/rp-pppoe-$(VERSION).tar.gz+' ../rp-pppoe-gui.spec > ../rp-pppoe-gui.spec.new && mv ../rp-pppoe-gui.spec.new ../rp-pppoe-gui.spec
+ sed -e 's+^Requires: rp-pppoe >=.*$$+Requires: rp-pppoe >= $(VERSION)+' ../rp-pppoe-gui.spec > ../rp-pppoe-gui.spec.new && mv ../rp-pppoe-gui.spec.new ../rp-pppoe-gui.spec
+
+# Convenience target for David! Don't try to use this one.
+km:
+ ./configure --enable-plugin=/home/dfs/Archive/PPP/ppp-2.4.0.pppoe4-patched-dfs
+
+.PHONY: update-version
+
+.PHONY: clean
+
+.PHONY: distclean
+
+.PHONY: rpms
diff --git a/mdk-stage1/rp-pppoe/src/common.c b/mdk-stage1/rp-pppoe/src/common.c
new file mode 100644
index 000000000..0e847fdfd
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/src/common.c
@@ -0,0 +1,485 @@
+/***********************************************************************
+*
+* common.c
+*
+* Implementation of user-space PPPoE redirector for Linux.
+*
+* Common functions used by PPPoE client and server
+*
+* Copyright (C) 2000 by Roaring Penguin Software Inc.
+*
+* This program may be distributed according to the terms of the GNU
+* General Public License, version 2 or (at your option) any later version.
+*
+***********************************************************************/
+
+static char const RCSID[] =
+"$Id: common.c 212191 2005-05-06 06:30:51Z rgarciasuarez $";
+
+#include "pppoe.h"
+
+#ifdef HAVE_SYSLOG_H
+#include <syslog.h>
+#endif
+
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+/**********************************************************************
+*%FUNCTION: parsePacket
+*%ARGUMENTS:
+* packet -- the PPPoE discovery packet to parse
+* func -- function called for each tag in the packet
+* extra -- an opaque data pointer supplied to parsing function
+*%RETURNS:
+* 0 if everything went well; -1 if there was an error
+*%DESCRIPTION:
+* Parses a PPPoE discovery packet, calling "func" for each tag in the packet.
+* "func" is passed the additional argument "extra".
+***********************************************************************/
+int
+parsePacket(PPPoEPacket *packet, ParseFunc *func, void *extra)
+{
+ UINT16_t len = ntohs(packet->length);
+ unsigned char *curTag;
+ UINT16_t tagType, tagLen;
+
+ if (packet->ver != 1) {
+ syslog(LOG_ERR, "Invalid PPPoE version (%d)", (int) packet->ver);
+ return -1;
+ }
+ if (packet->type != 1) {
+ syslog(LOG_ERR, "Invalid PPPoE type (%d)", (int) packet->type);
+ return -1;
+ }
+
+ /* Do some sanity checks on packet */
+ if (len > ETH_DATA_LEN - 6) { /* 6-byte overhead for PPPoE header */
+ syslog(LOG_ERR, "Invalid PPPoE packet length (%u)", len);
+ return -1;
+ }
+
+ /* Step through the tags */
+ curTag = packet->payload;
+ while(curTag - packet->payload < len) {
+ /* Alignment is not guaranteed, so do this by hand... */
+ tagType = (((UINT16_t) curTag[0]) << 8) +
+ (UINT16_t) curTag[1];
+ tagLen = (((UINT16_t) curTag[2]) << 8) +
+ (UINT16_t) curTag[3];
+ if (tagType == TAG_END_OF_LIST) {
+ return 0;
+ }
+ if ((curTag - packet->payload) + tagLen + TAG_HDR_SIZE > len) {
+ syslog(LOG_ERR, "Invalid PPPoE tag length (%u)", tagLen);
+ return -1;
+ }
+ func(tagType, tagLen, curTag+TAG_HDR_SIZE, extra);
+ curTag = curTag + TAG_HDR_SIZE + tagLen;
+ }
+ return 0;
+}
+
+/**********************************************************************
+*%FUNCTION: findTag
+*%ARGUMENTS:
+* packet -- the PPPoE discovery packet to parse
+* type -- the type of the tag to look for
+* tag -- will be filled in with tag contents
+*%RETURNS:
+* A pointer to the tag if one of the specified type is found; NULL
+* otherwise.
+*%DESCRIPTION:
+* Looks for a specific tag type.
+***********************************************************************/
+unsigned char *
+findTag(PPPoEPacket *packet, UINT16_t type, PPPoETag *tag)
+{
+ UINT16_t len = ntohs(packet->length);
+ unsigned char *curTag;
+ UINT16_t tagType, tagLen;
+
+ if (packet->ver != 1) {
+ syslog(LOG_ERR, "Invalid PPPoE version (%d)", (int) packet->ver);
+ return NULL;
+ }
+ if (packet->type != 1) {
+ syslog(LOG_ERR, "Invalid PPPoE type (%d)", (int) packet->type);
+ return NULL;
+ }
+
+ /* Do some sanity checks on packet */
+ if (len > ETH_DATA_LEN - 6) { /* 6-byte overhead for PPPoE header */
+ syslog(LOG_ERR, "Invalid PPPoE packet length (%u)", len);
+ return NULL;
+ }
+
+ /* Step through the tags */
+ curTag = packet->payload;
+ while(curTag - packet->payload < len) {
+ /* Alignment is not guaranteed, so do this by hand... */
+ tagType = (((UINT16_t) curTag[0]) << 8) +
+ (UINT16_t) curTag[1];
+ tagLen = (((UINT16_t) curTag[2]) << 8) +
+ (UINT16_t) curTag[3];
+ if (tagType == TAG_END_OF_LIST) {
+ return NULL;
+ }
+ if ((curTag - packet->payload) + tagLen + TAG_HDR_SIZE > len) {
+ syslog(LOG_ERR, "Invalid PPPoE tag length (%u)", tagLen);
+ return NULL;
+ }
+ if (tagType == type) {
+ memcpy(tag, curTag, tagLen + TAG_HDR_SIZE);
+ return curTag;
+ }
+ curTag = curTag + TAG_HDR_SIZE + tagLen;
+ }
+ return NULL;
+}
+
+/**********************************************************************
+*%FUNCTION: printErr
+*%ARGUMENTS:
+* str -- error message
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Prints a message to stderr and syslog.
+***********************************************************************/
+void
+printErr(char const *str)
+{
+ fprintf(stderr, "pppoe: %s\n", str);
+ syslog(LOG_ERR, "%s", str);
+}
+
+
+/**********************************************************************
+*%FUNCTION: strDup
+*%ARGUMENTS:
+* str -- string to copy
+*%RETURNS:
+* A malloc'd copy of str. Exits if malloc fails.
+***********************************************************************/
+char *
+strDup(char const *str)
+{
+ char *copy = malloc(strlen(str)+1);
+ if (!copy) {
+ rp_fatal("strdup failed");
+ }
+ strcpy(copy, str);
+ return copy;
+}
+
+/**********************************************************************
+*%FUNCTION: computeTCPChecksum
+*%ARGUMENTS:
+* ipHdr -- pointer to IP header
+* tcpHdr -- pointer to TCP header
+*%RETURNS:
+* The computed TCP checksum
+***********************************************************************/
+UINT16_t
+computeTCPChecksum(unsigned char *ipHdr, unsigned char *tcpHdr)
+{
+ UINT32_t sum = 0;
+ UINT16_t count = ipHdr[2] * 256 + ipHdr[3];
+ unsigned char *addr = tcpHdr;
+ unsigned char pseudoHeader[12];
+
+ /* Count number of bytes in TCP header and data */
+ count -= (ipHdr[0] & 0x0F) * 4;
+
+ memcpy(pseudoHeader, ipHdr+12, 8);
+ pseudoHeader[8] = 0;
+ pseudoHeader[9] = ipHdr[9];
+ pseudoHeader[10] = (count >> 8) & 0xFF;
+ pseudoHeader[11] = (count & 0xFF);
+
+ /* Checksum the pseudo-header */
+ sum += * (UINT16_t *) pseudoHeader;
+ sum += * ((UINT16_t *) (pseudoHeader+2));
+ sum += * ((UINT16_t *) (pseudoHeader+4));
+ sum += * ((UINT16_t *) (pseudoHeader+6));
+ sum += * ((UINT16_t *) (pseudoHeader+8));
+ sum += * ((UINT16_t *) (pseudoHeader+10));
+
+ /* Checksum the TCP header and data */
+ while (count > 1) {
+ sum += * (UINT16_t *) addr;
+ addr += 2;
+ count -= 2;
+ }
+ if (count > 0) {
+ sum += *addr;
+ }
+
+ while(sum >> 16) {
+ sum = (sum & 0xffff) + (sum >> 16);
+ }
+ return (UINT16_t) (~sum & 0xFFFF);
+}
+
+/**********************************************************************
+*%FUNCTION: clampMSS
+*%ARGUMENTS:
+* packet -- PPPoE session packet
+* dir -- either "incoming" or "outgoing"
+* clampMss -- clamp value
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Clamps MSS option if TCP SYN flag is set.
+***********************************************************************/
+void
+clampMSS(PPPoEPacket *packet, char const *dir, int clampMss)
+{
+ unsigned char *tcpHdr;
+ unsigned char *ipHdr;
+ unsigned char *opt;
+ unsigned char *endHdr;
+ unsigned char *mssopt = NULL;
+ UINT16_t csum;
+
+ int len;
+
+ /* Is it IPv4? */
+ if (packet->payload[0] != 0x00 ||
+ packet->payload[1] != 0x21) {
+ /* Nope, ignore it */
+ return;
+ }
+
+ ipHdr = packet->payload + 2;
+
+ /* Is it too short? */
+ len = (int) ntohs(packet->length);
+ if (len < 42) {
+ /* 20 byte IP header; 20 byte TCP header; 2 byte PPP protocol */
+ return;
+ }
+
+ /* Verify once more that it's IPv4 */
+ if ((ipHdr[0] & 0xF0) != 0x40) {
+ return;
+ }
+
+ /* Is it a fragment that's not at the beginning of the packet? */
+ if ((ipHdr[6] & 0x1F) || ipHdr[7]) {
+ /* Yup, don't touch! */
+ return;
+ }
+ /* Is it TCP? */
+ if (ipHdr[9] != 0x06) {
+ return;
+ }
+
+ /* Get start of TCP header */
+ tcpHdr = ipHdr + (ipHdr[0] & 0x0F) * 4;
+
+ /* Is SYN set? */
+ if (!(tcpHdr[13] & 0x02)) {
+ return;
+ }
+
+ /* Compute and verify TCP checksum -- do not touch a packet with a bad
+ checksum */
+ csum = computeTCPChecksum(ipHdr, tcpHdr);
+ if (csum) {
+ syslog(LOG_ERR, "Bad TCP checksum %x", (unsigned int) csum);
+
+ /* Upper layers will drop it */
+ return;
+ }
+
+ /* Look for existing MSS option */
+ endHdr = tcpHdr + ((tcpHdr[12] & 0xF0) >> 2);
+ opt = tcpHdr + 20;
+ while (opt < endHdr) {
+ if (!*opt) break; /* End of options */
+ switch(*opt) {
+ case 1:
+ opt++;
+ break;
+
+ case 2:
+ if (opt[1] != 4) {
+ /* Something fishy about MSS option length. */
+ syslog(LOG_ERR,
+ "Bogus length for MSS option (%u) from %u.%u.%u.%u",
+ (unsigned int) opt[1],
+ (unsigned int) ipHdr[12],
+ (unsigned int) ipHdr[13],
+ (unsigned int) ipHdr[14],
+ (unsigned int) ipHdr[15]);
+ return;
+ }
+ mssopt = opt;
+ break;
+ default:
+ if (opt[1] < 2) {
+ /* Someone's trying to attack us? */
+ syslog(LOG_ERR,
+ "Bogus TCP option length (%u) from %u.%u.%u.%u",
+ (unsigned int) opt[1],
+ (unsigned int) ipHdr[12],
+ (unsigned int) ipHdr[13],
+ (unsigned int) ipHdr[14],
+ (unsigned int) ipHdr[15]);
+ return;
+ }
+ opt += (opt[1]);
+ break;
+ }
+ /* Found existing MSS option? */
+ if (mssopt) break;
+ }
+
+ /* If MSS exists and it's low enough, do nothing */
+ if (mssopt) {
+ unsigned mss = mssopt[2] * 256 + mssopt[3];
+ if (mss <= clampMss) {
+ return;
+ }
+
+ mssopt[2] = (((unsigned) clampMss) >> 8) & 0xFF;
+ mssopt[3] = ((unsigned) clampMss) & 0xFF;
+ } else {
+ /* No MSS option. Don't add one; we'll have to use 536. */
+ return;
+ }
+
+ /* Recompute TCP checksum */
+ tcpHdr[16] = 0;
+ tcpHdr[17] = 0;
+ csum = computeTCPChecksum(ipHdr, tcpHdr);
+ (* (UINT16_t *) (tcpHdr+16)) = csum;
+}
+
+/***********************************************************************
+*%FUNCTION: sendPADT
+*%ARGUMENTS:
+* conn -- PPPoE connection
+* msg -- if non-NULL, extra error message to include in PADT packet.
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Sends a PADT packet
+***********************************************************************/
+void
+sendPADT(PPPoEConnection *conn, char const *msg)
+{
+ PPPoEPacket packet;
+ unsigned char *cursor = packet.payload;
+
+ UINT16_t plen = 0;
+
+ /* Do nothing if no session established yet */
+ if (!conn->session) return;
+
+ /* Do nothing if no discovery socket */
+ if (conn->discoverySocket < 0) return;
+
+ memcpy(packet.ethHdr.h_dest, conn->peerEth, ETH_ALEN);
+ memcpy(packet.ethHdr.h_source, conn->myEth, ETH_ALEN);
+
+ packet.ethHdr.h_proto = htons(Eth_PPPOE_Discovery);
+ packet.ver = 1;
+ packet.type = 1;
+ packet.code = CODE_PADT;
+ packet.session = conn->session;
+
+ /* Reset Session to zero so there is no possibility of
+ recursive calls to this function by any signal handler */
+ conn->session = 0;
+
+ /* If we're using Host-Uniq, copy it over */
+ if (conn->useHostUniq) {
+ PPPoETag hostUniq;
+ pid_t pid = getpid();
+ hostUniq.type = htons(TAG_HOST_UNIQ);
+ hostUniq.length = htons(sizeof(pid));
+ memcpy(hostUniq.payload, &pid, sizeof(pid));
+ memcpy(cursor, &hostUniq, sizeof(pid) + TAG_HDR_SIZE);
+ cursor += sizeof(pid) + TAG_HDR_SIZE;
+ plen += sizeof(pid) + TAG_HDR_SIZE;
+ }
+
+ /* Copy error message */
+ if (msg) {
+ PPPoETag err;
+ size_t elen = strlen(msg);
+ err.type = htons(TAG_GENERIC_ERROR);
+ err.length = htons(elen);
+ strcpy((char *)err.payload, msg);
+ memcpy(cursor, &err, elen + TAG_HDR_SIZE);
+ cursor += elen + TAG_HDR_SIZE;
+ plen += elen + TAG_HDR_SIZE;
+ }
+
+ /* Copy cookie and relay-ID if needed */
+ if (conn->cookie.type) {
+ CHECK_ROOM(cursor, packet.payload,
+ ntohs(conn->cookie.length) + TAG_HDR_SIZE);
+ memcpy(cursor, &conn->cookie, ntohs(conn->cookie.length) + TAG_HDR_SIZE);
+ cursor += ntohs(conn->cookie.length) + TAG_HDR_SIZE;
+ plen += ntohs(conn->cookie.length) + TAG_HDR_SIZE;
+ }
+
+ if (conn->relayId.type) {
+ CHECK_ROOM(cursor, packet.payload,
+ ntohs(conn->relayId.length) + TAG_HDR_SIZE);
+ memcpy(cursor, &conn->relayId, ntohs(conn->relayId.length) + TAG_HDR_SIZE);
+ cursor += ntohs(conn->relayId.length) + TAG_HDR_SIZE;
+ plen += ntohs(conn->relayId.length) + TAG_HDR_SIZE;
+ }
+
+ packet.length = htons(plen);
+ sendPacket(conn, conn->discoverySocket, &packet, (int) (plen + HDR_SIZE));
+ if (conn->debugFile) {
+ dumpPacket(conn->debugFile, &packet, "SENT");
+ fprintf(conn->debugFile, "\n");
+ fflush(conn->debugFile);
+ }
+ syslog(LOG_INFO,"Sent PADT");
+}
+
+/**********************************************************************
+*%FUNCTION: parseLogErrs
+*%ARGUMENTS:
+* type -- tag type
+* len -- tag length
+* data -- tag data
+* extra -- extra user data
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Picks error tags out of a packet and logs them.
+***********************************************************************/
+void
+parseLogErrs(UINT16_t type, UINT16_t len, unsigned char *data,
+ void *extra)
+{
+ switch(type) {
+ case TAG_SERVICE_NAME_ERROR:
+ syslog(LOG_ERR, "PADT: Service-Name-Error: %.*s", (int) len, data);
+ fprintf(stderr, "PADT: Service-Name-Error: %.*s\n", (int) len, data);
+ break;
+ case TAG_AC_SYSTEM_ERROR:
+ syslog(LOG_ERR, "PADT: System-Error: %.*s", (int) len, data);
+ fprintf(stderr, "PADT: System-Error: %.*s\n", (int) len, data);
+ break;
+ case TAG_GENERIC_ERROR:
+ syslog(LOG_ERR, "PADT: Generic-Error: %.*s", (int) len, data);
+ fprintf(stderr, "PADT: Generic-Error: %.*s\n", (int) len, data);
+ break;
+ }
+}
+
diff --git a/mdk-stage1/rp-pppoe/src/config.h b/mdk-stage1/rp-pppoe/src/config.h
new file mode 100644
index 000000000..e3adf4353
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/src/config.h
@@ -0,0 +1,135 @@
+/* config.h. Generated automatically by configure. */
+/* config.h.in. Generated automatically from configure.in by autoheader. */
+
+/* Define to empty if the keyword does not work. */
+/* #undef const */
+
+/* Define if you have <sys/wait.h> that is POSIX.1 compatible. */
+#define HAVE_SYS_WAIT_H 1
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+/* #undef pid_t */
+
+/* Define as the return type of signal handlers (int or void). */
+#define RETSIGTYPE void
+
+/* Define if the setvbuf function takes the buffering type as its second
+ argument and the buffer pointer as the third, as on System V
+ before release 3. */
+/* #undef SETVBUF_REVERSED */
+
+/* Define if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Define if you can safely include both <sys/time.h> and <time.h>. */
+#define TIME_WITH_SYS_TIME 1
+
+/* Define if your <sys/time.h> declares struct tm. */
+/* #undef TM_IN_SYS_TIME */
+
+#define HAVE_STRUCT_SOCKADDR_LL 1
+
+/* The number of bytes in a unsigned int. */
+#define SIZEOF_UNSIGNED_INT 4
+
+/* The number of bytes in a unsigned long. */
+#define SIZEOF_UNSIGNED_LONG 4
+
+/* The number of bytes in a unsigned short. */
+#define SIZEOF_UNSIGNED_SHORT 2
+
+/* Define if you have the select function. */
+#define HAVE_SELECT 1
+
+/* Define if you have the socket function. */
+#define HAVE_SOCKET 1
+
+/* Define if you have the strerror function. */
+#define HAVE_STRERROR 1
+
+/* Define if you have the strtol function. */
+#define HAVE_STRTOL 1
+
+/* Define if you have the <asm/types.h> header file. */
+#define HAVE_ASM_TYPES_H 1
+
+/* Define if you have the <fcntl.h> header file. */
+#define HAVE_FCNTL_H 1
+
+/* Define if you have the <getopt.h> header file. */
+#define HAVE_GETOPT_H 1
+
+/* Define if you have the <linux/if_ether.h> header file. */
+#define HAVE_LINUX_IF_ETHER_H 1
+
+/* Define if you have kernel-mode PPPoE in Linux file. */
+/* #undef HAVE_LINUX_KERNEL_PPPOE */
+
+/* Define if you have the <linux/if_packet.h> header file. */
+#define HAVE_LINUX_IF_PACKET_H 1
+
+/* Define if you have the <linux/if_pppox.h> header file. */
+#define HAVE_LINUX_IF_PPPOX_H 1
+
+/* Define if you have the <net/bpf.h> header file. */
+#define HAVE_NET_BPF_H 1
+
+/* Define if you have the <net/if_arp.h> header file. */
+//#define HAVE_NET_IF_ARP_H 1
+
+/* Define if you have the <net/ethernet.h> header file. */
+#define HAVE_NET_ETHERNET_H 1
+
+/* Define if you have the <net/if.h> header file. */
+#define HAVE_NET_IF_H 1
+
+/* Define if you have the <linux/if.h> header file. */
+#define HAVE_LINUX_IF_H 1
+
+/* Define if you have the <net/if_dl.h> header file. */
+/* #undef HAVE_NET_IF_DL_H */
+
+/* Define if you have the <net/if_ether.h> header file. */
+/* #undef HAVE_NET_IF_ETHER_H */
+
+/* Define if you have the <net/if_types.h> header file. */
+/* #undef HAVE_NET_IF_TYPES_H */
+
+/* Define if you have the <netinet/if_ether.h> header file. */
+//#define HAVE_NETINET_IF_ETHER_H 1
+
+/* Define if you have the <netpacket/packet.h> header file. */
+#define HAVE_NETPACKET_PACKET_H 1
+
+/* Define if you have the <sys/cdefs.h> header file. */
+#define HAVE_SYS_CDEFS_H 1
+
+/* Define if you have the <sys/dlpi.h> header file. */
+/* #undef HAVE_SYS_DLPI_H */
+
+/* Define if you have the <sys/ioctl.h> header file. */
+#define HAVE_SYS_IOCTL_H 1
+
+/* Define if you have the <sys/param.h> header file. */
+#define HAVE_SYS_PARAM_H 1
+
+/* Define if you have the <sys/socket.h> header file. */
+#define HAVE_SYS_SOCKET_H 1
+
+/* Define if you have the <sys/time.h> header file. */
+#define HAVE_SYS_TIME_H 1
+
+/* Define if you have the <sys/uio.h> header file. */
+#define HAVE_SYS_UIO_H 1
+
+/* Define if you have the <syslog.h> header file. */
+#define HAVE_SYSLOG_H 1
+
+/* Define if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define if you have the N_HDLC line discipline in linux/termios.h */
+#define HAVE_N_HDLC 1
+
+/* Define if bitfields are packed in reverse order */
+#define PACK_BITFIELDS_REVERSED 1
diff --git a/mdk-stage1/rp-pppoe/src/config.h.in b/mdk-stage1/rp-pppoe/src/config.h.in
new file mode 100644
index 000000000..e3340389d
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/src/config.h.in
@@ -0,0 +1,134 @@
+/* config.h.in. Generated automatically from configure.in by autoheader. */
+
+/* Define to empty if the keyword does not work. */
+#undef const
+
+/* Define if you have <sys/wait.h> that is POSIX.1 compatible. */
+#undef HAVE_SYS_WAIT_H
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+#undef pid_t
+
+/* Define as the return type of signal handlers (int or void). */
+#undef RETSIGTYPE
+
+/* Define if the setvbuf function takes the buffering type as its second
+ argument and the buffer pointer as the third, as on System V
+ before release 3. */
+#undef SETVBUF_REVERSED
+
+/* Define if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Define if you can safely include both <sys/time.h> and <time.h>. */
+#undef TIME_WITH_SYS_TIME
+
+/* Define if your <sys/time.h> declares struct tm. */
+#undef TM_IN_SYS_TIME
+
+#undef HAVE_STRUCT_SOCKADDR_LL
+
+/* The number of bytes in a unsigned int. */
+#undef SIZEOF_UNSIGNED_INT
+
+/* The number of bytes in a unsigned long. */
+#undef SIZEOF_UNSIGNED_LONG
+
+/* The number of bytes in a unsigned short. */
+#undef SIZEOF_UNSIGNED_SHORT
+
+/* Define if you have the select function. */
+#undef HAVE_SELECT
+
+/* Define if you have the socket function. */
+#undef HAVE_SOCKET
+
+/* Define if you have the strerror function. */
+#undef HAVE_STRERROR
+
+/* Define if you have the strtol function. */
+#undef HAVE_STRTOL
+
+/* Define if you have the <asm/types.h> header file. */
+#undef HAVE_ASM_TYPES_H
+
+/* Define if you have the <fcntl.h> header file. */
+#undef HAVE_FCNTL_H
+
+/* Define if you have the <getopt.h> header file. */
+#undef HAVE_GETOPT_H
+
+/* Define if you have the <linux/if_ether.h> header file. */
+#undef HAVE_LINUX_IF_ETHER_H
+
+/* Define if you have kernel-mode PPPoE in Linux file. */
+#undef HAVE_LINUX_KERNEL_PPPOE
+
+/* Define if you have the <linux/if_packet.h> header file. */
+#undef HAVE_LINUX_IF_PACKET_H
+
+/* Define if you have the <linux/if_pppox.h> header file. */
+#undef HAVE_LINUX_IF_PPPOX_H
+
+/* Define if you have the <net/bpf.h> header file. */
+#undef HAVE_NET_BPF_H
+
+/* Define if you have the <net/if_arp.h> header file. */
+#undef HAVE_NET_IF_ARP_H
+
+/* Define if you have the <net/ethernet.h> header file. */
+#undef HAVE_NET_ETHERNET_H
+
+/* Define if you have the <net/if.h> header file. */
+#undef HAVE_NET_IF_H
+
+/* Define if you have the <linux/if.h> header file. */
+#undef HAVE_LINUX_IF_H
+
+/* Define if you have the <net/if_dl.h> header file. */
+#undef HAVE_NET_IF_DL_H
+
+/* Define if you have the <net/if_ether.h> header file. */
+#undef HAVE_NET_IF_ETHER_H
+
+/* Define if you have the <net/if_types.h> header file. */
+#undef HAVE_NET_IF_TYPES_H
+
+/* Define if you have the <netinet/if_ether.h> header file. */
+#undef HAVE_NETINET_IF_ETHER_H
+
+/* Define if you have the <netpacket/packet.h> header file. */
+#undef HAVE_NETPACKET_PACKET_H
+
+/* Define if you have the <sys/cdefs.h> header file. */
+#undef HAVE_SYS_CDEFS_H
+
+/* Define if you have the <sys/dlpi.h> header file. */
+#undef HAVE_SYS_DLPI_H
+
+/* Define if you have the <sys/ioctl.h> header file. */
+#undef HAVE_SYS_IOCTL_H
+
+/* Define if you have the <sys/param.h> header file. */
+#undef HAVE_SYS_PARAM_H
+
+/* Define if you have the <sys/socket.h> header file. */
+#undef HAVE_SYS_SOCKET_H
+
+/* Define if you have the <sys/time.h> header file. */
+#undef HAVE_SYS_TIME_H
+
+/* Define if you have the <sys/uio.h> header file. */
+#undef HAVE_SYS_UIO_H
+
+/* Define if you have the <syslog.h> header file. */
+#undef HAVE_SYSLOG_H
+
+/* Define if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Define if you have the N_HDLC line discipline in linux/termios.h */
+#undef HAVE_N_HDLC
+
+/* Define if bitfields are packed in reverse order */
+#undef PACK_BITFIELDS_REVERSED
diff --git a/mdk-stage1/rp-pppoe/src/configure b/mdk-stage1/rp-pppoe/src/configure
new file mode 100755
index 000000000..eede451a1
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/src/configure
@@ -0,0 +1,2356 @@
+#! /bin/sh
+
+# Guess values for system-dependent variables and create Makefiles.
+# Generated automatically using autoconf version 2.13
+# Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc.
+#
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+
+# Defaults:
+ac_help=
+ac_default_prefix=/usr/local
+# Any additions from configure.in:
+ac_default_prefix=/usr
+ac_help="$ac_help
+ --enable-plugin=pppd_src_path build pppd plugin"
+
+# Initialize some variables set by options.
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+build=NONE
+cache_file=./config.cache
+exec_prefix=NONE
+host=NONE
+no_create=
+nonopt=NONE
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+target=NONE
+verbose=
+x_includes=NONE
+x_libraries=NONE
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datadir='${prefix}/share'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+libdir='${exec_prefix}/lib'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+infodir='${prefix}/info'
+mandir='${prefix}/man'
+
+# Initialize some other variables.
+subdirs=
+MFLAGS= MAKEFLAGS=
+SHELL=${CONFIG_SHELL-/bin/sh}
+# Maximum number of lines to put in a shell here document.
+ac_max_here_lines=12
+
+ac_prev=
+for ac_option
+do
+
+ # If the previous option needs an argument, assign it.
+ if test -n "$ac_prev"; then
+ eval "$ac_prev=\$ac_option"
+ ac_prev=
+ continue
+ fi
+
+ case "$ac_option" in
+ -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
+ *) ac_optarg= ;;
+ esac
+
+ # Accept the important Cygnus configure options, so we can diagnose typos.
+
+ case "$ac_option" in
+
+ -bindir | --bindir | --bindi | --bind | --bin | --bi)
+ ac_prev=bindir ;;
+ -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+ bindir="$ac_optarg" ;;
+
+ -build | --build | --buil | --bui | --bu)
+ ac_prev=build ;;
+ -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+ build="$ac_optarg" ;;
+
+ -cache-file | --cache-file | --cache-fil | --cache-fi \
+ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+ ac_prev=cache_file ;;
+ -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+ cache_file="$ac_optarg" ;;
+
+ -datadir | --datadir | --datadi | --datad | --data | --dat | --da)
+ ac_prev=datadir ;;
+ -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \
+ | --da=*)
+ datadir="$ac_optarg" ;;
+
+ -disable-* | --disable-*)
+ ac_feature=`echo $ac_option|sed -e 's/-*disable-//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then
+ { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+ fi
+ ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+ eval "enable_${ac_feature}=no" ;;
+
+ -enable-* | --enable-*)
+ ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then
+ { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+ fi
+ ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+ case "$ac_option" in
+ *=*) ;;
+ *) ac_optarg=yes ;;
+ esac
+ eval "enable_${ac_feature}='$ac_optarg'" ;;
+
+ -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+ | --exec | --exe | --ex)
+ ac_prev=exec_prefix ;;
+ -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+ | --exec=* | --exe=* | --ex=*)
+ exec_prefix="$ac_optarg" ;;
+
+ -gas | --gas | --ga | --g)
+ # Obsolete; use --with-gas.
+ with_gas=yes ;;
+
+ -help | --help | --hel | --he)
+ # Omit some internal or obsolete options to make the list less imposing.
+ # This message is too long to be a string in the A/UX 3.1 sh.
+ cat << EOF
+Usage: configure [options] [host]
+Options: [defaults in brackets after descriptions]
+Configuration:
+ --cache-file=FILE cache test results in FILE
+ --help print this message
+ --no-create do not create output files
+ --quiet, --silent do not print \`checking...' messages
+ --version print the version of autoconf that created configure
+Directory and file names:
+ --prefix=PREFIX install architecture-independent files in PREFIX
+ [$ac_default_prefix]
+ --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
+ [same as prefix]
+ --bindir=DIR user executables in DIR [EPREFIX/bin]
+ --sbindir=DIR system admin executables in DIR [EPREFIX/sbin]
+ --libexecdir=DIR program executables in DIR [EPREFIX/libexec]
+ --datadir=DIR read-only architecture-independent data in DIR
+ [PREFIX/share]
+ --sysconfdir=DIR read-only single-machine data in DIR [PREFIX/etc]
+ --sharedstatedir=DIR modifiable architecture-independent data in DIR
+ [PREFIX/com]
+ --localstatedir=DIR modifiable single-machine data in DIR [PREFIX/var]
+ --libdir=DIR object code libraries in DIR [EPREFIX/lib]
+ --includedir=DIR C header files in DIR [PREFIX/include]
+ --oldincludedir=DIR C header files for non-gcc in DIR [/usr/include]
+ --infodir=DIR info documentation in DIR [PREFIX/info]
+ --mandir=DIR man documentation in DIR [PREFIX/man]
+ --srcdir=DIR find the sources in DIR [configure dir or ..]
+ --program-prefix=PREFIX prepend PREFIX to installed program names
+ --program-suffix=SUFFIX append SUFFIX to installed program names
+ --program-transform-name=PROGRAM
+ run sed PROGRAM on installed program names
+EOF
+ cat << EOF
+Host type:
+ --build=BUILD configure for building on BUILD [BUILD=HOST]
+ --host=HOST configure for HOST [guessed]
+ --target=TARGET configure for TARGET [TARGET=HOST]
+Features and packages:
+ --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no)
+ --enable-FEATURE[=ARG] include FEATURE [ARG=yes]
+ --with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
+ --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
+ --x-includes=DIR X include files are in DIR
+ --x-libraries=DIR X library files are in DIR
+EOF
+ if test -n "$ac_help"; then
+ echo "--enable and --with options recognized:$ac_help"
+ fi
+ exit 0 ;;
+
+ -host | --host | --hos | --ho)
+ ac_prev=host ;;
+ -host=* | --host=* | --hos=* | --ho=*)
+ host="$ac_optarg" ;;
+
+ -includedir | --includedir | --includedi | --included | --include \
+ | --includ | --inclu | --incl | --inc)
+ ac_prev=includedir ;;
+ -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+ | --includ=* | --inclu=* | --incl=* | --inc=*)
+ includedir="$ac_optarg" ;;
+
+ -infodir | --infodir | --infodi | --infod | --info | --inf)
+ ac_prev=infodir ;;
+ -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+ infodir="$ac_optarg" ;;
+
+ -libdir | --libdir | --libdi | --libd)
+ ac_prev=libdir ;;
+ -libdir=* | --libdir=* | --libdi=* | --libd=*)
+ libdir="$ac_optarg" ;;
+
+ -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+ | --libexe | --libex | --libe)
+ ac_prev=libexecdir ;;
+ -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+ | --libexe=* | --libex=* | --libe=*)
+ libexecdir="$ac_optarg" ;;
+
+ -localstatedir | --localstatedir | --localstatedi | --localstated \
+ | --localstate | --localstat | --localsta | --localst \
+ | --locals | --local | --loca | --loc | --lo)
+ ac_prev=localstatedir ;;
+ -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+ | --localstate=* | --localstat=* | --localsta=* | --localst=* \
+ | --locals=* | --local=* | --loca=* | --loc=* | --lo=*)
+ localstatedir="$ac_optarg" ;;
+
+ -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+ ac_prev=mandir ;;
+ -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+ mandir="$ac_optarg" ;;
+
+ -nfp | --nfp | --nf)
+ # Obsolete; use --without-fp.
+ with_fp=no ;;
+
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c)
+ no_create=yes ;;
+
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+ no_recursion=yes ;;
+
+ -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+ | --oldin | --oldi | --old | --ol | --o)
+ ac_prev=oldincludedir ;;
+ -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+ oldincludedir="$ac_optarg" ;;
+
+ -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+ ac_prev=prefix ;;
+ -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+ prefix="$ac_optarg" ;;
+
+ -program-prefix | --program-prefix | --program-prefi | --program-pref \
+ | --program-pre | --program-pr | --program-p)
+ ac_prev=program_prefix ;;
+ -program-prefix=* | --program-prefix=* | --program-prefi=* \
+ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+ program_prefix="$ac_optarg" ;;
+
+ -program-suffix | --program-suffix | --program-suffi | --program-suff \
+ | --program-suf | --program-su | --program-s)
+ ac_prev=program_suffix ;;
+ -program-suffix=* | --program-suffix=* | --program-suffi=* \
+ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+ program_suffix="$ac_optarg" ;;
+
+ -program-transform-name | --program-transform-name \
+ | --program-transform-nam | --program-transform-na \
+ | --program-transform-n | --program-transform- \
+ | --program-transform | --program-transfor \
+ | --program-transfo | --program-transf \
+ | --program-trans | --program-tran \
+ | --progr-tra | --program-tr | --program-t)
+ ac_prev=program_transform_name ;;
+ -program-transform-name=* | --program-transform-name=* \
+ | --program-transform-nam=* | --program-transform-na=* \
+ | --program-transform-n=* | --program-transform-=* \
+ | --program-transform=* | --program-transfor=* \
+ | --program-transfo=* | --program-transf=* \
+ | --program-trans=* | --program-tran=* \
+ | --progr-tra=* | --program-tr=* | --program-t=*)
+ program_transform_name="$ac_optarg" ;;
+
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ silent=yes ;;
+
+ -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+ ac_prev=sbindir ;;
+ -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+ | --sbi=* | --sb=*)
+ sbindir="$ac_optarg" ;;
+
+ -sharedstatedir | --sharedstatedir | --sharedstatedi \
+ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+ | --sharedst | --shareds | --shared | --share | --shar \
+ | --sha | --sh)
+ ac_prev=sharedstatedir ;;
+ -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+ | --sha=* | --sh=*)
+ sharedstatedir="$ac_optarg" ;;
+
+ -site | --site | --sit)
+ ac_prev=site ;;
+ -site=* | --site=* | --sit=*)
+ site="$ac_optarg" ;;
+
+ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+ ac_prev=srcdir ;;
+ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+ srcdir="$ac_optarg" ;;
+
+ -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+ | --syscon | --sysco | --sysc | --sys | --sy)
+ ac_prev=sysconfdir ;;
+ -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+ sysconfdir="$ac_optarg" ;;
+
+ -target | --target | --targe | --targ | --tar | --ta | --t)
+ ac_prev=target ;;
+ -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+ target="$ac_optarg" ;;
+
+ -v | -verbose | --verbose | --verbos | --verbo | --verb)
+ verbose=yes ;;
+
+ -version | --version | --versio | --versi | --vers)
+ echo "configure generated by autoconf version 2.13"
+ exit 0 ;;
+
+ -with-* | --with-*)
+ ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then
+ { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+ fi
+ ac_package=`echo $ac_package| sed 's/-/_/g'`
+ case "$ac_option" in
+ *=*) ;;
+ *) ac_optarg=yes ;;
+ esac
+ eval "with_${ac_package}='$ac_optarg'" ;;
+
+ -without-* | --without-*)
+ ac_package=`echo $ac_option|sed -e 's/-*without-//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then
+ { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+ fi
+ ac_package=`echo $ac_package| sed 's/-/_/g'`
+ eval "with_${ac_package}=no" ;;
+
+ --x)
+ # Obsolete; use --with-x.
+ with_x=yes ;;
+
+ -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+ | --x-incl | --x-inc | --x-in | --x-i)
+ ac_prev=x_includes ;;
+ -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+ x_includes="$ac_optarg" ;;
+
+ -x-libraries | --x-libraries | --x-librarie | --x-librari \
+ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+ ac_prev=x_libraries ;;
+ -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+ x_libraries="$ac_optarg" ;;
+
+ -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; }
+ ;;
+
+ *)
+ if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then
+ echo "configure: warning: $ac_option: invalid host type" 1>&2
+ fi
+ if test "x$nonopt" != xNONE; then
+ { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; }
+ fi
+ nonopt="$ac_option"
+ ;;
+
+ esac
+done
+
+if test -n "$ac_prev"; then
+ { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; }
+fi
+
+trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
+
+# File descriptor usage:
+# 0 standard input
+# 1 file creation
+# 2 errors and warnings
+# 3 some systems may open it to /dev/tty
+# 4 used on the Kubota Titan
+# 6 checking for... messages and results
+# 5 compiler messages saved in config.log
+if test "$silent" = yes; then
+ exec 6>/dev/null
+else
+ exec 6>&1
+fi
+exec 5>./config.log
+
+echo "\
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+" 1>&5
+
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Also quote any args containing shell metacharacters.
+ac_configure_args=
+for ac_arg
+do
+ case "$ac_arg" in
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c) ;;
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;;
+ *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*)
+ ac_configure_args="$ac_configure_args '$ac_arg'" ;;
+ *) ac_configure_args="$ac_configure_args $ac_arg" ;;
+ esac
+done
+
+# NLS nuisances.
+# Only set these to C if already set. These must not be set unconditionally
+# because not all systems understand e.g. LANG=C (notably SCO).
+# Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'!
+# Non-C LC_CTYPE values break the ctype check.
+if test "${LANG+set}" = set; then LANG=C; export LANG; fi
+if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi
+if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi
+if test "${LC_CTYPE+set}" = set; then LC_CTYPE=C; export LC_CTYPE; fi
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -rf conftest* confdefs.h
+# AIX cpp loses on an empty file, so make sure it contains at least a newline.
+echo > confdefs.h
+
+# A filename unique to this package, relative to the directory that
+# configure is in, which we can look for to find out if srcdir is correct.
+ac_unique_file=pppoe.c
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+ ac_srcdir_defaulted=yes
+ # Try the directory containing this script, then its parent.
+ ac_prog=$0
+ ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'`
+ test "x$ac_confdir" = "x$ac_prog" && ac_confdir=.
+ srcdir=$ac_confdir
+ if test ! -r $srcdir/$ac_unique_file; then
+ srcdir=..
+ fi
+else
+ ac_srcdir_defaulted=no
+fi
+if test ! -r $srcdir/$ac_unique_file; then
+ if test "$ac_srcdir_defaulted" = yes; then
+ { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; }
+ else
+ { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; }
+ fi
+fi
+srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'`
+
+# Prefer explicitly selected file to automatically selected ones.
+if test -z "$CONFIG_SITE"; then
+ if test "x$prefix" != xNONE; then
+ CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site"
+ else
+ CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site"
+ fi
+fi
+for ac_site_file in $CONFIG_SITE; do
+ if test -r "$ac_site_file"; then
+ echo "loading site script $ac_site_file"
+ . "$ac_site_file"
+ fi
+done
+
+if test -r "$cache_file"; then
+ echo "loading cache $cache_file"
+ . $cache_file
+else
+ echo "creating cache $cache_file"
+ > $cache_file
+fi
+
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+ac_exeext=
+ac_objext=o
+if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then
+ # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu.
+ if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then
+ ac_n= ac_c='
+' ac_t=' '
+ else
+ ac_n=-n ac_c= ac_t=
+ fi
+else
+ ac_n= ac_c='\c' ac_t=
+fi
+
+
+
+
+
+
+
+# Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:536: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_dummy="$PATH"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_prog_CC="gcc"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+ echo "$ac_t""$CC" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+if test -z "$CC"; then
+ # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:566: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_prog_rejected=no
+ ac_dummy="$PATH"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then
+ ac_prog_rejected=yes
+ continue
+ fi
+ ac_cv_prog_CC="cc"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+if test $ac_prog_rejected = yes; then
+ # We found a bogon in the path, so make sure we never use it.
+ set dummy $ac_cv_prog_CC
+ shift
+ if test $# -gt 0; then
+ # We chose a different compiler from the bogus one.
+ # However, it has the same basename, so the bogon will be chosen
+ # first if we set CC to just the basename; use the full file name.
+ shift
+ set dummy "$ac_dir/$ac_word" "$@"
+ shift
+ ac_cv_prog_CC="$@"
+ fi
+fi
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+ echo "$ac_t""$CC" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+ if test -z "$CC"; then
+ case "`uname -s`" in
+ *win32* | *WIN32*)
+ # Extract the first word of "cl", so it can be a program name with args.
+set dummy cl; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:617: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_dummy="$PATH"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_prog_CC="cl"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+ echo "$ac_t""$CC" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+ ;;
+ esac
+ fi
+ test -z "$CC" && { echo "configure: error: no acceptable cc found in \$PATH" 1>&2; exit 1; }
+fi
+
+echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6
+echo "configure:649: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5
+
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+cat > conftest.$ac_ext << EOF
+
+#line 660 "configure"
+#include "confdefs.h"
+
+main(){return(0);}
+EOF
+if { (eval echo configure:665: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ ac_cv_prog_cc_works=yes
+ # If we can't run a trivial program, we are probably using a cross compiler.
+ if (./conftest; exit) 2>/dev/null; then
+ ac_cv_prog_cc_cross=no
+ else
+ ac_cv_prog_cc_cross=yes
+ fi
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ ac_cv_prog_cc_works=no
+fi
+rm -fr conftest*
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+echo "$ac_t""$ac_cv_prog_cc_works" 1>&6
+if test $ac_cv_prog_cc_works = no; then
+ { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; }
+fi
+echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6
+echo "configure:691: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5
+echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6
+cross_compiling=$ac_cv_prog_cc_cross
+
+echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6
+echo "configure:696: checking whether we are using GNU C" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.c <<EOF
+#ifdef __GNUC__
+ yes;
+#endif
+EOF
+if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:705: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
+ ac_cv_prog_gcc=yes
+else
+ ac_cv_prog_gcc=no
+fi
+fi
+
+echo "$ac_t""$ac_cv_prog_gcc" 1>&6
+
+if test $ac_cv_prog_gcc = yes; then
+ GCC=yes
+else
+ GCC=
+fi
+
+ac_test_CFLAGS="${CFLAGS+set}"
+ac_save_CFLAGS="$CFLAGS"
+CFLAGS=
+echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6
+echo "configure:724: checking whether ${CC-cc} accepts -g" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ echo 'void f(){}' > conftest.c
+if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then
+ ac_cv_prog_cc_g=yes
+else
+ ac_cv_prog_cc_g=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_prog_cc_g" 1>&6
+if test "$ac_test_CFLAGS" = set; then
+ CFLAGS="$ac_save_CFLAGS"
+elif test $ac_cv_prog_cc_g = yes; then
+ if test "$GCC" = yes; then
+ CFLAGS="-g -O2"
+ else
+ CFLAGS="-g"
+ fi
+else
+ if test "$GCC" = yes; then
+ CFLAGS="-O2"
+ else
+ CFLAGS=
+ fi
+fi
+
+
+
+echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6
+echo "configure:758: checking how to run the C preprocessor" >&5
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+ CPP=
+fi
+if test -z "$CPP"; then
+if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ # This must be in double quotes, not single quotes, because CPP may get
+ # substituted into the Makefile and "${CC-cc}" will confuse make.
+ CPP="${CC-cc} -E"
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp.
+ cat > conftest.$ac_ext <<EOF
+#line 773 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:779: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ :
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ CPP="${CC-cc} -E -traditional-cpp"
+ cat > conftest.$ac_ext <<EOF
+#line 790 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:796: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ :
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ CPP="${CC-cc} -nologo -E"
+ cat > conftest.$ac_ext <<EOF
+#line 807 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:813: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ :
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ CPP=/lib/cpp
+fi
+rm -f conftest*
+fi
+rm -f conftest*
+fi
+rm -f conftest*
+ ac_cv_prog_CPP="$CPP"
+fi
+ CPP="$ac_cv_prog_CPP"
+else
+ ac_cv_prog_CPP="$CPP"
+fi
+echo "$ac_t""$CPP" 1>&6
+
+echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6
+echo "configure:838: checking for ANSI C header files" >&5
+if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 843 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:851: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ ac_cv_header_stdc=yes
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+if test $ac_cv_header_stdc = yes; then
+ # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+cat > conftest.$ac_ext <<EOF
+#line 868 "configure"
+#include "confdefs.h"
+#include <string.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "memchr" >/dev/null 2>&1; then
+ :
+else
+ rm -rf conftest*
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+cat > conftest.$ac_ext <<EOF
+#line 886 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "free" >/dev/null 2>&1; then
+ :
+else
+ rm -rf conftest*
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+if test "$cross_compiling" = yes; then
+ :
+else
+ cat > conftest.$ac_ext <<EOF
+#line 907 "configure"
+#include "confdefs.h"
+#include <ctype.h>
+#define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+#define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int main () { int i; for (i = 0; i < 256; i++)
+if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2);
+exit (0); }
+
+EOF
+if { (eval echo configure:918: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ :
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ ac_cv_header_stdc=no
+fi
+rm -fr conftest*
+fi
+
+fi
+fi
+
+echo "$ac_t""$ac_cv_header_stdc" 1>&6
+if test $ac_cv_header_stdc = yes; then
+ cat >> confdefs.h <<\EOF
+#define STDC_HEADERS 1
+EOF
+
+fi
+
+echo $ac_n "checking for sys/wait.h that is POSIX.1 compatible""... $ac_c" 1>&6
+echo "configure:942: checking for sys/wait.h that is POSIX.1 compatible" >&5
+if eval "test \"`echo '$''{'ac_cv_header_sys_wait_h'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 947 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <sys/wait.h>
+#ifndef WEXITSTATUS
+#define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
+#endif
+#ifndef WIFEXITED
+#define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
+#endif
+int main() {
+int s;
+wait (&s);
+s = WIFEXITED (s) ? WEXITSTATUS (s) : 1;
+; return 0; }
+EOF
+if { (eval echo configure:963: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ac_cv_header_sys_wait_h=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ac_cv_header_sys_wait_h=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_header_sys_wait_h" 1>&6
+if test $ac_cv_header_sys_wait_h = yes; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_SYS_WAIT_H 1
+EOF
+
+fi
+
+for ac_hdr in fcntl.h sys/ioctl.h sys/time.h syslog.h unistd.h net/if_arp.h netinet/if_ether.h getopt.h sys/uio.h sys/param.h fcntl.h net/bpf.h netpacket/packet.h net/ethernet.h asm/types.h linux/if_packet.h linux/if_ether.h linux/if_pppox.h sys/socket.h sys/cdefs.h linux/if.h net/if.h net/if_dl.h net/if_ether.h net/if_types.h netinet/if_ether.h net/if_types.h net/if_dl.h sys/dlpi.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:987: checking for $ac_hdr" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 992 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:997: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=yes"
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+
+echo $ac_n "checking for working const""... $ac_c" 1>&6
+echo "configure:1025: checking for working const" >&5
+if eval "test \"`echo '$''{'ac_cv_c_const'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1030 "configure"
+#include "confdefs.h"
+
+int main() {
+
+/* Ultrix mips cc rejects this. */
+typedef int charset[2]; const charset x;
+/* SunOS 4.1.1 cc rejects this. */
+char const *const *ccp;
+char **p;
+/* NEC SVR4.0.2 mips cc rejects this. */
+struct point {int x, y;};
+static struct point const zero = {0,0};
+/* AIX XL C 1.02.0.0 rejects this.
+ It does not let you subtract one const X* pointer from another in an arm
+ of an if-expression whose if-part is not a constant expression */
+const char *g = "string";
+ccp = &g + (g ? g-g : 0);
+/* HPUX 7.0 cc rejects these. */
+++ccp;
+p = (char**) ccp;
+ccp = (char const *const *) p;
+{ /* SCO 3.2v4 cc rejects this. */
+ char *t;
+ char const *s = 0 ? (char *) 0 : (char const *) 0;
+
+ *t++ = 0;
+}
+{ /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */
+ int x[] = {25, 17};
+ const int *foo = &x[0];
+ ++foo;
+}
+{ /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */
+ typedef const int *iptr;
+ iptr p = 0;
+ ++p;
+}
+{ /* AIX XL C 1.02.0.0 rejects this saying
+ "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */
+ struct s { int j; const int *ap[3]; };
+ struct s *b; b->j = 5;
+}
+{ /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */
+ const int foo = 10;
+}
+
+; return 0; }
+EOF
+if { (eval echo configure:1079: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ac_cv_c_const=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ac_cv_c_const=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_c_const" 1>&6
+if test $ac_cv_c_const = no; then
+ cat >> confdefs.h <<\EOF
+#define const
+EOF
+
+fi
+
+echo $ac_n "checking for pid_t""... $ac_c" 1>&6
+echo "configure:1100: checking for pid_t" >&5
+if eval "test \"`echo '$''{'ac_cv_type_pid_t'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1105 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "(^|[^a-zA-Z_0-9])pid_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then
+ rm -rf conftest*
+ ac_cv_type_pid_t=yes
+else
+ rm -rf conftest*
+ ac_cv_type_pid_t=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_type_pid_t" 1>&6
+if test $ac_cv_type_pid_t = no; then
+ cat >> confdefs.h <<\EOF
+#define pid_t int
+EOF
+
+fi
+
+echo $ac_n "checking whether time.h and sys/time.h may both be included""... $ac_c" 1>&6
+echo "configure:1133: checking whether time.h and sys/time.h may both be included" >&5
+if eval "test \"`echo '$''{'ac_cv_header_time'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1138 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <sys/time.h>
+#include <time.h>
+int main() {
+struct tm *tp;
+; return 0; }
+EOF
+if { (eval echo configure:1147: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ac_cv_header_time=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ac_cv_header_time=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_header_time" 1>&6
+if test $ac_cv_header_time = yes; then
+ cat >> confdefs.h <<\EOF
+#define TIME_WITH_SYS_TIME 1
+EOF
+
+fi
+
+echo $ac_n "checking whether struct tm is in sys/time.h or time.h""... $ac_c" 1>&6
+echo "configure:1168: checking whether struct tm is in sys/time.h or time.h" >&5
+if eval "test \"`echo '$''{'ac_cv_struct_tm'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1173 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <time.h>
+int main() {
+struct tm *tp; tp->tm_sec;
+; return 0; }
+EOF
+if { (eval echo configure:1181: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ac_cv_struct_tm=time.h
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ac_cv_struct_tm=sys/time.h
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_struct_tm" 1>&6
+if test $ac_cv_struct_tm = sys/time.h; then
+ cat >> confdefs.h <<\EOF
+#define TM_IN_SYS_TIME 1
+EOF
+
+fi
+
+
+# Extract the first word of "echo", so it can be a program name with args.
+set dummy echo; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:1205: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_path_ECHO'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ case "$ECHO" in
+ /*)
+ ac_cv_path_ECHO="$ECHO" # Let the user override the test with a path.
+ ;;
+ ?:/*)
+ ac_cv_path_ECHO="$ECHO" # Let the user override the test with a dos path.
+ ;;
+ *)
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_dummy="/usr/ucb/bin:$PATH"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_path_ECHO="$ac_dir/$ac_word"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+ test -z "$ac_cv_path_ECHO" && ac_cv_path_ECHO=""""
+ ;;
+esac
+fi
+ECHO="$ac_cv_path_ECHO"
+if test -n "$ECHO"; then
+ echo "$ac_t""$ECHO" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+
+$ECHO -n "checking for struct sockaddr_ll... "
+cat > conftest.$ac_ext <<EOF
+#line 1241 "configure"
+#include "confdefs.h"
+#include <asm/types.h>
+#include <linux/if_packet.h>
+#include <linux/if_ether.h>
+
+int main() {
+struct sockaddr_ll sa;
+; return 0; }
+EOF
+if { (eval echo configure:1251: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ac_cv_struct_sockaddr_ll=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ac_cv_struct_sockaddr_ll=no
+fi
+rm -f conftest*
+$ECHO $ac_cv_struct_sockaddr_ll
+if test "$ac_cv_struct_sockaddr_ll" = yes ; then
+cat >> confdefs.h <<\EOF
+#define HAVE_STRUCT_SOCKADDR_LL 1
+EOF
+
+fi
+
+$ECHO -n "checking for N_HDLC line discipline... "
+cat > conftest.$ac_ext <<EOF
+#line 1271 "configure"
+#include "confdefs.h"
+#include <linux/termios.h>
+int main() {
+int x = N_HDLC;
+; return 0; }
+EOF
+if { (eval echo configure:1278: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ac_cv_n_hdlc=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ac_cv_n_hdlc=no
+fi
+rm -f conftest*
+$ECHO $ac_cv_n_hdlc
+if test "$ac_cv_n_hdlc" = yes ; then
+cat >> confdefs.h <<\EOF
+#define HAVE_N_HDLC 1
+EOF
+
+fi
+
+# Check whether --enable-plugin or --disable-plugin was given.
+if test "${enable_plugin+set}" = set; then
+ enableval="$enable_plugin"
+ ac_cv_pluginpath=$enableval
+else
+ ac_cv_pluginpath=no
+fi
+
+
+LINUX_KERNELMODE_PLUGIN=""
+PPPD_INCDIR=""
+if test "$ac_cv_header_linux_if_pppox_h" = yes ; then
+ if test "$ac_cv_pluginpath" != no ; then
+ LINUX_KERNELMODE_PLUGIN=rp-pppoe.so
+ PPPD_INCDIR=$ac_cv_pluginpath
+ fi
+fi
+
+
+
+
+PPPOE_RELAY=""
+if test "`uname -s`" = "Linux" ; then
+ PPPOE_RELAY=pppoe-relay
+fi
+
+
+echo $ac_n "checking for 8-bit clean memcmp""... $ac_c" 1>&6
+echo "configure:1324: checking for 8-bit clean memcmp" >&5
+if eval "test \"`echo '$''{'ac_cv_func_memcmp_clean'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test "$cross_compiling" = yes; then
+ ac_cv_func_memcmp_clean=no
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1332 "configure"
+#include "confdefs.h"
+
+main()
+{
+ char c0 = 0x40, c1 = 0x80, c2 = 0x81;
+ exit(memcmp(&c0, &c2, 1) < 0 && memcmp(&c1, &c2, 1) < 0 ? 0 : 1);
+}
+
+EOF
+if { (eval echo configure:1342: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ ac_cv_func_memcmp_clean=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ ac_cv_func_memcmp_clean=no
+fi
+rm -fr conftest*
+fi
+
+fi
+
+echo "$ac_t""$ac_cv_func_memcmp_clean" 1>&6
+test $ac_cv_func_memcmp_clean = no && LIBOBJS="$LIBOBJS memcmp.${ac_objext}"
+
+echo $ac_n "checking whether setvbuf arguments are reversed""... $ac_c" 1>&6
+echo "configure:1360: checking whether setvbuf arguments are reversed" >&5
+if eval "test \"`echo '$''{'ac_cv_func_setvbuf_reversed'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test "$cross_compiling" = yes; then
+ { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; }
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1368 "configure"
+#include "confdefs.h"
+#include <stdio.h>
+/* If setvbuf has the reversed format, exit 0. */
+main () {
+ /* This call has the arguments reversed.
+ A reversed system may check and see that the address of main
+ is not _IOLBF, _IONBF, or _IOFBF, and return nonzero. */
+ if (setvbuf(stdout, _IOLBF, (char *) main, BUFSIZ) != 0)
+ exit(1);
+ putc('\r', stdout);
+ exit(0); /* Non-reversed systems segv here. */
+}
+EOF
+if { (eval echo configure:1382: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ ac_cv_func_setvbuf_reversed=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ ac_cv_func_setvbuf_reversed=no
+fi
+rm -fr conftest*
+fi
+
+rm -f core core.* *.core
+fi
+
+echo "$ac_t""$ac_cv_func_setvbuf_reversed" 1>&6
+if test $ac_cv_func_setvbuf_reversed = yes; then
+ cat >> confdefs.h <<\EOF
+#define SETVBUF_REVERSED 1
+EOF
+
+fi
+
+echo $ac_n "checking return type of signal handlers""... $ac_c" 1>&6
+echo "configure:1406: checking return type of signal handlers" >&5
+if eval "test \"`echo '$''{'ac_cv_type_signal'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1411 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <signal.h>
+#ifdef signal
+#undef signal
+#endif
+#ifdef __cplusplus
+extern "C" void (*signal (int, void (*)(int)))(int);
+#else
+void (*signal ()) ();
+#endif
+
+int main() {
+int i;
+; return 0; }
+EOF
+if { (eval echo configure:1428: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ac_cv_type_signal=void
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ac_cv_type_signal=int
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_type_signal" 1>&6
+cat >> confdefs.h <<EOF
+#define RETSIGTYPE $ac_cv_type_signal
+EOF
+
+
+for ac_func in select socket strerror strtol
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:1449: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1454 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:1477: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+ac_aux_dir=
+for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do
+ if test -f $ac_dir/install-sh; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install-sh -c"
+ break
+ elif test -f $ac_dir/install.sh; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install.sh -c"
+ break
+ fi
+done
+if test -z "$ac_aux_dir"; then
+ { echo "configure: error: can not find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." 1>&2; exit 1; }
+fi
+ac_config_guess=$ac_aux_dir/config.guess
+ac_config_sub=$ac_aux_dir/config.sub
+ac_configure=$ac_aux_dir/configure # This should be Cygnus configure.
+
+# Find a good install program. We prefer a C program (faster),
+# so one script is as good as another. But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# ./install, which can be erroneously created by make from ./install.sh.
+echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6
+echo "configure:1532: checking for a BSD compatible install" >&5
+if test -z "$INSTALL"; then
+if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ IFS="${IFS= }"; ac_save_IFS="$IFS"; IFS=":"
+ for ac_dir in $PATH; do
+ # Account for people who put trailing slashes in PATH elements.
+ case "$ac_dir/" in
+ /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;;
+ *)
+ # OSF1 and SCO ODT 3.0 have their own names for install.
+ # Don't use installbsd from OSF since it installs stuff as root
+ # by default.
+ for ac_prog in ginstall scoinst install; do
+ if test -f $ac_dir/$ac_prog; then
+ if test $ac_prog = install &&
+ grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then
+ # AIX install. It has an incompatible calling convention.
+ :
+ else
+ ac_cv_path_install="$ac_dir/$ac_prog -c"
+ break 2
+ fi
+ fi
+ done
+ ;;
+ esac
+ done
+ IFS="$ac_save_IFS"
+
+fi
+ if test "${ac_cv_path_install+set}" = set; then
+ INSTALL="$ac_cv_path_install"
+ else
+ # As a last resort, use the slow shell script. We don't cache a
+ # path for INSTALL within a source directory, because that will
+ # break other packages using the cache if that directory is
+ # removed, or if the path is relative.
+ INSTALL="$ac_install_sh"
+ fi
+fi
+echo "$ac_t""$INSTALL" 1>&6
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL_PROGRAM}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+
+echo $ac_n "checking size of unsigned short""... $ac_c" 1>&6
+echo "configure:1586: checking size of unsigned short" >&5
+if eval "test \"`echo '$''{'ac_cv_sizeof_unsigned_short'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test "$cross_compiling" = yes; then
+ { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; }
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1594 "configure"
+#include "confdefs.h"
+#include <stdio.h>
+main()
+{
+ FILE *f=fopen("conftestval", "w");
+ if (!f) exit(1);
+ fprintf(f, "%d\n", sizeof(unsigned short));
+ exit(0);
+}
+EOF
+if { (eval echo configure:1605: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ ac_cv_sizeof_unsigned_short=`cat conftestval`
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ ac_cv_sizeof_unsigned_short=0
+fi
+rm -fr conftest*
+fi
+
+fi
+echo "$ac_t""$ac_cv_sizeof_unsigned_short" 1>&6
+cat >> confdefs.h <<EOF
+#define SIZEOF_UNSIGNED_SHORT $ac_cv_sizeof_unsigned_short
+EOF
+
+
+echo $ac_n "checking size of unsigned int""... $ac_c" 1>&6
+echo "configure:1625: checking size of unsigned int" >&5
+if eval "test \"`echo '$''{'ac_cv_sizeof_unsigned_int'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test "$cross_compiling" = yes; then
+ { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; }
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1633 "configure"
+#include "confdefs.h"
+#include <stdio.h>
+main()
+{
+ FILE *f=fopen("conftestval", "w");
+ if (!f) exit(1);
+ fprintf(f, "%d\n", sizeof(unsigned int));
+ exit(0);
+}
+EOF
+if { (eval echo configure:1644: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ ac_cv_sizeof_unsigned_int=`cat conftestval`
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ ac_cv_sizeof_unsigned_int=0
+fi
+rm -fr conftest*
+fi
+
+fi
+echo "$ac_t""$ac_cv_sizeof_unsigned_int" 1>&6
+cat >> confdefs.h <<EOF
+#define SIZEOF_UNSIGNED_INT $ac_cv_sizeof_unsigned_int
+EOF
+
+
+echo $ac_n "checking size of unsigned long""... $ac_c" 1>&6
+echo "configure:1664: checking size of unsigned long" >&5
+if eval "test \"`echo '$''{'ac_cv_sizeof_unsigned_long'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test "$cross_compiling" = yes; then
+ { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; }
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1672 "configure"
+#include "confdefs.h"
+#include <stdio.h>
+main()
+{
+ FILE *f=fopen("conftestval", "w");
+ if (!f) exit(1);
+ fprintf(f, "%d\n", sizeof(unsigned long));
+ exit(0);
+}
+EOF
+if { (eval echo configure:1683: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ ac_cv_sizeof_unsigned_long=`cat conftestval`
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ ac_cv_sizeof_unsigned_long=0
+fi
+rm -fr conftest*
+fi
+
+fi
+echo "$ac_t""$ac_cv_sizeof_unsigned_long" 1>&6
+cat >> confdefs.h <<EOF
+#define SIZEOF_UNSIGNED_LONG $ac_cv_sizeof_unsigned_long
+EOF
+
+
+
+# Extract the first word of "pppd", so it can be a program name with args.
+set dummy pppd; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:1706: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_path_PPPD'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ case "$PPPD" in
+ /*)
+ ac_cv_path_PPPD="$PPPD" # Let the user override the test with a path.
+ ;;
+ ?:/*)
+ ac_cv_path_PPPD="$PPPD" # Let the user override the test with a dos path.
+ ;;
+ *)
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_dummy="$PATH:/sbin:/usr/sbin:/usr/local/sbin"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_path_PPPD="$ac_dir/$ac_word"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+ test -z "$ac_cv_path_PPPD" && ac_cv_path_PPPD="NOTFOUND"
+ ;;
+esac
+fi
+PPPD="$ac_cv_path_PPPD"
+if test -n "$PPPD"; then
+ echo "$ac_t""$PPPD" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+
+# Extract the first word of "setsid", so it can be a program name with args.
+set dummy setsid; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:1743: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_path_SETSID'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ case "$SETSID" in
+ /*)
+ ac_cv_path_SETSID="$SETSID" # Let the user override the test with a path.
+ ;;
+ ?:/*)
+ ac_cv_path_SETSID="$SETSID" # Let the user override the test with a dos path.
+ ;;
+ *)
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_dummy="$PATH:/sbin:/usr/sbin:/usr/local/sbin"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_path_SETSID="$ac_dir/$ac_word"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+ test -z "$ac_cv_path_SETSID" && ac_cv_path_SETSID=""""
+ ;;
+esac
+fi
+SETSID="$ac_cv_path_SETSID"
+if test -n "$SETSID"; then
+ echo "$ac_t""$SETSID" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+
+# Extract the first word of "id", so it can be a program name with args.
+set dummy id; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:1780: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_path_ID'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ case "$ID" in
+ /*)
+ ac_cv_path_ID="$ID" # Let the user override the test with a path.
+ ;;
+ ?:/*)
+ ac_cv_path_ID="$ID" # Let the user override the test with a dos path.
+ ;;
+ *)
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_dummy="/usr/xpg4/bin:$PATH"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_path_ID="$ac_dir/$ac_word"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+ test -z "$ac_cv_path_ID" && ac_cv_path_ID=""""
+ ;;
+esac
+fi
+ID="$ac_cv_path_ID"
+if test -n "$ID"; then
+ echo "$ac_t""$ID" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+
+$ECHO -n "checking for Linux 2.4.X kernel-mode PPPoE support..."
+if test "`uname -s`" = "Linux" ; then
+if test "$cross_compiling" = yes; then
+ { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; }
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1820 "configure"
+#include "confdefs.h"
+#include <sys/socket.h>
+#include <net/ethernet.h>
+#include <linux/if.h>
+#include <linux/if_pppox.h>
+int main()
+{
+ if (socket(AF_PPPOX, SOCK_DGRAM, PX_PROTO_OE) >= 0) return 0; else return 1;
+}
+
+EOF
+if { (eval echo configure:1832: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ ac_cv_linux_kernel_pppoe=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ ac_cv_linux_kernel_pppoe=no
+fi
+rm -fr conftest*
+fi
+
+else
+ ac_cv_linux_kernel_pppoe=no
+fi
+
+$ECHO $ac_cv_linux_kernel_pppoe
+if test "$ac_cv_linux_kernel_pppoe" = yes ; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_LINUX_KERNEL_PPPOE 1
+EOF
+
+fi
+
+if test "$GCC" = yes; then
+ CFLAGS="$CFLAGS -Wall -Wstrict-prototypes -ansi -pedantic"
+fi
+
+if test "$PPPD" = "NOTFOUND"; then
+ $ECHO ""
+ $ECHO "*** Oops! I couldn't find pppd, the PPP daemon anywhere."
+ $ECHO "*** You must install pppd, version 2.3.10 or later."
+ $ECHO "*** I will keep going, but it may not work."
+ $ECHO ""
+fi
+
+
+PPPD_VERSION=`$PPPD --version 2>&1 | awk '{print $NF}'`
+
+case "$PPPD_VERSION" in
+1.*|2.0.*|2.1.*|2.2.*|2.3.0|2.3.1|2.3.2|2.3.3|2.3.4|2.3.5|2.3.6)
+ $ECHO ""
+ $ECHO "*** Oops! Your version of pppd is $PPPD_VERSION, which is too old."
+ $ECHO "*** You need at least 2.3.7 (2.3.10 or newer recommended.)"
+ $ECHO "*** I will keep going, but it may not work."
+ $ECHO ""
+ ;;
+
+2.3.7|2.3.8|2.3.9)
+ $ECHO ""
+ $ECHO "*** Warning. Your version of pppd is $PPPD_VERSION. You will"
+ $ECHO "*** not be able to use connect-on-demand. Upgrade to pppd"
+ $ECHO "*** 2.3.10 or newer if you need connect-on-demand."
+ $ECHO ""
+ ;;
+
+2*|3*|4*|5*|6*|7*|8*|9*)
+ ;;
+
+*)
+ $ECHO ""
+ $ECHO "*** Oops. I cannot figure out what version of pppd you have."
+ $ECHO "*** All I got back was '$PPPD_VERSION'"
+ $ECHO "*** I will keep going, but it may not work."
+ $ECHO ""
+ ;;
+esac
+
+$ECHO -n "checking packing order of bit fields... "
+if test "$cross_compiling" = yes; then
+ { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; }
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1905 "configure"
+#include "confdefs.h"
+
+union foo {
+ struct bar {
+ unsigned int ver:4;
+ unsigned int type:4;
+ } bb;
+ unsigned char baz;
+};
+
+int
+main(void)
+{
+ union foo x;
+ x.bb.ver = 1;
+ x.bb.type = 2;
+ if (x.baz == 0x21) {
+ return 1;
+ } else if (x.baz == 0x12) {
+ return 0;
+ } else {
+ return 2;
+ }
+}
+EOF
+if { (eval echo configure:1931: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ PACK=normal
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ PACK=rev
+fi
+rm -fr conftest*
+fi
+
+
+if test "$PACK" = "rev" ; then
+ $ECHO "reversed"
+ cat >> confdefs.h <<\EOF
+#define PACK_BITFIELDS_REVERSED 1
+EOF
+
+else
+ $ECHO "normal"
+fi
+
+# Sigh... got to fix this up for tcl
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+# Fully resolve WRAPPER for Tcl script.
+WRAPPER=${sbindir}/pppoe-wrapper
+eval "WRAPPER=${WRAPPER}"
+eval "WRAPPER=${WRAPPER}"
+
+
+# Determine what targets to build
+TARGETS="pppoe pppoe-server"
+
+# pppoe-sniff is built only on Linux and Solaris
+if test "$ac_cv_header_linux_if_packet_h" = "yes" -o "$ac_cv_header_sys_dlpi_h" = "yes" ; then
+ TARGETS="$TARGETS pppoe-sniff"
+fi
+
+# pppoe-relay is built only on Linux
+if test "$ac_cv_header_linux_if_packet_h" = "yes" ; then
+ TARGETS="$TARGETS pppoe-relay"
+fi
+
+# plugin is built only if we have kernel support
+if test -n "$LINUX_KERNELMODE_PLUGIN" ; then
+ TARGETS="$TARGETS $LINUX_KERNELMODE_PLUGIN"
+fi
+
+
+
+trap '' 1 2 15
+cat > confcache <<\EOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs. It is not useful on other systems.
+# If it contains results you don't want to keep, you may remove or edit it.
+#
+# By default, configure uses ./config.cache as the cache file,
+# creating it if it does not exist already. You can give configure
+# the --cache-file=FILE option to use a different cache file; that is
+# what configure does when it calls configure scripts in
+# subdirectories, so they share the cache.
+# Giving --cache-file=/dev/null disables caching, for debugging configure.
+# config.status only pays attention to the cache file if you give it the
+# --recheck option to rerun configure.
+#
+EOF
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, don't put newlines in cache variables' values.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(set) 2>&1 |
+ case `(ac_space=' '; set | grep ac_space) 2>&1` in
+ *ac_space=\ *)
+ # `set' does not quote correctly, so add quotes (double-quote substitution
+ # turns \\\\ into \\, and sed turns \\ into \).
+ sed -n \
+ -e "s/'/'\\\\''/g" \
+ -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p"
+ ;;
+ *)
+ # `set' quotes correctly as required by POSIX, so do not add quotes.
+ sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p'
+ ;;
+ esac >> confcache
+if cmp -s $cache_file confcache; then
+ :
+else
+ if test -w $cache_file; then
+ echo "updating cache $cache_file"
+ cat confcache > $cache_file
+ else
+ echo "not updating unwritable cache $cache_file"
+ fi
+fi
+rm -f confcache
+
+trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+# Any assignment to VPATH causes Sun make to only execute
+# the first set of double-colon rules, so remove it if not needed.
+# If there is a colon in the path, we need to keep it.
+if test "x$srcdir" = x.; then
+ ac_vpsub='/^[ ]*VPATH[ ]*=[^:]*$/d'
+fi
+
+trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15
+
+DEFS=-DHAVE_CONFIG_H
+
+# Without the "./", some shells look in PATH for config.status.
+: ${CONFIG_STATUS=./config.status}
+
+echo creating $CONFIG_STATUS
+rm -f $CONFIG_STATUS
+cat > $CONFIG_STATUS <<EOF
+#! /bin/sh
+# Generated automatically by configure.
+# Run this file to recreate the current configuration.
+# This directory was configured as follows,
+# on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+#
+# $0 $ac_configure_args
+#
+# Compiler output produced by configure, useful for debugging
+# configure, is in ./config.log if it exists.
+
+ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]"
+for ac_option
+do
+ case "\$ac_option" in
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion"
+ exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;;
+ -version | --version | --versio | --versi | --vers | --ver | --ve | --v)
+ echo "$CONFIG_STATUS generated by autoconf version 2.13"
+ exit 0 ;;
+ -help | --help | --hel | --he | --h)
+ echo "\$ac_cs_usage"; exit 0 ;;
+ *) echo "\$ac_cs_usage"; exit 1 ;;
+ esac
+done
+
+ac_given_srcdir=$srcdir
+ac_given_INSTALL="$INSTALL"
+
+trap 'rm -fr `echo "Makefile ../scripts/adsl-connect ../scripts/adsl-start ../scripts/adsl-stop ../scripts/adsl-init ../scripts/adsl-init-suse ../scripts/adsl-init-turbolinux ../scripts/adsl-setup ../gui/Makefile ../gui/tkpppoe config.h" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15
+EOF
+cat >> $CONFIG_STATUS <<EOF
+
+# Protect against being on the right side of a sed subst in config.status.
+sed 's/%@/@@/; s/@%/@@/; s/%g\$/@g/; /@g\$/s/[\\\\&%]/\\\\&/g;
+ s/@@/%@/; s/@@/@%/; s/@g\$/%g/' > conftest.subs <<\\CEOF
+$ac_vpsub
+$extrasub
+s%@SHELL@%$SHELL%g
+s%@CFLAGS@%$CFLAGS%g
+s%@CPPFLAGS@%$CPPFLAGS%g
+s%@CXXFLAGS@%$CXXFLAGS%g
+s%@FFLAGS@%$FFLAGS%g
+s%@DEFS@%$DEFS%g
+s%@LDFLAGS@%$LDFLAGS%g
+s%@LIBS@%$LIBS%g
+s%@exec_prefix@%$exec_prefix%g
+s%@prefix@%$prefix%g
+s%@program_transform_name@%$program_transform_name%g
+s%@bindir@%$bindir%g
+s%@sbindir@%$sbindir%g
+s%@libexecdir@%$libexecdir%g
+s%@datadir@%$datadir%g
+s%@sysconfdir@%$sysconfdir%g
+s%@sharedstatedir@%$sharedstatedir%g
+s%@localstatedir@%$localstatedir%g
+s%@libdir@%$libdir%g
+s%@includedir@%$includedir%g
+s%@oldincludedir@%$oldincludedir%g
+s%@infodir@%$infodir%g
+s%@mandir@%$mandir%g
+s%@CC@%$CC%g
+s%@CPP@%$CPP%g
+s%@ECHO@%$ECHO%g
+s%@LINUX_KERNELMODE_PLUGIN@%$LINUX_KERNELMODE_PLUGIN%g
+s%@PPPD_INCDIR@%$PPPD_INCDIR%g
+s%@PPPOE_RELAY@%$PPPOE_RELAY%g
+s%@LIBOBJS@%$LIBOBJS%g
+s%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g
+s%@INSTALL_SCRIPT@%$INSTALL_SCRIPT%g
+s%@INSTALL_DATA@%$INSTALL_DATA%g
+s%@PPPD@%$PPPD%g
+s%@SETSID@%$SETSID%g
+s%@ID@%$ID%g
+s%@WRAPPER@%$WRAPPER%g
+s%@TARGETS@%$TARGETS%g
+
+CEOF
+EOF
+
+cat >> $CONFIG_STATUS <<\EOF
+
+# Split the substitutions into bite-sized pieces for seds with
+# small command number limits, like on Digital OSF/1 and HP-UX.
+ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script.
+ac_file=1 # Number of current file.
+ac_beg=1 # First line for current file.
+ac_end=$ac_max_sed_cmds # Line after last line for current file.
+ac_more_lines=:
+ac_sed_cmds=""
+while $ac_more_lines; do
+ if test $ac_beg -gt 1; then
+ sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file
+ else
+ sed "${ac_end}q" conftest.subs > conftest.s$ac_file
+ fi
+ if test ! -s conftest.s$ac_file; then
+ ac_more_lines=false
+ rm -f conftest.s$ac_file
+ else
+ if test -z "$ac_sed_cmds"; then
+ ac_sed_cmds="sed -f conftest.s$ac_file"
+ else
+ ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file"
+ fi
+ ac_file=`expr $ac_file + 1`
+ ac_beg=$ac_end
+ ac_end=`expr $ac_end + $ac_max_sed_cmds`
+ fi
+done
+if test -z "$ac_sed_cmds"; then
+ ac_sed_cmds=cat
+fi
+EOF
+
+cat >> $CONFIG_STATUS <<EOF
+
+CONFIG_FILES=\${CONFIG_FILES-"Makefile ../scripts/adsl-connect ../scripts/adsl-start ../scripts/adsl-stop ../scripts/adsl-init ../scripts/adsl-init-suse ../scripts/adsl-init-turbolinux ../scripts/adsl-setup ../gui/Makefile ../gui/tkpppoe"}
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then
+ # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+ case "$ac_file" in
+ *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'`
+ ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
+ *) ac_file_in="${ac_file}.in" ;;
+ esac
+
+ # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories.
+
+ # Remove last slash and all that follows it. Not all systems have dirname.
+ ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
+ if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
+ # The file is in a subdirectory.
+ test ! -d "$ac_dir" && mkdir "$ac_dir"
+ ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`"
+ # A "../" for each directory in $ac_dir_suffix.
+ ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'`
+ else
+ ac_dir_suffix= ac_dots=
+ fi
+
+ case "$ac_given_srcdir" in
+ .) srcdir=.
+ if test -z "$ac_dots"; then top_srcdir=.
+ else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;;
+ /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;;
+ *) # Relative path.
+ srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix"
+ top_srcdir="$ac_dots$ac_given_srcdir" ;;
+ esac
+
+ case "$ac_given_INSTALL" in
+ [/$]*) INSTALL="$ac_given_INSTALL" ;;
+ *) INSTALL="$ac_dots$ac_given_INSTALL" ;;
+ esac
+
+ echo creating "$ac_file"
+ rm -f "$ac_file"
+ configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure."
+ case "$ac_file" in
+ *Makefile*) ac_comsub="1i\\
+# $configure_input" ;;
+ *) ac_comsub= ;;
+ esac
+
+ ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"`
+ sed -e "$ac_comsub
+s%@configure_input@%$configure_input%g
+s%@srcdir@%$srcdir%g
+s%@top_srcdir@%$top_srcdir%g
+s%@INSTALL@%$INSTALL%g
+" $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file
+fi; done
+rm -f conftest.s*
+
+# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where
+# NAME is the cpp macro being defined and VALUE is the value it is being given.
+#
+# ac_d sets the value in "#define NAME VALUE" lines.
+ac_dA='s%^\([ ]*\)#\([ ]*define[ ][ ]*\)'
+ac_dB='\([ ][ ]*\)[^ ]*%\1#\2'
+ac_dC='\3'
+ac_dD='%g'
+# ac_u turns "#undef NAME" with trailing blanks into "#define NAME VALUE".
+ac_uA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)'
+ac_uB='\([ ]\)%\1#\2define\3'
+ac_uC=' '
+ac_uD='\4%g'
+# ac_e turns "#undef NAME" without trailing blanks into "#define NAME VALUE".
+ac_eA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)'
+ac_eB='$%\1#\2define\3'
+ac_eC=' '
+ac_eD='%g'
+
+if test "${CONFIG_HEADERS+set}" != set; then
+EOF
+cat >> $CONFIG_STATUS <<EOF
+ CONFIG_HEADERS="config.h"
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+fi
+for ac_file in .. $CONFIG_HEADERS; do if test "x$ac_file" != x..; then
+ # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+ case "$ac_file" in
+ *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'`
+ ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
+ *) ac_file_in="${ac_file}.in" ;;
+ esac
+
+ echo creating $ac_file
+
+ rm -f conftest.frag conftest.in conftest.out
+ ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"`
+ cat $ac_file_inputs > conftest.in
+
+EOF
+
+# Transform confdefs.h into a sed script conftest.vals that substitutes
+# the proper values into config.h.in to produce config.h. And first:
+# Protect against being on the right side of a sed subst in config.status.
+# Protect against being in an unquoted here document in config.status.
+rm -f conftest.vals
+cat > conftest.hdr <<\EOF
+s/[\\&%]/\\&/g
+s%[\\$`]%\\&%g
+s%#define \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD}%gp
+s%ac_d%ac_u%gp
+s%ac_u%ac_e%gp
+EOF
+sed -n -f conftest.hdr confdefs.h > conftest.vals
+rm -f conftest.hdr
+
+# This sed command replaces #undef with comments. This is necessary, for
+# example, in the case of _POSIX_SOURCE, which is predefined and required
+# on some systems where configure will not decide to define it.
+cat >> conftest.vals <<\EOF
+s%^[ ]*#[ ]*undef[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*%/* & */%
+EOF
+
+# Break up conftest.vals because some shells have a limit on
+# the size of here documents, and old seds have small limits too.
+
+rm -f conftest.tail
+while :
+do
+ ac_lines=`grep -c . conftest.vals`
+ # grep -c gives empty output for an empty file on some AIX systems.
+ if test -z "$ac_lines" || test "$ac_lines" -eq 0; then break; fi
+ # Write a limited-size here document to conftest.frag.
+ echo ' cat > conftest.frag <<CEOF' >> $CONFIG_STATUS
+ sed ${ac_max_here_lines}q conftest.vals >> $CONFIG_STATUS
+ echo 'CEOF
+ sed -f conftest.frag conftest.in > conftest.out
+ rm -f conftest.in
+ mv conftest.out conftest.in
+' >> $CONFIG_STATUS
+ sed 1,${ac_max_here_lines}d conftest.vals > conftest.tail
+ rm -f conftest.vals
+ mv conftest.tail conftest.vals
+done
+rm -f conftest.vals
+
+cat >> $CONFIG_STATUS <<\EOF
+ rm -f conftest.frag conftest.h
+ echo "/* $ac_file. Generated automatically by configure. */" > conftest.h
+ cat conftest.in >> conftest.h
+ rm -f conftest.in
+ if cmp -s $ac_file conftest.h 2>/dev/null; then
+ echo "$ac_file is unchanged"
+ rm -f conftest.h
+ else
+ # Remove last slash and all that follows it. Not all systems have dirname.
+ ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
+ if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
+ # The file is in a subdirectory.
+ test ! -d "$ac_dir" && mkdir "$ac_dir"
+ fi
+ rm -f $ac_file
+ mv conftest.h $ac_file
+ fi
+fi; done
+
+EOF
+cat >> $CONFIG_STATUS <<EOF
+
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+
+exit 0
+EOF
+chmod +x $CONFIG_STATUS
+rm -fr confdefs* $ac_clean_files
+test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1
+
+
+$ECHO ""
+$ECHO "On this platform, the following targets will be built:"
+$ECHO " $TARGETS"
+$ECHO ""
+$ECHO "Type 'make' to compile the software."
diff --git a/mdk-stage1/rp-pppoe/src/configure.in b/mdk-stage1/rp-pppoe/src/configure.in
new file mode 100644
index 000000000..c11690179
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/src/configure.in
@@ -0,0 +1,231 @@
+dnl Process this file with autoconf to produce a configure script.
+AC_INIT(pppoe.c)
+
+AC_CONFIG_HEADER(config.h)
+
+AC_PREFIX_DEFAULT(/usr)
+
+dnl Checks for programs.
+AC_PROG_CC
+
+dnl Checks for libraries.
+
+dnl Checks for header files.
+AC_HEADER_STDC
+AC_HEADER_SYS_WAIT
+AC_CHECK_HEADERS(fcntl.h sys/ioctl.h sys/time.h syslog.h unistd.h net/if_arp.h netinet/if_ether.h getopt.h sys/uio.h sys/param.h fcntl.h net/bpf.h netpacket/packet.h net/ethernet.h asm/types.h linux/if_packet.h linux/if_ether.h linux/if_pppox.h sys/socket.h sys/cdefs.h linux/if.h net/if.h net/if_dl.h net/if_ether.h net/if_types.h netinet/if_ether.h net/if_types.h net/if_dl.h sys/dlpi.h )
+
+dnl Checks for typedefs, structures, and compiler characteristics.
+AC_C_CONST
+AC_TYPE_PID_T
+AC_HEADER_TIME
+AC_STRUCT_TM
+
+dnl Check for an echo which supports -n -- another hack for Solaris
+AC_PATH_PROG(ECHO, echo, "", /usr/ucb/bin:$PATH)
+
+dnl Check for sockaddr_ll
+$ECHO -n "checking for struct sockaddr_ll... "
+AC_TRY_COMPILE([#include <asm/types.h>
+#include <linux/if_packet.h>
+#include <linux/if_ether.h>
+], [struct sockaddr_ll sa;],
+ac_cv_struct_sockaddr_ll=yes, ac_cv_struct_sockaddr_ll=no)
+$ECHO $ac_cv_struct_sockaddr_ll
+if test "$ac_cv_struct_sockaddr_ll" = yes ; then
+AC_DEFINE(HAVE_STRUCT_SOCKADDR_LL)
+fi
+
+dnl Check for N_HDLC line discipline
+$ECHO -n "checking for N_HDLC line discipline... "
+AC_TRY_COMPILE([#include <linux/termios.h>],
+ [int x = N_HDLC;],
+ ac_cv_n_hdlc=yes, ac_cv_n_hdlc=no)
+$ECHO $ac_cv_n_hdlc
+if test "$ac_cv_n_hdlc" = yes ; then
+AC_DEFINE(HAVE_N_HDLC)
+fi
+
+AC_ARG_ENABLE(plugin, [ --enable-plugin=pppd_src_path build pppd plugin], ac_cv_pluginpath=$enableval, ac_cv_pluginpath=no)
+
+dnl Determine whether or not to build Linux pppd plugin
+LINUX_KERNELMODE_PLUGIN=""
+PPPD_INCDIR=""
+if test "$ac_cv_header_linux_if_pppox_h" = yes ; then
+ if test "$ac_cv_pluginpath" != no ; then
+ LINUX_KERNELMODE_PLUGIN=rp-pppoe.so
+ PPPD_INCDIR=$ac_cv_pluginpath
+ fi
+fi
+
+AC_SUBST(LINUX_KERNELMODE_PLUGIN)
+AC_SUBST(PPPD_INCDIR)
+
+dnl Determine whether or not to build PPPoE relay
+PPPOE_RELAY=""
+if test "`uname -s`" = "Linux" ; then
+ PPPOE_RELAY=pppoe-relay
+fi
+AC_SUBST(PPPOE_RELAY)
+
+dnl Checks for library functions.
+AC_FUNC_MEMCMP
+AC_FUNC_SETVBUF_REVERSED
+AC_TYPE_SIGNAL
+AC_CHECK_FUNCS(select socket strerror strtol)
+AC_PROG_INSTALL
+
+dnl Integer sizes
+AC_CHECK_SIZEOF(unsigned short)
+AC_CHECK_SIZEOF(unsigned int)
+AC_CHECK_SIZEOF(unsigned long)
+
+dnl Check for location of pppd
+AC_PATH_PROG(PPPD, pppd, NOTFOUND, $PATH:/sbin:/usr/sbin:/usr/local/sbin)
+
+dnl Check for setsid (probably Linux-specific)
+AC_PATH_PROG(SETSID, setsid, "", $PATH:/sbin:/usr/sbin:/usr/local/sbin)
+
+dnl Check for an "id" which accepts "-u" option -- hack for Solaris.
+AC_PATH_PROG(ID, id, "", /usr/xpg4/bin:$PATH)
+
+dnl Check for Linux-specific kernel support for PPPoE
+$ECHO -n "checking for Linux 2.4.X kernel-mode PPPoE support..."
+if test "`uname -s`" = "Linux" ; then
+AC_TRY_RUN([#include <sys/socket.h>
+#include <net/ethernet.h>
+#include <linux/if.h>
+#include <linux/if_pppox.h>
+int main()
+{
+ if (socket(AF_PPPOX, SOCK_DGRAM, PX_PROTO_OE) >= 0) return 0; else return 1;
+}
+], ac_cv_linux_kernel_pppoe=yes, ac_cv_linux_kernel_pppoe=no)
+else
+ ac_cv_linux_kernel_pppoe=no
+fi
+
+$ECHO $ac_cv_linux_kernel_pppoe
+if test "$ac_cv_linux_kernel_pppoe" = yes ; then
+ AC_DEFINE(HAVE_LINUX_KERNEL_PPPOE)
+fi
+
+dnl GCC warning level
+if test "$GCC" = yes; then
+ CFLAGS="$CFLAGS -Wall -Wstrict-prototypes"
+fi
+
+dnl If we couldn't find pppd, die
+if test "$PPPD" = "NOTFOUND"; then
+ $ECHO ""
+ $ECHO "*** Oops! I couldn't find pppd, the PPP daemon anywhere."
+ $ECHO "*** You must install pppd, version 2.3.10 or later."
+ $ECHO "*** I will keep going, but it may not work."
+ $ECHO ""
+fi
+
+dnl Figure out pppd version. 2.3.7 to 2.3.9 -- issue warning. Less than
+dnl 2.3.7 -- stop
+
+PPPD_VERSION=`$PPPD --version 2>&1 | awk '{print $NF}'`
+
+case "$PPPD_VERSION" in
+1.*|2.0.*|2.1.*|2.2.*|2.3.0|2.3.1|2.3.2|2.3.3|2.3.4|2.3.5|2.3.6)
+ $ECHO ""
+ $ECHO "*** Oops! Your version of pppd is $PPPD_VERSION, which is too old."
+ $ECHO "*** You need at least 2.3.7 (2.3.10 or newer recommended.)"
+ $ECHO "*** I will keep going, but it may not work."
+ $ECHO ""
+ ;;
+
+2.3.7|2.3.8|2.3.9)
+ $ECHO ""
+ $ECHO "*** Warning. Your version of pppd is $PPPD_VERSION. You will"
+ $ECHO "*** not be able to use connect-on-demand. Upgrade to pppd"
+ $ECHO "*** 2.3.10 or newer if you need connect-on-demand."
+ $ECHO ""
+ ;;
+
+2*|3*|4*|5*|6*|7*|8*|9*)
+ ;;
+
+*)
+ $ECHO ""
+ $ECHO "*** Oops. I cannot figure out what version of pppd you have."
+ $ECHO "*** All I got back was '$PPPD_VERSION'"
+ $ECHO "*** I will keep going, but it may not work."
+ $ECHO ""
+ ;;
+esac
+
+dnl Figure out packing order of structures
+$ECHO -n "checking packing order of bit fields... "
+AC_TRY_RUN([
+union foo {
+ struct bar {
+ unsigned int ver:4;
+ unsigned int type:4;
+ } bb;
+ unsigned char baz;
+};
+
+int
+main(void)
+{
+ union foo x;
+ x.bb.ver = 1;
+ x.bb.type = 2;
+ if (x.baz == 0x21) {
+ return 1;
+ } else if (x.baz == 0x12) {
+ return 0;
+ } else {
+ return 2;
+ }
+}], PACK=normal, PACK=rev)
+
+if test "$PACK" = "rev" ; then
+ $ECHO "reversed"
+ AC_DEFINE(PACK_BITFIELDS_REVERSED)
+else
+ $ECHO "normal"
+fi
+
+# Sigh... got to fix this up for tcl
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+# Fully resolve WRAPPER for Tcl script.
+WRAPPER=${sbindir}/pppoe-wrapper
+eval "WRAPPER=${WRAPPER}"
+eval "WRAPPER=${WRAPPER}"
+AC_SUBST(WRAPPER)
+
+# Determine what targets to build
+TARGETS="pppoe pppoe-server"
+
+# pppoe-sniff is built only on Linux and Solaris
+if test "$ac_cv_header_linux_if_packet_h" = "yes" -o "$ac_cv_header_sys_dlpi_h" = "yes" ; then
+ TARGETS="$TARGETS pppoe-sniff"
+fi
+
+# pppoe-relay is built only on Linux
+if test "$ac_cv_header_linux_if_packet_h" = "yes" ; then
+ TARGETS="$TARGETS pppoe-relay"
+fi
+
+# plugin is built only if we have kernel support
+if test -n "$LINUX_KERNELMODE_PLUGIN" ; then
+ TARGETS="$TARGETS $LINUX_KERNELMODE_PLUGIN"
+fi
+
+AC_SUBST(TARGETS)
+
+AC_OUTPUT(Makefile ../scripts/adsl-connect ../scripts/adsl-start ../scripts/adsl-stop ../scripts/adsl-init ../scripts/adsl-init-suse ../scripts/adsl-init-turbolinux ../scripts/adsl-setup ../gui/Makefile ../gui/tkpppoe)
+
+$ECHO ""
+$ECHO "On this platform, the following targets will be built:"
+$ECHO " $TARGETS"
+$ECHO ""
+$ECHO "Type 'make' to compile the software."
diff --git a/mdk-stage1/rp-pppoe/src/debug.c b/mdk-stage1/rp-pppoe/src/debug.c
new file mode 100644
index 000000000..c279e1197
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/src/debug.c
@@ -0,0 +1,143 @@
+/***********************************************************************
+*
+* debug.c
+*
+* Implementation of user-space PPPoE redirector for Linux.
+*
+* Functions for printing debugging information
+*
+* Copyright (C) 2000 by Roaring Penguin Software Inc.
+*
+* This program may be distributed according to the terms of the GNU
+* General Public License, version 2 or (at your option) any later version.
+*
+***********************************************************************/
+
+static char const RCSID[] =
+"$Id: debug.c 195724 2001-06-11 13:49:39Z gc $";
+
+#include "pppoe.h"
+#include <sys/time.h>
+#include <time.h>
+#include <unistd.h>
+#include <ctype.h>
+
+/**********************************************************************
+*%FUNCTION: dumpHex
+*%ARGUMENTS:
+* fp -- file to dump to
+* buf -- buffer to dump
+* len -- length of data
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Dumps buffer to fp in an easy-to-read format
+***********************************************************************/
+void
+dumpHex(FILE *fp, unsigned char const *buf, int len)
+{
+ int i;
+ int base;
+
+ if (!fp) return;
+
+ /* do NOT dump PAP packets */
+ if (len >= 2 && buf[0] == 0xC0 && buf[1] == 0x23) {
+ fprintf(fp, "(PAP Authentication Frame -- Contents not dumped)\n");
+ return;
+ }
+
+ for (base=0; base<len; base += 16) {
+ for (i=base; i<base+16; i++) {
+ if (i < len) {
+ fprintf(fp, "%02x ", (unsigned) buf[i]);
+ } else {
+ fprintf(fp, " ");
+ }
+ }
+ fprintf(fp, " ");
+ for (i=base; i<base+16; i++) {
+ if (i < len) {
+ if (isprint(buf[i])) {
+ fprintf(fp, "%c", buf[i]);
+ } else {
+ fprintf(fp, ".");
+ }
+ } else {
+ break;
+ }
+ }
+ fprintf(fp, "\n");
+ }
+}
+
+/**********************************************************************
+*%FUNCTION: dumpPacket
+*%ARGUMENTS:
+* fp -- file to dump to
+* packet -- a PPPoE packet
+* dir -- either SENT or RCVD
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Dumps the PPPoE packet to fp in an easy-to-read format
+***********************************************************************/
+void
+dumpPacket(FILE *fp, PPPoEPacket *packet, char const *dir)
+{
+ int len = ntohs(packet->length);
+
+ /* Sheesh... printing times is a pain... */
+ struct timeval tv;
+ time_t now;
+ int millisec;
+ struct tm *lt;
+ char timebuf[256];
+
+ UINT16_t type = etherType(packet);
+ if (!fp) return;
+ gettimeofday(&tv, NULL);
+ now = (time_t) tv.tv_sec;
+ millisec = tv.tv_usec / 1000;
+ lt = localtime(&now);
+ strftime(timebuf, 256, "%H:%M:%S", lt);
+ fprintf(fp, "%s.%03d %s PPPoE ", timebuf, millisec, dir);
+ if (type == Eth_PPPOE_Discovery) {
+ fprintf(fp, "Discovery (%x) ", (unsigned) type);
+ } else if (type == Eth_PPPOE_Session) {
+ fprintf(fp, "Session (%x) ", (unsigned) type);
+ } else {
+ fprintf(fp, "Unknown (%x) ", (unsigned) type);
+ }
+
+ switch(packet->code) {
+ case CODE_PADI: fprintf(fp, "PADI "); break;
+ case CODE_PADO: fprintf(fp, "PADO "); break;
+ case CODE_PADR: fprintf(fp, "PADR "); break;
+ case CODE_PADS: fprintf(fp, "PADS "); break;
+ case CODE_PADT: fprintf(fp, "PADT "); break;
+ case CODE_SESS: fprintf(fp, "SESS "); break;
+ }
+
+ fprintf(fp, "sess-id %d length %d\n",
+ (int) ntohs(packet->session),
+ len);
+
+ /* Ugly... I apologize... */
+ fprintf(fp,
+ "SourceAddr %02x:%02x:%02x:%02x:%02x:%02x "
+ "DestAddr %02x:%02x:%02x:%02x:%02x:%02x\n",
+ (unsigned) packet->ethHdr.h_source[0],
+ (unsigned) packet->ethHdr.h_source[1],
+ (unsigned) packet->ethHdr.h_source[2],
+ (unsigned) packet->ethHdr.h_source[3],
+ (unsigned) packet->ethHdr.h_source[4],
+ (unsigned) packet->ethHdr.h_source[5],
+ (unsigned) packet->ethHdr.h_dest[0],
+ (unsigned) packet->ethHdr.h_dest[1],
+ (unsigned) packet->ethHdr.h_dest[2],
+ (unsigned) packet->ethHdr.h_dest[3],
+ (unsigned) packet->ethHdr.h_dest[4],
+ (unsigned) packet->ethHdr.h_dest[5]);
+ dumpHex(fp, packet->payload, ntohs(packet->length));
+}
diff --git a/mdk-stage1/rp-pppoe/src/discovery.c b/mdk-stage1/rp-pppoe/src/discovery.c
new file mode 100644
index 000000000..74eeacc3b
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/src/discovery.c
@@ -0,0 +1,629 @@
+/***********************************************************************
+*
+* discovery.c
+*
+* Perform PPPoE discovery
+*
+* Copyright (C) 1999 by Roaring Penguin Software Inc.
+*
+***********************************************************************/
+
+static char const RCSID[] =
+"$Id: discovery.c 195724 2001-06-11 13:49:39Z gc $";
+
+#include "pppoe.h"
+
+#ifdef HAVE_SYSLOG_H
+#include <syslog.h>
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+
+#ifdef HAVE_SYS_UIO_H
+#include <sys/uio.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef USE_LINUX_PACKET
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#endif
+
+#include <signal.h>
+
+/**********************************************************************
+*%FUNCTION: parseForHostUniq
+*%ARGUMENTS:
+* type -- tag type
+* len -- tag length
+* data -- tag data.
+* extra -- user-supplied pointer. This is assumed to be a pointer to int.
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* If a HostUnique tag is found which matches our PID, sets *extra to 1.
+***********************************************************************/
+void
+parseForHostUniq(UINT16_t type, UINT16_t len, unsigned char *data,
+ void *extra)
+{
+ int *val = (int *) extra;
+ if (type == TAG_HOST_UNIQ && len == sizeof(pid_t)) {
+ pid_t tmp;
+ memcpy(&tmp, data, len);
+ if (tmp == getpid()) {
+ *val = 1;
+ }
+ }
+}
+
+/**********************************************************************
+*%FUNCTION: packetIsForMe
+*%ARGUMENTS:
+* conn -- PPPoE connection info
+* packet -- a received PPPoE packet
+*%RETURNS:
+* 1 if packet is for this PPPoE daemon; 0 otherwise.
+*%DESCRIPTION:
+* If we are using the Host-Unique tag, verifies that packet contains
+* our unique identifier.
+***********************************************************************/
+int
+packetIsForMe(PPPoEConnection *conn, PPPoEPacket *packet)
+{
+ int forMe = 0;
+
+ /* If we're not using the Host-Unique tag, then accept the packet */
+ if (!conn->useHostUniq) return 1;
+
+ parsePacket(packet, parseForHostUniq, &forMe);
+ return forMe;
+}
+
+/**********************************************************************
+*%FUNCTION: parsePADOTags
+*%ARGUMENTS:
+* type -- tag type
+* len -- tag length
+* data -- tag data
+* extra -- extra user data. Should point to a PacketCriteria structure
+* which gets filled in according to selected AC name and service
+* name.
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Picks interesting tags out of a PADO packet
+***********************************************************************/
+void
+parsePADOTags(UINT16_t type, UINT16_t len, unsigned char *data,
+ void *extra)
+{
+ struct PacketCriteria *pc = (struct PacketCriteria *) extra;
+ PPPoEConnection *conn = pc->conn;
+ int i;
+
+ switch(type) {
+ case TAG_AC_NAME:
+ if (conn->printACNames) {
+ printf("Access-Concentrator: %.*s\n", (int) len, data);
+ }
+ if (conn->acName && len == strlen(conn->acName) &&
+ !strncmp((char *) data, conn->acName, len)) {
+ pc->acNameOK = 1;
+ }
+ break;
+ case TAG_SERVICE_NAME:
+ if (conn->printACNames && len > 0) {
+ printf(" Service-Name: %.*s\n", (int) len, data);
+ }
+ if (conn->serviceName && len == strlen(conn->serviceName) &&
+ !strncmp((char *) data, conn->serviceName, len)) {
+ pc->serviceNameOK = 1;
+ }
+ break;
+ case TAG_AC_COOKIE:
+ if (conn->printACNames) {
+ printf("Got a cookie:");
+ /* Print first 20 bytes of cookie */
+ for (i=0; i<len && i < 20; i++) {
+ printf(" %02x", (unsigned) data[i]);
+ }
+ if (i < len) printf("...");
+ printf("\n");
+ }
+ conn->cookie.type = htons(type);
+ conn->cookie.length = htons(len);
+ memcpy(conn->cookie.payload, data, len);
+ break;
+ case TAG_RELAY_SESSION_ID:
+ if (conn->printACNames) {
+ printf("Got a Relay-ID:");
+ /* Print first 20 bytes of relay ID */
+ for (i=0; i<len && i < 20; i++) {
+ printf(" %02x", (unsigned) data[i]);
+ }
+ if (i < len) printf("...");
+ printf("\n");
+ }
+ conn->relayId.type = htons(type);
+ conn->relayId.length = htons(len);
+ memcpy(conn->relayId.payload, data, len);
+ break;
+ case TAG_SERVICE_NAME_ERROR:
+ if (conn->printACNames) {
+ printf("Got a Service-Name-Error tag: %.*s\n", (int) len, data);
+ } else {
+ syslog(LOG_ERR, "PADO: Service-Name-Error: %.*s", (int) len, data);
+ exit(1);
+ }
+ break;
+ case TAG_AC_SYSTEM_ERROR:
+ if (conn->printACNames) {
+ printf("Got a System-Error tag: %.*s\n", (int) len, data);
+ } else {
+ syslog(LOG_ERR, "PADO: System-Error: %.*s", (int) len, data);
+ exit(1);
+ }
+ break;
+ case TAG_GENERIC_ERROR:
+ if (conn->printACNames) {
+ printf("Got a Generic-Error tag: %.*s\n", (int) len, data);
+ } else {
+ syslog(LOG_ERR, "PADO: Generic-Error: %.*s", (int) len, data);
+ exit(1);
+ }
+ break;
+ }
+}
+
+/**********************************************************************
+*%FUNCTION: parsePADSTags
+*%ARGUMENTS:
+* type -- tag type
+* len -- tag length
+* data -- tag data
+* extra -- extra user data (pointer to PPPoEConnection structure)
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Picks interesting tags out of a PADS packet
+***********************************************************************/
+void
+parsePADSTags(UINT16_t type, UINT16_t len, unsigned char *data,
+ void *extra)
+{
+ PPPoEConnection *conn = (PPPoEConnection *) extra;
+ switch(type) {
+ case TAG_SERVICE_NAME:
+ syslog(LOG_DEBUG, "PADS: Service-Name: '%.*s'", (int) len, data);
+ break;
+ case TAG_SERVICE_NAME_ERROR:
+ syslog(LOG_ERR, "PADS: Service-Name-Error: %.*s", (int) len, data);
+ fprintf(stderr, "PADS: Service-Name-Error: %.*s\n", (int) len, data);
+ exit(1);
+ case TAG_AC_SYSTEM_ERROR:
+ syslog(LOG_ERR, "PADS: System-Error: %.*s", (int) len, data);
+ fprintf(stderr, "PADS: System-Error: %.*s\n", (int) len, data);
+ exit(1);
+ case TAG_GENERIC_ERROR:
+ syslog(LOG_ERR, "PADS: Generic-Error: %.*s", (int) len, data);
+ fprintf(stderr, "PADS: Generic-Error: %.*s\n", (int) len, data);
+ exit(1);
+ case TAG_RELAY_SESSION_ID:
+ conn->relayId.type = htons(type);
+ conn->relayId.length = htons(len);
+ memcpy(conn->relayId.payload, data, len);
+ break;
+ }
+}
+
+/***********************************************************************
+*%FUNCTION: sendPADI
+*%ARGUMENTS:
+* conn -- PPPoEConnection structure
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Sends a PADI packet
+***********************************************************************/
+void
+sendPADI(PPPoEConnection *conn)
+{
+ PPPoEPacket packet;
+ unsigned char *cursor = packet.payload;
+ PPPoETag *svc = (PPPoETag *) (&packet.payload);
+ UINT16_t namelen = 0;
+ UINT16_t plen;
+
+ if (conn->serviceName) {
+ namelen = (UINT16_t) strlen(conn->serviceName);
+ }
+ plen = TAG_HDR_SIZE + namelen;
+ CHECK_ROOM(cursor, packet.payload, plen);
+
+ /* Set destination to Ethernet broadcast address */
+ memset(packet.ethHdr.h_dest, 0xFF, ETH_ALEN);
+ memcpy(packet.ethHdr.h_source, conn->myEth, ETH_ALEN);
+
+ packet.ethHdr.h_proto = htons(Eth_PPPOE_Discovery);
+ packet.ver = 1;
+ packet.type = 1;
+ packet.code = CODE_PADI;
+ packet.session = 0;
+
+ svc->type = TAG_SERVICE_NAME;
+ svc->length = htons(namelen);
+ CHECK_ROOM(cursor, packet.payload, namelen+TAG_HDR_SIZE);
+
+ if (conn->serviceName) {
+ memcpy(svc->payload, conn->serviceName, strlen(conn->serviceName));
+ }
+ cursor += namelen + TAG_HDR_SIZE;
+
+ /* If we're using Host-Uniq, copy it over */
+ if (conn->useHostUniq) {
+ PPPoETag hostUniq;
+ pid_t pid = getpid();
+ hostUniq.type = htons(TAG_HOST_UNIQ);
+ hostUniq.length = htons(sizeof(pid));
+ memcpy(hostUniq.payload, &pid, sizeof(pid));
+ CHECK_ROOM(cursor, packet.payload, sizeof(pid) + TAG_HDR_SIZE);
+ memcpy(cursor, &hostUniq, sizeof(pid) + TAG_HDR_SIZE);
+ cursor += sizeof(pid) + TAG_HDR_SIZE;
+ plen += sizeof(pid) + TAG_HDR_SIZE;
+ }
+
+ packet.length = htons(plen);
+
+ sendPacket(conn, conn->discoverySocket, &packet, (int) (plen + HDR_SIZE));
+ if (conn->debugFile) {
+ dumpPacket(conn->debugFile, &packet, "SENT");
+ fprintf(conn->debugFile, "\n");
+ fflush(conn->debugFile);
+ }
+}
+
+/**********************************************************************
+*%FUNCTION: waitForPADO
+*%ARGUMENTS:
+* conn -- PPPoEConnection structure
+* timeout -- how long to wait (in seconds)
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Waits for a PADO packet and copies useful information
+***********************************************************************/
+void
+waitForPADO(PPPoEConnection *conn, int timeout)
+{
+ fd_set readable;
+ int r;
+ struct timeval tv;
+ PPPoEPacket packet;
+ int len;
+
+ struct PacketCriteria pc;
+ pc.conn = conn;
+ pc.acNameOK = (conn->acName) ? 0 : 1;
+ pc.serviceNameOK = (conn->serviceName) ? 0 : 1;
+
+ do {
+ if (BPF_BUFFER_IS_EMPTY) {
+ tv.tv_sec = timeout;
+ tv.tv_usec = 0;
+
+ FD_ZERO(&readable);
+ FD_SET(conn->discoverySocket, &readable);
+
+ while(1) {
+ r = select(conn->discoverySocket+1, &readable, NULL, NULL, &tv);
+ if (r >= 0 || errno != EINTR) break;
+ }
+ if (r < 0) {
+ fatalSys("select (waitForPADO)");
+ }
+ if (r == 0) return; /* Timed out */
+ }
+
+ /* Get the packet */
+ receivePacket(conn->discoverySocket, &packet, &len);
+
+ /* Check length */
+ if (ntohs(packet.length) + HDR_SIZE > len) {
+ syslog(LOG_ERR, "Bogus PPPoE length field (%u)",
+ (unsigned int) ntohs(packet.length));
+ continue;
+ }
+
+#ifdef USE_BPF
+ /* If it's not a Discovery packet, loop again */
+ if (etherType(&packet) != Eth_PPPOE_Discovery) continue;
+#endif
+
+ if (conn->debugFile) {
+ dumpPacket(conn->debugFile, &packet, "RCVD");
+ fprintf(conn->debugFile, "\n");
+ fflush(conn->debugFile);
+ }
+ /* If it's not for us, loop again */
+ if (!packetIsForMe(conn, &packet)) continue;
+
+ if (packet.code == CODE_PADO) {
+ if (NOT_UNICAST(packet.ethHdr.h_source)) {
+ printErr("Ignoring PADO packet from non-unicast MAC address");
+ continue;
+ }
+ conn->numPADOs++;
+ if (conn->printACNames) {
+ printf("--------------------------------------------------\n");
+ }
+ parsePacket(&packet, parsePADOTags, &pc);
+ if (pc.acNameOK && pc.serviceNameOK) {
+ memcpy(conn->peerEth, packet.ethHdr.h_source, ETH_ALEN);
+ if (conn->printACNames) {
+ printf("AC-Ethernet-Address: %02x:%02x:%02x:%02x:%02x:%02x\n",
+ (unsigned) conn->peerEth[0],
+ (unsigned) conn->peerEth[1],
+ (unsigned) conn->peerEth[2],
+ (unsigned) conn->peerEth[3],
+ (unsigned) conn->peerEth[4],
+ (unsigned) conn->peerEth[5]);
+ continue;
+ }
+ conn->discoveryState = STATE_RECEIVED_PADO;
+ break;
+ }
+ }
+ } while (conn->discoveryState != STATE_RECEIVED_PADO);
+}
+
+/***********************************************************************
+*%FUNCTION: sendPADR
+*%ARGUMENTS:
+* conn -- PPPoE connection structur
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Sends a PADR packet
+***********************************************************************/
+void
+sendPADR(PPPoEConnection *conn)
+{
+ PPPoEPacket packet;
+ PPPoETag *svc = (PPPoETag *) packet.payload;
+ unsigned char *cursor = packet.payload;
+
+ UINT16_t namelen = 0;
+ UINT16_t plen;
+
+ if (conn->serviceName) {
+ namelen = (UINT16_t) strlen(conn->serviceName);
+ }
+ plen = TAG_HDR_SIZE + namelen;
+ CHECK_ROOM(cursor, packet.payload, plen);
+
+ memcpy(packet.ethHdr.h_dest, conn->peerEth, ETH_ALEN);
+ memcpy(packet.ethHdr.h_source, conn->myEth, ETH_ALEN);
+
+ packet.ethHdr.h_proto = htons(Eth_PPPOE_Discovery);
+ packet.ver = 1;
+ packet.type = 1;
+ packet.code = CODE_PADR;
+ packet.session = 0;
+
+ svc->type = TAG_SERVICE_NAME;
+ svc->length = htons(namelen);
+ if (conn->serviceName) {
+ memcpy(svc->payload, conn->serviceName, namelen);
+ }
+ cursor += namelen + TAG_HDR_SIZE;
+
+ /* If we're using Host-Uniq, copy it over */
+ if (conn->useHostUniq) {
+ PPPoETag hostUniq;
+ pid_t pid = getpid();
+ hostUniq.type = htons(TAG_HOST_UNIQ);
+ hostUniq.length = htons(sizeof(pid));
+ memcpy(hostUniq.payload, &pid, sizeof(pid));
+ CHECK_ROOM(cursor, packet.payload, sizeof(pid)+TAG_HDR_SIZE);
+ memcpy(cursor, &hostUniq, sizeof(pid) + TAG_HDR_SIZE);
+ cursor += sizeof(pid) + TAG_HDR_SIZE;
+ plen += sizeof(pid) + TAG_HDR_SIZE;
+ }
+
+ /* Copy cookie and relay-ID if needed */
+ if (conn->cookie.type) {
+ CHECK_ROOM(cursor, packet.payload,
+ ntohs(conn->cookie.length) + TAG_HDR_SIZE);
+ memcpy(cursor, &conn->cookie, ntohs(conn->cookie.length) + TAG_HDR_SIZE);
+ cursor += ntohs(conn->cookie.length) + TAG_HDR_SIZE;
+ plen += ntohs(conn->cookie.length) + TAG_HDR_SIZE;
+ }
+
+ if (conn->relayId.type) {
+ CHECK_ROOM(cursor, packet.payload,
+ ntohs(conn->relayId.length) + TAG_HDR_SIZE);
+ memcpy(cursor, &conn->relayId, ntohs(conn->relayId.length) + TAG_HDR_SIZE);
+ cursor += ntohs(conn->relayId.length) + TAG_HDR_SIZE;
+ plen += ntohs(conn->relayId.length) + TAG_HDR_SIZE;
+ }
+
+ packet.length = htons(plen);
+ sendPacket(conn, conn->discoverySocket, &packet, (int) (plen + HDR_SIZE));
+ if (conn->debugFile) {
+ dumpPacket(conn->debugFile, &packet, "SENT");
+ fprintf(conn->debugFile, "\n");
+ fflush(conn->debugFile);
+ }
+}
+
+/**********************************************************************
+*%FUNCTION: waitForPADS
+*%ARGUMENTS:
+* conn -- PPPoE connection info
+* timeout -- how long to wait (in seconds)
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Waits for a PADS packet and copies useful information
+***********************************************************************/
+void
+waitForPADS(PPPoEConnection *conn, int timeout)
+{
+ fd_set readable;
+ int r;
+ struct timeval tv;
+ PPPoEPacket packet;
+ int len;
+
+ do {
+ if (BPF_BUFFER_IS_EMPTY) {
+ tv.tv_sec = timeout;
+ tv.tv_usec = 0;
+
+ FD_ZERO(&readable);
+ FD_SET(conn->discoverySocket, &readable);
+
+ while(1) {
+ r = select(conn->discoverySocket+1, &readable, NULL, NULL, &tv);
+ if (r >= 0 || errno != EINTR) break;
+ }
+ if (r < 0) {
+ fatalSys("select (waitForPADS)");
+ }
+ if (r == 0) return;
+ }
+
+ /* Get the packet */
+ receivePacket(conn->discoverySocket, &packet, &len);
+
+ /* Check length */
+ if (ntohs(packet.length) + HDR_SIZE > len) {
+ syslog(LOG_ERR, "Bogus PPPoE length field (%u)",
+ (unsigned int) ntohs(packet.length));
+ continue;
+ }
+
+#ifdef USE_BPF
+ /* If it's not a Discovery packet, loop again */
+ if (etherType(&packet) != Eth_PPPOE_Discovery) continue;
+#endif
+ if (conn->debugFile) {
+ dumpPacket(conn->debugFile, &packet, "RCVD");
+ fprintf(conn->debugFile, "\n");
+ fflush(conn->debugFile);
+ }
+
+ /* If it's not from the AC, it's not for me */
+ if (memcmp(packet.ethHdr.h_source, conn->peerEth, ETH_ALEN)) continue;
+
+ /* If it's not for us, loop again */
+ if (!packetIsForMe(conn, &packet)) continue;
+
+ /* Is it PADS? */
+ if (packet.code == CODE_PADS) {
+ /* Parse for goodies */
+ parsePacket(&packet, parsePADSTags, conn);
+ conn->discoveryState = STATE_SESSION;
+ break;
+ }
+ } while (conn->discoveryState != STATE_SESSION);
+
+ /* Don't bother with ntohs; we'll just end up converting it back... */
+ conn->session = packet.session;
+
+ syslog(LOG_INFO, "PPP session is %d", (int) ntohs(conn->session));
+
+ /* RFC 2516 says session id MUST NOT be zero or 0xFFFF */
+ if (ntohs(conn->session) == 0 || ntohs(conn->session) == 0xFFFF) {
+ syslog(LOG_ERR, "Access concentrator used a session value of %x -- the AC is violating RFC 2516", (unsigned int) ntohs(conn->session));
+ }
+}
+
+/**********************************************************************
+*%FUNCTION: discovery
+*%ARGUMENTS:
+* conn -- PPPoE connection info structure
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Performs the PPPoE discovery phase
+***********************************************************************/
+void
+discovery(PPPoEConnection *conn)
+{
+ int padiAttempts = 0;
+ int padrAttempts = 0;
+ int timeout = PADI_TIMEOUT;
+
+ /* Skip discovery and don't open discovery socket? */
+ if (conn->skipDiscovery && conn->noDiscoverySocket) {
+ conn->discoveryState = STATE_SESSION;
+ return;
+ }
+
+ conn->discoverySocket =
+ openInterface(conn->ifName, Eth_PPPOE_Discovery, conn->myEth);
+
+ /* Skip discovery? */
+ if (conn->skipDiscovery) {
+ conn->discoveryState = STATE_SESSION;
+ if (conn->killSession) {
+ sendPADT(conn, "RP-PPPoE: Session killed manually");
+ exit(0);
+ }
+ return;
+ }
+
+ do {
+ padiAttempts++;
+ if (padiAttempts > MAX_PADI_ATTEMPTS) {
+ rp_fatal("Timeout waiting for PADO packets");
+ }
+ sendPADI(conn);
+ conn->discoveryState = STATE_SENT_PADI;
+ waitForPADO(conn, timeout);
+
+ /* If we're just probing for access concentrators, don't do
+ exponential backoff. This reduces the time for an unsuccessful
+ probe to 15 seconds. */
+ if (!conn->printACNames) {
+ timeout *= 2;
+ }
+ if (conn->printACNames && conn->numPADOs) {
+ break;
+ }
+ } while (conn->discoveryState == STATE_SENT_PADI);
+
+ /* If we're only printing access concentrator names, we're done */
+ if (conn->printACNames) {
+ printf("--------------------------------------------------\n");
+ exit(0);
+ }
+
+ timeout = PADI_TIMEOUT;
+ do {
+ padrAttempts++;
+ if (padrAttempts > MAX_PADI_ATTEMPTS) {
+ rp_fatal("Timeout waiting for PADS packets");
+ }
+ sendPADR(conn);
+ conn->discoveryState = STATE_SENT_PADR;
+ waitForPADS(conn, timeout);
+ timeout *= 2;
+ } while (conn->discoveryState == STATE_SENT_PADR);
+
+ /* We're done. */
+ conn->discoveryState = STATE_SESSION;
+ return;
+}
+
diff --git a/mdk-stage1/rp-pppoe/src/if.c b/mdk-stage1/rp-pppoe/src/if.c
new file mode 100644
index 000000000..07203b116
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/src/if.c
@@ -0,0 +1,1092 @@
+/***********************************************************************
+*
+* if.c
+*
+* Implementation of user-space PPPoE redirector for Linux.
+*
+* Functions for opening a raw socket and reading/writing raw Ethernet frames.
+*
+* Copyright (C) 2000 by Roaring Penguin Software Inc.
+*
+* This program may be distributed according to the terms of the GNU
+* General Public License, version 2 or (at your option) any later version.
+*
+***********************************************************************/
+
+static char const RCSID[] =
+"$Id: if.c 195724 2001-06-11 13:49:39Z gc $";
+
+#include "pppoe.h"
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef HAVE_NETPACKET_PACKET_H
+#include <netpacket/packet.h>
+#elif defined(HAVE_LINUX_IF_PACKET_H)
+#include <linux/if_packet.h>
+#endif
+
+#ifdef HAVE_NET_ETHERNET_H
+#include <net/ethernet.h>
+#endif
+
+#ifdef HAVE_ASM_TYPES_H
+#include <asm/types.h>
+#endif
+
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+
+#ifdef HAVE_SYSLOG_H
+#include <syslog.h>
+#endif
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef HAVE_NET_IF_ARP_H
+#include <net/if_arp.h>
+#endif
+
+#ifdef USE_DLPI
+
+#include <limits.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/stream.h>
+#include <sys/stropts.h>
+#include <sys/dlpi.h>
+#include <sys/bufmod.h>
+#include <stdio.h>
+#include <signal.h>
+#include <stropts.h>
+
+/* function declarations */
+
+void dlpromisconreq( int fd, u_long level);
+void dlinforeq(int fd);
+void dlunitdatareq(int fd, u_char *addrp, int addrlen, u_long minpri, u_long maxpri, u_char *datap, int datalen);
+void dlinfoack(int fd, char *bufp);
+void dlbindreq(int fd, u_long sap, u_long max_conind, u_long service_mode, u_long conn_mgmt, u_long xidtest);
+void dlattachreq(int fd, u_long ppa);
+void dlokack(int fd, char *bufp);
+void dlbindack(int fd, char *bufp);
+int strioctl(int fd, int cmd, int timout, int len, char *dp);
+void strgetmsg(int fd, struct strbuf *ctlp, struct strbuf *datap, int *flagsp, char *caller);
+void sigalrm(int sig);
+void expecting(int prim, union DL_primitives *dlp);
+char *dlprim(u_long prim);
+
+/* #define DL_DEBUG */
+
+static int dl_abssaplen;
+static int dl_saplen;
+static int dl_addrlen;
+
+#endif
+
+#ifdef USE_BPF
+#include <net/bpf.h>
+#include <fcntl.h>
+
+unsigned char *bpfBuffer; /* Packet filter buffer */
+int bpfLength = 0; /* Packet filter buffer length */
+int bpfSize = 0; /* Number of unread bytes in buffer */
+int bpfOffset = 0; /* Current offset in bpfBuffer */
+#endif
+
+/* Initialize frame types to RFC 2516 values. Some broken peers apparently
+ use different frame types... sigh... */
+
+UINT16_t Eth_PPPOE_Discovery = ETH_PPPOE_DISCOVERY;
+UINT16_t Eth_PPPOE_Session = ETH_PPPOE_SESSION;
+
+/**********************************************************************
+*%FUNCTION: etherType
+*%ARGUMENTS:
+* packet -- a received PPPoE packet
+*%RETURNS:
+* ethernet packet type (see /usr/include/net/ethertypes.h)
+*%DESCRIPTION:
+* Checks the ethernet packet header to determine its type.
+* We should only be receveing DISCOVERY and SESSION types if the BPF
+* is set up correctly. Logs an error if an unexpected type is received.
+* Note that the ethernet type names come from "pppoe.h" and the packet
+* packet structure names use the LINUX dialect to maintain consistency
+* with the rest of this file. See the BSD section of "pppoe.h" for
+* translations of the data structure names.
+***********************************************************************/
+UINT16_t
+etherType(PPPoEPacket *packet)
+{
+ UINT16_t type = (UINT16_t) ntohs(packet->ethHdr.h_proto);
+ if (type != Eth_PPPOE_Discovery && type != Eth_PPPOE_Session) {
+ syslog(LOG_ERR, "Invalid ether type 0x%x", type);
+ }
+ return type;
+}
+
+#ifdef USE_BPF
+/**********************************************************************
+*%FUNCTION: getHWaddr
+*%ARGUMENTS:
+* ifname -- name of interface
+* hwaddr -- buffer for ehthernet address
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Locates the Ethernet hardware address for an interface.
+***********************************************************************/
+void
+getHWaddr(int sock, char const *ifname, unsigned char *hwaddr)
+{
+ char inbuf[8192];
+ const struct sockaddr_dl *sdl;
+ struct ifconf ifc;
+ struct ifreq ifreq, *ifr;
+ int i;
+ int found = 0;
+
+ ifc.ifc_len = sizeof(inbuf);
+ ifc.ifc_buf = inbuf;
+ if (ioctl(sock, SIOCGIFCONF, &ifc) < 0) {
+ fatalSys("SIOCGIFCONF");
+ }
+ ifr = ifc.ifc_req;
+ ifreq.ifr_name[0] = '\0';
+ for (i = 0; i < ifc.ifc_len; ) {
+ ifr = (struct ifreq *)((caddr_t)ifc.ifc_req + i);
+ i += sizeof(ifr->ifr_name) +
+ (ifr->ifr_addr.sa_len > sizeof(struct sockaddr)
+ ? ifr->ifr_addr.sa_len
+ : sizeof(struct sockaddr));
+ if (ifr->ifr_addr.sa_family == AF_LINK) {
+ sdl = (const struct sockaddr_dl *) &ifr->ifr_addr;
+ if ((sdl->sdl_type == IFT_ETHER) &&
+ (sdl->sdl_alen == ETH_ALEN) &&
+ !strncmp(ifname, ifr->ifr_name, sizeof(ifr->ifr_name))) {
+ if (found) {
+ char buffer[256];
+ sprintf(buffer, "interface %.16s has more than one ethernet address", ifname);
+ rp_fatal(buffer);
+ } else {
+ found = 1;
+ memcpy(hwaddr, LLADDR(sdl), ETH_ALEN);
+ }
+ }
+ }
+ }
+ if (!found) {
+ char buffer[256];
+ sprintf(buffer, "interface %.16s has no ethernet address", ifname);
+ rp_fatal(buffer);
+ }
+}
+
+/**********************************************************************
+*%FUNCTION: initFilter
+*%ARGUMENTS:
+* fd -- file descriptor of BSD device
+* type -- Ethernet frame type (0 for watch mode)
+* hwaddr -- buffer with ehthernet address
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Initializes the packet filter rules.
+***********************************************************************/
+void
+initFilter(int fd, UINT16_t type, unsigned char *hwaddr)
+{
+ /* Packet Filter Instructions:
+ * Note that the ethernet type names come from "pppoe.h" and are
+ * used here to maintain consistency with the rest of this file. */
+ static struct bpf_insn bpfRun[] = { /* run PPPoE */
+ BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 12), /* ethernet type */
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ETH_PPPOE_SESSION, 5, 0),
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ETH_PPPOE_DISCOVERY, 0, 9),
+ BPF_STMT(BPF_LD+BPF_W+BPF_ABS, 0), /* first word of dest. addr */
+#define PPPOE_BCAST_CMPW 4 /* offset of word compare */
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0, 0, 2),
+ BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 4), /* next 1/2 word of dest. */
+#define PPPOE_BCAST_CMPH 6 /* offset of 1/2 word compare */
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0, 4, 0),
+ BPF_STMT(BPF_LD+BPF_W+BPF_ABS, 0), /* first word of dest. addr */
+#define PPPOE_FILTER_CMPW 8 /* offset of word compare */
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0, 0, 3),
+ BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 4), /* next 1/2 word of dest. */
+#define PPPOE_FILTER_CMPH 10 /* offset of 1/rd compare */
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0, 0, 1),
+ BPF_STMT(BPF_RET+BPF_K, (u_int) -1), /* keep packet */
+ BPF_STMT(BPF_RET+BPF_K, 0), /* drop packet */
+ };
+
+ /* Fix the potentially varying parts */
+ bpfRun[1].code = (u_short) BPF_JMP+BPF_JEQ+BPF_K;
+ bpfRun[1].jt = 5;
+ bpfRun[1].jf = 0;
+ bpfRun[1].k = Eth_PPPOE_Session;
+
+ bpfRun[2].code = (u_short) BPF_JMP+BPF_JEQ+BPF_K;
+ bpfRun[2].jt = 0;
+ bpfRun[2].jf = 9;
+ bpfRun[2].k = Eth_PPPOE_Discovery;
+
+ {
+ struct bpf_insn bpfInsn[sizeof(bpfRun) / sizeof(bpfRun[0])];
+ struct bpf_program bpfProgram;
+ memcpy(bpfInsn, bpfRun, sizeof(bpfRun));
+ bpfInsn[PPPOE_BCAST_CMPW].k = ((0xff << 24) | (0xff << 16) |
+ (0xff << 8) | 0xff);
+ bpfInsn[PPPOE_BCAST_CMPH].k = ((0xff << 8) | 0xff);
+ bpfInsn[PPPOE_FILTER_CMPW].k = ((hwaddr[0] << 24) | (hwaddr[1] << 16) |
+ (hwaddr[2] << 8) | hwaddr[3]);
+ bpfInsn[PPPOE_FILTER_CMPH].k = ((hwaddr[4] << 8) | hwaddr[5]);
+ bpfProgram.bf_len = (sizeof(bpfInsn) / sizeof(bpfInsn[0]));
+ bpfProgram.bf_insns = &bpfInsn[0];
+
+ /* Apply the filter */
+ if (ioctl(fd, BIOCSETF, &bpfProgram) < 0) {
+ fatalSys("ioctl(BIOCSETF)");
+ }
+ }
+}
+
+/**********************************************************************
+*%FUNCTION: openInterface
+*%ARGUMENTS:
+* ifname -- name of interface
+* type -- Ethernet frame type (0 for any frame type)
+* hwaddr -- if non-NULL, set to the hardware address
+*%RETURNS:
+* A file descriptor for talking with the Ethernet card. Exits on error.
+* Note that the Linux version of this routine returns a socket instead.
+*%DESCRIPTION:
+* Opens a BPF on an interface for all PPPoE traffic (discovery and
+* session). If 'type' is 0, uses promiscuous mode to watch any PPPoE
+* traffic on this network.
+***********************************************************************/
+int
+openInterface(char const *ifname, UINT16_t type, unsigned char *hwaddr)
+{
+ static int fd = -1;
+ char bpfName[32];
+ u_int optval;
+ struct bpf_version bpf_ver;
+ struct ifreq ifr;
+ int sock;
+ int i;
+
+ /* BSD only opens one socket for both Discovery and Session packets */
+ if (fd >= 0) {
+ return fd;
+ }
+
+ /* Find a free BPF device */
+ for (i = 0; i < 256; i++) {
+ sprintf(bpfName, "/dev/bpf%d", i);
+ if (((fd = open(bpfName, O_RDWR, 0)) >= 0) ||
+ (errno != EBUSY)) {
+ break;
+ }
+ }
+ if (fd < 0) {
+ switch (errno) {
+ case EACCES: /* permission denied */
+ {
+ char buffer[256];
+ sprintf(buffer, "Cannot open %.32s -- pppoe must be run as root.", bpfName);
+ rp_fatal(buffer);
+ }
+ break;
+ case EBUSY:
+ case ENOENT: /* no such file */
+ if (i == 0) {
+ rp_fatal("No /dev/bpf* devices (check your kernel configuration for BPF support)");
+ } else {
+ rp_fatal("All /dev/bpf* devices are in use");
+ }
+ break;
+ }
+ fatalSys(bpfName);
+ }
+
+ if ((sock = socket(AF_LOCAL, SOCK_DGRAM, 0)) < 0) {
+ fatalSys("socket");
+ }
+
+ /* Check that the interface is up */
+ strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+ if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) {
+ fatalSys("ioctl(SIOCGIFFLAGS)");
+ }
+ if ((ifr.ifr_flags & IFF_UP) == 0) {
+ char buffer[256];
+ sprintf(buffer, "Interface %.16s is not up\n", ifname);
+ rp_fatal(buffer);
+ }
+
+ /* Fill in hardware address and initialize the packet filter rules */
+ if (hwaddr == NULL) {
+ rp_fatal("openInterface: no hwaddr arg.");
+ }
+ getHWaddr(sock, ifname, hwaddr);
+ initFilter(fd, type, hwaddr);
+
+ /* Sanity check on MTU -- apparently does not work on OpenBSD */
+#if !defined(__OpenBSD__)
+ strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+ if (ioctl(sock, SIOCGIFMTU, &ifr) < 0) {
+ fatalSys("ioctl(SIOCGIFMTU)");
+ }
+ if (ifr.ifr_mtu < ETH_DATA_LEN) {
+ char buffer[256];
+ sprintf(buffer, "Interface %.16s has MTU of %d -- should be %d. You may have serious connection problems.",
+ ifname, ifr.ifr_mtu, ETH_DATA_LEN);
+ printErr(buffer);
+ }
+#endif
+
+ /* done with the socket */
+ if (close(sock) < 0) {
+ fatalSys("close");
+ }
+
+ /* Check the BPF version number */
+ if (ioctl(fd, BIOCVERSION, &bpf_ver) < 0) {
+ fatalSys("ioctl(BIOCVERSION)");
+ }
+ if ((bpf_ver.bv_major != BPF_MAJOR_VERSION) ||
+ (bpf_ver.bv_minor < BPF_MINOR_VERSION)) {
+ char buffer[256];
+ sprintf(buffer, "Unsupported BPF version: %d.%d (kernel: %d.%d)",
+ BPF_MAJOR_VERSION, BPF_MINOR_VERSION,
+ bpf_ver.bv_major, bpf_ver.bv_minor);
+ rp_fatal(buffer);
+ }
+
+ /* allocate a receive packet buffer */
+ if (ioctl(fd, BIOCGBLEN, &bpfLength) < 0) {
+ fatalSys("ioctl(BIOCGBLEN)");
+ }
+ if (!(bpfBuffer = (unsigned char *) malloc(bpfLength))) {
+ rp_fatal("malloc");
+ }
+
+ /* reads should return as soon as there is a packet available */
+ optval = 1;
+ if (ioctl(fd, BIOCIMMEDIATE, &optval) < 0) {
+ fatalSys("ioctl(BIOCIMMEDIATE)");
+ }
+
+ /* Bind the interface to the filter */
+ strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+ if (ioctl(fd, BIOCSETIF, &ifr) < 0) {
+ char buffer[256];
+ sprintf(buffer, "ioctl(BIOCSETIF) can't select interface %.16s",
+ ifname);
+ rp_fatal(buffer);
+ }
+
+ syslog(LOG_INFO, "Interface=%.16s HWaddr=%02X:%02X:%02X:%02X:%02X:%02X Device=%.32s Buffer size=%d",
+ ifname,
+ hwaddr[0], hwaddr[1], hwaddr[2],
+ hwaddr[3], hwaddr[4], hwaddr[5],
+ bpfName, bpfLength);
+ return fd;
+}
+
+#endif /* USE_BPF */
+
+#ifdef USE_LINUX_PACKET
+/**********************************************************************
+*%FUNCTION: openInterface
+*%ARGUMENTS:
+* ifname -- name of interface
+* type -- Ethernet frame type
+* hwaddr -- if non-NULL, set to the hardware address
+*%RETURNS:
+* A raw socket for talking to the Ethernet card. Exits on error.
+*%DESCRIPTION:
+* Opens a raw Ethernet socket
+***********************************************************************/
+int
+openInterface(char const *ifname, UINT16_t type, unsigned char *hwaddr)
+{
+ int optval=1;
+ int fd;
+ struct ifreq ifr;
+ int domain, stype;
+
+#ifdef HAVE_STRUCT_SOCKADDR_LL
+ struct sockaddr_ll sa;
+#else
+ struct sockaddr sa;
+#endif
+
+ memset(&sa, 0, sizeof(sa));
+
+#ifdef HAVE_STRUCT_SOCKADDR_LL
+ domain = PF_PACKET;
+ stype = SOCK_RAW;
+#else
+ domain = PF_INET;
+ stype = SOCK_PACKET;
+#endif
+
+ if ((fd = socket(domain, stype, htons(type))) < 0) {
+ /* Give a more helpful message for the common error case */
+ if (errno == EPERM) {
+ rp_fatal("Cannot create raw socket -- pppoe must be run as root.");
+ }
+ fatalSys("socket");
+ }
+
+ if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &optval, sizeof(optval)) < 0) {
+ fatalSys("setsockopt");
+ }
+
+ /* Fill in hardware address */
+ if (hwaddr) {
+ strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+ if (ioctl(fd, SIOCGIFHWADDR, &ifr) < 0) {
+ fatalSys("ioctl(SIOCGIFHWADDR)");
+ }
+ memcpy(hwaddr, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
+#ifdef ARPHRD_ETHER
+ if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) {
+ char buffer[256];
+ sprintf(buffer, "Interface %.16s is not Ethernet", ifname);
+ rp_fatal(buffer);
+ }
+#endif
+ if (NOT_UNICAST(hwaddr)) {
+ char buffer[256];
+ sprintf(buffer,
+ "Interface %.16s has broadcast/multicast MAC address??",
+ ifname);
+ rp_fatal(buffer);
+ }
+ }
+
+ /* Sanity check on MTU */
+ strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+ if (ioctl(fd, SIOCGIFMTU, &ifr) < 0) {
+ fatalSys("ioctl(SIOCGIFMTU)");
+ }
+ if (ifr.ifr_mtu < ETH_DATA_LEN) {
+ char buffer[256];
+ sprintf(buffer, "Interface %.16s has MTU of %d -- should be %d. You may have serious connection problems.",
+ ifname, ifr.ifr_mtu, ETH_DATA_LEN);
+ printErr(buffer);
+ }
+
+#ifdef HAVE_STRUCT_SOCKADDR_LL
+ /* Get interface index */
+ sa.sll_family = AF_PACKET;
+ sa.sll_protocol = htons(type);
+
+ strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+ if (ioctl(fd, SIOCGIFINDEX, &ifr) < 0) {
+ fatalSys("ioctl(SIOCFIGINDEX): Could not get interface index");
+ }
+ sa.sll_ifindex = ifr.ifr_ifindex;
+
+#else
+ strcpy(sa.sa_data, ifname);
+#endif
+
+ /* We're only interested in packets on specified interface */
+ if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) < 0) {
+ fatalSys("bind");
+ }
+
+ return fd;
+}
+
+#endif /* USE_LINUX */
+
+/***********************************************************************
+*%FUNCTION: sendPacket
+*%ARGUMENTS:
+* sock -- socket to send to
+* pkt -- the packet to transmit
+* size -- size of packet (in bytes)
+*%RETURNS:
+* 0 on success; -1 on failure
+*%DESCRIPTION:
+* Transmits a packet
+***********************************************************************/
+int
+sendPacket(PPPoEConnection *conn, int sock, PPPoEPacket *pkt, int size)
+{
+#if defined(USE_BPF)
+ if (write(sock, pkt, size) < 0) {
+ sysErr("write (sendPacket)");
+ return -1;
+ }
+#elif defined(HAVE_STRUCT_SOCKADDR_LL)
+ if (send(sock, pkt, size, 0) < 0) {
+ sysErr("send (sendPacket)");
+ return -1;
+ }
+#else
+#ifdef USE_DLPI
+
+#define ABS(x) ((x) < 0 ? -(x) : (x))
+
+ u_char addr[MAXDLADDR];
+ u_char phys[MAXDLADDR];
+ u_char sap[MAXDLADDR];
+ u_char xmitbuf[MAXDLBUF];
+ int data_size;
+
+ short tmp_sap;
+
+ tmp_sap = htons(pkt->ethHdr.h_proto);
+ data_size = size - sizeof(struct ethhdr);
+
+ memcpy((char *)phys, (char *)pkt->ethHdr.h_dest, ETHERADDRL);
+ memcpy((char *)sap, (char *)&tmp_sap, sizeof(ushort_t));
+ memcpy((char *)xmitbuf, (char *)pkt + sizeof(struct ethhdr), data_size);
+
+ if (dl_saplen > 0) { /* order is sap+phys */
+ (void) memcpy((char*)addr, (char*)&sap, dl_abssaplen);
+ (void) memcpy((char*)addr+dl_abssaplen, (char*)phys, ETHERADDRL);
+ } else { /* order is phys+sap */
+ (void) memcpy((char*)addr, (char*)phys, ETHERADDRL);
+ (void) memcpy((char*)addr+ETHERADDRL, (char*)&sap, dl_abssaplen);
+ }
+
+#ifdef DL_DEBUG
+ printf("%02x:%02x:%02x:%02x:%02x:%02x %02x:%02x\n",
+ addr[0],addr[1],addr[2],addr[3],addr[4],addr[5],
+ addr[6],addr[7]);
+#endif
+
+ dlunitdatareq(sock, addr, dl_addrlen, 0, 0, xmitbuf, data_size);
+
+
+
+#else
+ struct sockaddr sa;
+
+ if (!conn) {
+ rp_fatal("relay and server not supported on Linux 2.0 kernels");
+ }
+ strcpy(sa.sa_data, conn->ifName);
+ if (sendto(sock, pkt, size, 0, &sa, sizeof(sa)) < 0) {
+ sysErr("sendto (sendPacket)");
+ return -1;
+ }
+#endif
+#endif
+ return 0;
+}
+
+#ifdef USE_BPF
+/***********************************************************************
+*%FUNCTION: clearPacketHeader
+*%ARGUMENTS:
+* pkt -- packet that needs its head clearing
+*%RETURNS:
+* nothing
+*%DESCRIPTION:
+* Clears a PPPoE packet header after a truncated packet has been
+* received. Insures that the packet will fail any integrity tests
+* and will be discarded by upper level routines. Also resets the
+* bpfSize and bpfOffset variables to force a new read on the next
+* call to receivePacket().
+***********************************************************************/
+void
+clearPacketHeader(PPPoEPacket *pkt)
+{
+ bpfSize = bpfOffset = 0;
+ memset(pkt, 0, HDR_SIZE);
+}
+#endif
+
+/***********************************************************************
+*%FUNCTION: receivePacket
+*%ARGUMENTS:
+* sock -- socket to read from
+* pkt -- place to store the received packet
+* size -- set to size of packet in bytes
+*%RETURNS:
+* >= 0 if all OK; < 0 if error
+*%DESCRIPTION:
+* Receives a packet
+***********************************************************************/
+int
+receivePacket(int sock, PPPoEPacket *pkt, int *size)
+{
+#ifdef USE_BPF
+ struct bpf_hdr hdr;
+ int seglen, copylen;
+
+ if (bpfSize <= 0) {
+ bpfOffset = 0;
+ if ((bpfSize = read(sock, bpfBuffer, bpfLength)) < 0) {
+ sysErr("read (receivePacket)");
+ return -1;
+ }
+ }
+ if (bpfSize < sizeof(hdr)) {
+ syslog(LOG_ERR, "Truncated bpf packet header: len=%d", bpfSize);
+ clearPacketHeader(pkt); /* resets bpfSize and bpfOffset */
+ return 0;
+ }
+ memcpy(&hdr, bpfBuffer + bpfOffset, sizeof(hdr));
+ if (hdr.bh_caplen != hdr.bh_datalen) {
+ syslog(LOG_ERR, "Truncated bpf packet: caplen=%d, datalen=%d",
+ hdr.bh_caplen, hdr.bh_datalen);
+ clearPacketHeader(pkt); /* resets bpfSize and bpfOffset */
+ return 0;
+ }
+ seglen = hdr.bh_hdrlen + hdr.bh_caplen;
+ if (seglen > bpfSize) {
+ syslog(LOG_ERR, "Truncated bpf packet: seglen=%d, bpfSize=%d",
+ seglen, bpfSize);
+ clearPacketHeader(pkt); /* resets bpfSize and bpfOffset */
+ return 0;
+ }
+ seglen = BPF_WORDALIGN(seglen);
+ *size = copylen = ((hdr.bh_caplen < sizeof(PPPoEPacket)) ?
+ hdr.bh_caplen : sizeof(PPPoEPacket));
+ memcpy(pkt, bpfBuffer + bpfOffset + hdr.bh_hdrlen, copylen);
+ if (seglen >= bpfSize) {
+ bpfSize = bpfOffset = 0;
+ } else {
+ bpfSize -= seglen;
+ bpfOffset += seglen;
+ }
+#else
+#ifdef USE_DLPI
+ struct strbuf data;
+ int flags = 0;
+ int retval;
+
+ data.buf = (char *) pkt;
+ data.maxlen = MAXDLBUF;
+ data.len = 0;
+
+ if ((retval = getmsg(sock, NULL, &data, &flags)) < 0) {
+ sysErr("read (receivePacket)");
+ return -1;
+ }
+
+ *size = data.len;
+
+#else
+ if ((*size = recv(sock, pkt, sizeof(PPPoEPacket), 0)) < 0) {
+ sysErr("recv (receivePacket)");
+ return -1;
+ }
+#endif
+#endif
+ return 0;
+}
+
+#ifdef USE_DLPI
+/**********************************************************************
+*%FUNCTION: openInterface
+*%ARGUMENTS:
+* ifname -- name of interface
+* type -- Ethernet frame type
+* hwaddr -- if non-NULL, set to the hardware address
+*%RETURNS:
+* A raw socket for talking to the Ethernet card. Exits on error.
+*%DESCRIPTION:
+* Opens a raw Ethernet socket
+***********************************************************************/
+int
+openInterface(char const *ifname, UINT16_t type, unsigned char *hwaddr)
+{
+ int fd;
+ long buf[MAXDLBUF];
+
+ union DL_primitives *dlp;
+
+ char base_dev[PATH_MAX];
+ int ppa;
+
+ if(strlen(ifname) > PATH_MAX) {
+ rp_fatal("socket: string to long");
+ }
+
+ ppa = atoi(&ifname[strlen(ifname)-1]);
+ strncpy(base_dev, ifname, PATH_MAX);
+ base_dev[strlen(base_dev)-1] = '\0';
+
+ if (( fd = open(base_dev, O_RDWR)) < 0) {
+ /* Give a more helpful message for the common error case */
+ if (errno == EPERM) {
+ rp_fatal("Cannot create raw socket -- pppoe must be run as root.");
+ }
+ fatalSys("socket");
+ }
+
+ dlinforeq(fd);
+ dlinfoack(fd, (char *)buf);
+
+ dlp = (union DL_primitives*) buf;
+
+ dl_abssaplen = ABS(dlp->info_ack.dl_sap_length);
+ dl_saplen = dlp->info_ack.dl_sap_length;
+ if (ETHERADDRL != (dlp->info_ack.dl_addr_length - dl_abssaplen))
+ fatalSys("invalid destination physical address length");
+ dl_addrlen = dl_abssaplen + ETHERADDRL;
+
+ dlattachreq(fd, ppa);
+ dlokack(fd, (char *)buf);
+
+ dlbindreq(fd, type, 0, DL_CLDLS, 0, 0);
+ dlbindack(fd, (char *)buf);
+
+ if ( strioctl(fd, DLIOCRAW, -1, 0, NULL) < 0 ) {
+ fatalSys("DLIOCRAW");
+ }
+
+ if (ioctl(fd, I_FLUSH, FLUSHR) < 0) fatalSys("I_FLUSH");
+
+ return fd;
+}
+
+/* cloned from dlcommon.c */
+
+void dlpromisconreq(int fd, u_long level)
+{
+ dl_promiscon_req_t promiscon_req;
+ struct strbuf ctl;
+ int flags;
+
+ promiscon_req.dl_primitive = DL_PROMISCON_REQ;
+ promiscon_req.dl_level = level;
+
+ ctl.maxlen = 0;
+ ctl.len = sizeof (promiscon_req);
+ ctl.buf = (char *) &promiscon_req;
+
+ flags = 0;
+
+ if (putmsg(fd, &ctl, (struct strbuf*) NULL, flags) < 0)
+ fatalSys("dlpromiscon: putmsg");
+
+}
+
+void dlinforeq(int fd)
+{
+ dl_info_req_t info_req;
+ struct strbuf ctl;
+ int flags;
+
+ info_req.dl_primitive = DL_INFO_REQ;
+
+ ctl.maxlen = 0;
+ ctl.len = sizeof (info_req);
+ ctl.buf = (char *) &info_req;
+
+ flags = RS_HIPRI;
+
+ if (putmsg(fd, &ctl, (struct strbuf*) NULL, flags) < 0)
+ fatalSys("dlinforeq: putmsg");
+}
+
+void dlunitdatareq(int fd, u_char *addrp, int addrlen, u_long minpri, u_long maxpri, u_char *datap, int datalen)
+{
+ long buf[MAXDLBUF];
+ union DL_primitives *dlp;
+ struct strbuf data, ctl;
+
+ dlp = (union DL_primitives*) buf;
+
+ dlp->unitdata_req.dl_primitive = DL_UNITDATA_REQ;
+ dlp->unitdata_req.dl_dest_addr_length = addrlen;
+ dlp->unitdata_req.dl_dest_addr_offset = sizeof (dl_unitdata_req_t);
+ dlp->unitdata_req.dl_priority.dl_min = minpri;
+ dlp->unitdata_req.dl_priority.dl_max = maxpri;
+
+ (void) memcpy(OFFADDR(dlp, sizeof (dl_unitdata_req_t)), addrp, addrlen);
+
+ ctl.maxlen = 0;
+ ctl.len = sizeof (dl_unitdata_req_t) + addrlen;
+ ctl.buf = (char *) buf;
+
+ data.maxlen = 0;
+ data.len = datalen;
+ data.buf = (char *) datap;
+
+ if (putmsg(fd, &ctl, &data, 0) < 0)
+ fatalSys("dlunitdatareq: putmsg");
+}
+
+void dlinfoack(int fd, char *bufp)
+{
+ union DL_primitives *dlp;
+ struct strbuf ctl;
+ int flags;
+
+ ctl.maxlen = MAXDLBUF;
+ ctl.len = 0;
+ ctl.buf = bufp;
+
+ strgetmsg(fd, &ctl, (struct strbuf*)NULL, &flags, "dlinfoack");
+
+ dlp = (union DL_primitives *) ctl.buf;
+
+ expecting(DL_INFO_ACK, dlp);
+
+ if (ctl.len < sizeof (dl_info_ack_t)) {
+ char buffer[256];
+ sprintf(buffer, "dlinfoack: response ctl.len too short: %d", ctl.len);
+ rp_fatal(buffer);
+ }
+
+ if (flags != RS_HIPRI)
+ rp_fatal("dlinfoack: DL_INFO_ACK was not M_PCPROTO");
+
+ if (ctl.len < sizeof (dl_info_ack_t)) {
+ char buffer[256];
+ sprintf(buffer, "dlinfoack: short response ctl.len: %d", ctl.len);
+ rp_fatal(buffer);
+ }
+}
+
+void dlbindreq(int fd, u_long sap, u_long max_conind, u_long service_mode, u_long conn_mgmt, u_long xidtest)
+{
+ dl_bind_req_t bind_req;
+ struct strbuf ctl;
+ int flags;
+
+ bind_req.dl_primitive = DL_BIND_REQ;
+ bind_req.dl_sap = sap;
+ bind_req.dl_max_conind = max_conind;
+ bind_req.dl_service_mode = service_mode;
+ bind_req.dl_conn_mgmt = conn_mgmt;
+ bind_req.dl_xidtest_flg = xidtest;
+
+ ctl.maxlen = 0;
+ ctl.len = sizeof (bind_req);
+ ctl.buf = (char *) &bind_req;
+
+ flags = 0;
+
+ if (putmsg(fd, &ctl, (struct strbuf*) NULL, flags) < 0)
+ fatalSys("dlbindreq: putmsg");
+}
+
+void dlattachreq(int fd, u_long ppa)
+{
+ dl_attach_req_t attach_req;
+ struct strbuf ctl;
+ int flags;
+
+ attach_req.dl_primitive = DL_ATTACH_REQ;
+ attach_req.dl_ppa = ppa;
+
+ ctl.maxlen = 0;
+ ctl.len = sizeof (attach_req);
+ ctl.buf = (char *) &attach_req;
+
+ flags = 0;
+
+ if (putmsg(fd, &ctl, (struct strbuf*) NULL, flags) < 0)
+ fatalSys("dlattachreq: putmsg");
+}
+
+void dlokack(int fd, char *bufp)
+{
+ union DL_primitives *dlp;
+ struct strbuf ctl;
+ int flags;
+
+ ctl.maxlen = MAXDLBUF;
+ ctl.len = 0;
+ ctl.buf = bufp;
+
+ strgetmsg(fd, &ctl, (struct strbuf*)NULL, &flags, "dlokack");
+
+ dlp = (union DL_primitives *) ctl.buf;
+
+ expecting(DL_OK_ACK, dlp);
+
+ if (ctl.len < sizeof (dl_ok_ack_t)) {
+ char buffer[256];
+ sprintf(buffer, "dlokack: response ctl.len too short: %d", ctl.len);
+ rp_fatal(buffer);
+ }
+
+ if (flags != RS_HIPRI)
+ rp_fatal("dlokack: DL_OK_ACK was not M_PCPROTO");
+
+ if (ctl.len < sizeof (dl_ok_ack_t)) {
+ char buffer[256];
+ sprintf(buffer, "dlokack: short response ctl.len: %d", ctl.len);
+ rp_fatal(buffer);
+ }
+}
+
+void dlbindack(int fd, char *bufp)
+{
+ union DL_primitives *dlp;
+ struct strbuf ctl;
+ int flags;
+
+ ctl.maxlen = MAXDLBUF;
+ ctl.len = 0;
+ ctl.buf = bufp;
+
+ strgetmsg(fd, &ctl, (struct strbuf*)NULL, &flags, "dlbindack");
+
+ dlp = (union DL_primitives *) ctl.buf;
+
+ expecting(DL_BIND_ACK, dlp);
+
+ if (flags != RS_HIPRI)
+ rp_fatal("dlbindack: DL_OK_ACK was not M_PCPROTO");
+
+ if (ctl.len < sizeof (dl_bind_ack_t)) {
+ char buffer[256];
+ sprintf(buffer, "dlbindack: short response ctl.len: %d", ctl.len);
+ rp_fatal(buffer);
+ }
+}
+
+int strioctl(int fd, int cmd, int timout, int len, char *dp)
+{
+ struct strioctl sioc;
+ int rc;
+
+ sioc.ic_cmd = cmd;
+ sioc.ic_timout = timout;
+ sioc.ic_len = len;
+ sioc.ic_dp = dp;
+ rc = ioctl(fd, I_STR, &sioc);
+
+ if (rc < 0)
+ return (rc);
+ else
+ return (sioc.ic_len);
+}
+
+void strgetmsg(int fd, struct strbuf *ctlp, struct strbuf *datap, int *flagsp, char *caller)
+{
+ int rc;
+ static char errmsg[80];
+
+ /*
+ * Start timer.
+ */
+ (void) signal(SIGALRM, sigalrm);
+ if (alarm(MAXWAIT) < 0) {
+ (void) sprintf(errmsg, "%s: alarm", caller);
+ fatalSys(errmsg);
+ }
+
+ /*
+ * Set flags argument and issue getmsg().
+ */
+ *flagsp = 0;
+ if ((rc = getmsg(fd, ctlp, datap, flagsp)) < 0) {
+ (void) sprintf(errmsg, "%s: getmsg", caller);
+ fatalSys(errmsg);
+ }
+
+ /*
+ * Stop timer.
+ */
+ if (alarm(0) < 0) {
+ (void) sprintf(errmsg, "%s: alarm", caller);
+ fatalSys(errmsg);
+ }
+
+ /*
+ * Check for MOREDATA and/or MORECTL.
+ */
+ if ((rc & (MORECTL | MOREDATA)) == (MORECTL | MOREDATA)) {
+ char buffer[256];
+ sprintf(buffer, "%s: MORECTL|MOREDATA", caller);
+ rp_fatal(buffer);
+ }
+
+ if (rc & MORECTL) {
+ char buffer[256];
+ sprintf(buffer, "%s: MORECTL", caller);
+ rp_fatal(buffer);
+ }
+
+ if (rc & MOREDATA) {
+ char buffer[256];
+ sprintf(buffer, "%s: MOREDATA", caller);
+ rp_fatal(buffer);
+ }
+
+ /*
+ * Check for at least sizeof (long) control data portion.
+ */
+ if (ctlp->len < sizeof (long)) {
+ char buffer[256];
+ sprintf(buffer, "getmsg: control portion length < sizeof (long): %d", ctlp->len);
+ rp_fatal(buffer);
+ }
+}
+
+void sigalrm(int sig)
+{
+ (void) rp_fatal("sigalrm: TIMEOUT");
+}
+
+void expecting(int prim, union DL_primitives *dlp)
+{
+ if (dlp->dl_primitive != (u_long)prim) {
+ char buffer[256];
+ sprintf(buffer, "expected %s got %s", dlprim(prim), dlprim(dlp->dl_primitive));
+ rp_fatal(buffer);
+ exit(1);
+ }
+}
+
+char *dlprim(u_long prim)
+{
+ static char primbuf[80];
+
+ switch ((int)prim) {
+ CASERET(DL_INFO_REQ);
+ CASERET(DL_INFO_ACK);
+ CASERET(DL_ATTACH_REQ);
+ CASERET(DL_DETACH_REQ);
+ CASERET(DL_BIND_REQ);
+ CASERET(DL_BIND_ACK);
+ CASERET(DL_UNBIND_REQ);
+ CASERET(DL_OK_ACK);
+ CASERET(DL_ERROR_ACK);
+ CASERET(DL_SUBS_BIND_REQ);
+ CASERET(DL_SUBS_BIND_ACK);
+ CASERET(DL_UNITDATA_REQ);
+ CASERET(DL_UNITDATA_IND);
+ CASERET(DL_UDERROR_IND);
+ CASERET(DL_UDQOS_REQ);
+ CASERET(DL_CONNECT_REQ);
+ CASERET(DL_CONNECT_IND);
+ CASERET(DL_CONNECT_RES);
+ CASERET(DL_CONNECT_CON);
+ CASERET(DL_TOKEN_REQ);
+ CASERET(DL_TOKEN_ACK);
+ CASERET(DL_DISCONNECT_REQ);
+ CASERET(DL_DISCONNECT_IND);
+ CASERET(DL_RESET_REQ);
+ CASERET(DL_RESET_IND);
+ CASERET(DL_RESET_RES);
+ CASERET(DL_RESET_CON);
+ default:
+ (void) sprintf(primbuf, "unknown primitive 0x%lx", prim);
+ return (primbuf);
+ }
+}
+
+#endif /* USE_DLPI */
diff --git a/mdk-stage1/rp-pppoe/src/install-sh b/mdk-stage1/rp-pppoe/src/install-sh
new file mode 100755
index 000000000..58719246f
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/src/install-sh
@@ -0,0 +1,238 @@
+#! /bin/sh
+#
+# install - install a program, script, or datafile
+# This comes from X11R5.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# `make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch.
+#
+
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit="${DOITPROG-}"
+
+
+# put in absolute paths if you don't have them in your path; or use env. vars.
+
+mvprog="${MVPROG-mv}"
+cpprog="${CPPROG-cp}"
+chmodprog="${CHMODPROG-chmod}"
+chownprog="${CHOWNPROG-chown}"
+chgrpprog="${CHGRPPROG-chgrp}"
+stripprog="${STRIPPROG-strip}"
+rmprog="${RMPROG-rm}"
+mkdirprog="${MKDIRPROG-mkdir}"
+
+transformbasename=""
+transform_arg=""
+instcmd="$mvprog"
+chmodcmd="$chmodprog 0755"
+chowncmd=""
+chgrpcmd=""
+stripcmd=""
+rmcmd="$rmprog -f"
+mvcmd="$mvprog"
+src=""
+dst=""
+dir_arg=""
+
+while [ x"$1" != x ]; do
+ case $1 in
+ -c) instcmd="$cpprog"
+ shift
+ continue;;
+
+ -d) dir_arg=true
+ shift
+ continue;;
+
+ -m) chmodcmd="$chmodprog $2"
+ shift
+ shift
+ continue;;
+
+ -o) chowncmd="$chownprog $2"
+ shift
+ shift
+ continue;;
+
+ -g) chgrpcmd="$chgrpprog $2"
+ shift
+ shift
+ continue;;
+
+ -s) stripcmd="$stripprog"
+ shift
+ continue;;
+
+ -t=*) transformarg=`echo $1 | sed 's/-t=//'`
+ shift
+ continue;;
+
+ -b=*) transformbasename=`echo $1 | sed 's/-b=//'`
+ shift
+ continue;;
+
+ *) if [ x"$src" = x ]
+ then
+ src=$1
+ else
+ # this colon is to work around a 386BSD /bin/sh bug
+ :
+ dst=$1
+ fi
+ shift
+ continue;;
+ esac
+done
+
+if [ x"$src" = x ]
+then
+ echo "install: no input file specified"
+ exit 1
+else
+ true
+fi
+
+if [ x"$dir_arg" != x ]; then
+ dst=$src
+ src=""
+
+ if [ -d $dst ]; then
+ instcmd=:
+ else
+ instcmd=mkdir
+ fi
+else
+
+# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
+# might cause directories to be created, which would be especially bad
+# if $src (and thus $dsttmp) contains '*'.
+
+ if [ -f $src -o -d $src ]
+ then
+ true
+ else
+ echo "install: $src does not exist"
+ exit 1
+ fi
+
+ if [ x"$dst" = x ]
+ then
+ echo "install: no destination specified"
+ exit 1
+ else
+ true
+ fi
+
+# If destination is a directory, append the input filename; if your system
+# does not like double slashes in filenames, you may need to add some logic
+
+ if [ -d $dst ]
+ then
+ dst="$dst"/`basename $src`
+ else
+ true
+ fi
+fi
+
+## this sed command emulates the dirname command
+dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
+
+# Make sure that the destination directory exists.
+# this part is taken from Noah Friedman's mkinstalldirs script
+
+# Skip lots of stat calls in the usual case.
+if [ ! -d "$dstdir" ]; then
+defaultIFS='
+'
+IFS="${IFS-${defaultIFS}}"
+
+oIFS="${IFS}"
+# Some sh's can't handle IFS=/ for some reason.
+IFS='%'
+set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
+IFS="${oIFS}"
+
+pathcomp=''
+
+while [ $# -ne 0 ] ; do
+ pathcomp="${pathcomp}${1}"
+ shift
+
+ if [ ! -d "${pathcomp}" ] ;
+ then
+ $mkdirprog "${pathcomp}"
+ else
+ true
+ fi
+
+ pathcomp="${pathcomp}/"
+done
+fi
+
+if [ x"$dir_arg" != x ]
+then
+ $doit $instcmd $dst &&
+
+ if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
+ if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
+ if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
+ if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
+else
+
+# If we're going to rename the final executable, determine the name now.
+
+ if [ x"$transformarg" = x ]
+ then
+ dstfile=`basename $dst`
+ else
+ dstfile=`basename $dst $transformbasename |
+ sed $transformarg`$transformbasename
+ fi
+
+# don't allow the sed command to completely eliminate the filename
+
+ if [ x"$dstfile" = x ]
+ then
+ dstfile=`basename $dst`
+ else
+ true
+ fi
+
+# Make a temp file name in the proper directory.
+
+ dsttmp=$dstdir/#inst.$$#
+
+# Move or copy the file name to the temp name
+
+ $doit $instcmd $src $dsttmp &&
+
+ trap "rm -f ${dsttmp}" 0 &&
+
+# and set any options; do chmod last to preserve setuid bits
+
+# If any of these fail, we abort the whole thing. If we want to
+# ignore errors from any of these, just make sure not to ignore
+# errors from the above "$doit $instcmd $src $dsttmp" command.
+
+ if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
+ if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
+ if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
+ if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
+
+# Now rename the file to the real destination.
+
+ $doit $rmcmd -f $dstdir/$dstfile &&
+ $doit $mvcmd $dsttmp $dstdir/$dstfile
+
+fi &&
+
+
+exit 0
diff --git a/mdk-stage1/rp-pppoe/src/md5.c b/mdk-stage1/rp-pppoe/src/md5.c
new file mode 100644
index 000000000..5b7a0d7b2
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/src/md5.c
@@ -0,0 +1,246 @@
+/*
+ * This code implements the MD5 message-digest algorithm.
+ * The algorithm is due to Ron Rivest. This code was
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ *
+ * To compute the message digest of a chunk of bytes, declare an
+ * MD5Context structure, pass it to MD5Init, call MD5Update as
+ * needed on buffers full of bytes, and then call MD5Final, which
+ * will fill a supplied 16-byte array with the digest.
+ */
+#include <string.h> /* for memcpy() */
+#include "md5.h"
+
+void byteReverse(unsigned char *buf, unsigned longs);
+
+/*
+ * Note: this code is harmless on little-endian machines.
+ */
+void byteReverse(unsigned char *buf, unsigned longs)
+{
+ uint32 t;
+ do {
+ t = (uint32) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
+ ((unsigned) buf[1] << 8 | buf[0]);
+ *(uint32 *) buf = t;
+ buf += 4;
+ } while (--longs);
+}
+
+/*
+ * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
+ * initialization constants.
+ */
+void MD5Init(struct MD5Context *ctx)
+{
+ ctx->buf[0] = 0x67452301;
+ ctx->buf[1] = 0xefcdab89;
+ ctx->buf[2] = 0x98badcfe;
+ ctx->buf[3] = 0x10325476;
+
+ ctx->bits[0] = 0;
+ ctx->bits[1] = 0;
+}
+
+/*
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ */
+void MD5Update(struct MD5Context *ctx, unsigned char const *buf, unsigned len)
+{
+ uint32 t;
+
+ /* Update bitcount */
+
+ t = ctx->bits[0];
+ if ((ctx->bits[0] = t + ((uint32) len << 3)) < t)
+ ctx->bits[1]++; /* Carry from low to high */
+ ctx->bits[1] += len >> 29;
+
+ t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */
+
+ /* Handle any leading odd-sized chunks */
+
+ if (t) {
+ unsigned char *p = (unsigned char *) ctx->in + t;
+
+ t = 64 - t;
+ if (len < t) {
+ memcpy(p, buf, len);
+ return;
+ }
+ memcpy(p, buf, t);
+ byteReverse(ctx->in, 16);
+ MD5Transform(ctx->buf, (uint32 *) ctx->in);
+ buf += t;
+ len -= t;
+ }
+ /* Process data in 64-byte chunks */
+
+ while (len >= 64) {
+ memcpy(ctx->in, buf, 64);
+ byteReverse(ctx->in, 16);
+ MD5Transform(ctx->buf, (uint32 *) ctx->in);
+ buf += 64;
+ len -= 64;
+ }
+
+ /* Handle any remaining bytes of data. */
+
+ memcpy(ctx->in, buf, len);
+}
+
+/*
+ * Final wrapup - pad to 64-byte boundary with the bit pattern
+ * 1 0* (64-bit count of bits processed, MSB-first)
+ */
+void MD5Final(unsigned char digest[16], struct MD5Context *ctx)
+{
+ unsigned count;
+ unsigned char *p;
+
+ /* Compute number of bytes mod 64 */
+ count = (ctx->bits[0] >> 3) & 0x3F;
+
+ /* Set the first char of padding to 0x80. This is safe since there is
+ always at least one byte free */
+ p = ctx->in + count;
+ *p++ = 0x80;
+
+ /* Bytes of padding needed to make 64 bytes */
+ count = 64 - 1 - count;
+
+ /* Pad out to 56 mod 64 */
+ if (count < 8) {
+ /* Two lots of padding: Pad the first block to 64 bytes */
+ memset(p, 0, count);
+ byteReverse(ctx->in, 16);
+ MD5Transform(ctx->buf, (uint32 *) ctx->in);
+
+ /* Now fill the next block with 56 bytes */
+ memset(ctx->in, 0, 56);
+ } else {
+ /* Pad block to 56 bytes */
+ memset(p, 0, count - 8);
+ }
+ byteReverse(ctx->in, 14);
+
+ /* Append length in bits and transform */
+ ((uint32 *) ctx->in)[14] = ctx->bits[0];
+ ((uint32 *) ctx->in)[15] = ctx->bits[1];
+
+ MD5Transform(ctx->buf, (uint32 *) ctx->in);
+ byteReverse((unsigned char *) ctx->buf, 4);
+ memcpy(digest, ctx->buf, 16);
+ memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */
+}
+
+#ifndef ASM_MD5
+
+/* The four core functions - F1 is optimized somewhat */
+
+/* #define F1(x, y, z) (x & y | ~x & z) */
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+#define F2(x, y, z) F1(z, x, y)
+#define F3(x, y, z) (x ^ y ^ z)
+#define F4(x, y, z) (y ^ (x | ~z))
+
+/* This is the central step in the MD5 algorithm. */
+#define MD5STEP(f, w, x, y, z, data, s) \
+ ( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x )
+
+/*
+ * The core of the MD5 algorithm, this alters an existing MD5 hash to
+ * reflect the addition of 16 longwords of new data. MD5Update blocks
+ * the data and converts bytes into longwords for this routine.
+ */
+void MD5Transform(uint32 buf[4], uint32 const in[16])
+{
+ register uint32 a, b, c, d;
+
+ a = buf[0];
+ b = buf[1];
+ c = buf[2];
+ d = buf[3];
+
+ MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
+ MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
+ MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
+ MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
+ MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
+ MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
+ MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
+ MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
+ MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
+ MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
+ MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
+ MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
+ MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
+ MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
+ MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
+ MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
+
+ MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
+ MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
+ MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
+ MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
+ MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
+ MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
+ MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
+ MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
+ MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
+ MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
+ MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
+ MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
+ MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
+ MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
+ MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
+ MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
+
+ MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
+ MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
+ MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
+ MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
+ MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
+ MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
+ MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
+ MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
+ MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
+ MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
+ MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
+ MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
+ MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
+ MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
+ MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
+ MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
+
+ MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
+ MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
+ MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
+ MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
+ MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
+ MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
+ MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
+ MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
+ MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
+ MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
+ MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
+ MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
+ MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
+ MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
+ MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
+ MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
+
+ buf[0] += a;
+ buf[1] += b;
+ buf[2] += c;
+ buf[3] += d;
+}
+
+#endif
diff --git a/mdk-stage1/rp-pppoe/src/md5.h b/mdk-stage1/rp-pppoe/src/md5.h
new file mode 100644
index 000000000..e264f686d
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/src/md5.h
@@ -0,0 +1,27 @@
+#ifndef MD5_H
+#define MD5_H
+
+#ifdef __alpha
+typedef unsigned int uint32;
+#else
+typedef unsigned long uint32;
+#endif
+
+struct MD5Context {
+ uint32 buf[4];
+ uint32 bits[2];
+ unsigned char in[64];
+};
+
+void MD5Init(struct MD5Context *context);
+void MD5Update(struct MD5Context *context, unsigned char const *buf,
+ unsigned len);
+void MD5Final(unsigned char digest[16], struct MD5Context *context);
+void MD5Transform(uint32 buf[4], uint32 const in[16]);
+
+/*
+ * This is needed to make RSAREF happy on some MS-DOS compilers.
+ */
+typedef struct MD5Context MD5_CTX;
+
+#endif /* !MD5_H */
diff --git a/mdk-stage1/rp-pppoe/src/plugin.c b/mdk-stage1/rp-pppoe/src/plugin.c
new file mode 100644
index 000000000..aefa0ca6f
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/src/plugin.c
@@ -0,0 +1,397 @@
+/***********************************************************************
+*
+* plugin.c
+*
+* pppd plugin for kernel-mode PPPoE on Linux
+*
+* Copyright (C) 2001 by Roaring Penguin Software Inc., Michal Ostrowski
+* and Jamal Hadi Salim.
+*
+* Much code and many ideas derived from pppoe plugin by Michal
+* Ostrowski and Jamal Hadi Salim, which carries this copyright:
+*
+* Copyright 2000 Michal Ostrowski <mostrows@styx.uwaterloo.ca>,
+* Jamal Hadi Salim <hadi@cyberus.ca>
+* Borrows heavily from the PPPoATM plugin by Mitchell Blank Jr.,
+* which is based in part on work from Jens Axboe and Paul Mackerras.
+*
+* 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.
+***********************************************************************/
+
+static char const RCSID[] =
+"$Id: plugin.c 195724 2001-06-11 13:49:39Z gc $";
+
+#define _GNU_SOURCE 1
+#include "pppoe.h"
+
+#include "pppd/pppd.h"
+#include "pppd/fsm.h"
+#include "pppd/lcp.h"
+#include "pppd/ipcp.h"
+#include "pppd/ccp.h"
+#include "pppd/pathnames.h"
+
+#include <linux/types.h>
+#include <syslog.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <net/ethernet.h>
+#include <net/if_arp.h>
+#include <linux/if_pppox.h>
+
+/* From sys-linux.c in pppd -- MUST FIX THIS! */
+extern int new_style_driver;
+
+static char *service = NULL;
+static char *acName = NULL;
+static char *existingSession = NULL;
+
+static option_t Options[] = {
+ { "rp_pppoe_service", o_string, &service,
+ "Desired PPPoE service name" },
+ { "rp_pppoe_ac", o_string, &acName,
+ "Desired PPPoE access concentrator name" },
+ { "rp_pppoe_sess", o_string, &existingSession,
+ "Attach to existing session (sessid:macaddr)" },
+ { NULL }
+};
+int (*OldDevnameHook)(const char *name) = NULL;
+static PPPoEConnection *conn = NULL;
+
+/**********************************************************************
+ * %FUNCTION: PPPOEInitDevice
+ * %ARGUMENTS:
+ * None
+ * %RETURNS:
+ *
+ * %DESCRIPTION:
+ * Initializes PPPoE device.
+ ***********************************************************************/
+static int
+PPPOEInitDevice(void)
+{
+ conn = malloc(sizeof(PPPoEConnection));
+ if (!conn) {
+ fatal("Could not allocate memory for PPPoE session");
+ }
+ memset(conn, 0, sizeof(PPPoEConnection));
+ if (acName) {
+ SET_STRING(conn->acName, acName);
+ }
+ if (service) {
+ SET_STRING(conn->serviceName, acName);
+ }
+ SET_STRING(conn->ifName, devnam);
+ conn->discoverySocket = -1;
+ conn->sessionSocket = -1;
+ conn->useHostUniq = 1;
+ return 1;
+}
+
+/**********************************************************************
+ * %FUNCTION: PPPOEConnectDevice
+ * %ARGUMENTS:
+ * None
+ * %RETURNS:
+ * Non-negative if all goes well; -1 otherwise
+ * %DESCRIPTION:
+ * Connects PPPoE device.
+ ***********************************************************************/
+static int
+PPPOEConnectDevice(void)
+{
+ struct sockaddr_pppox sp;
+
+ strlcpy(ppp_devnam, devnam, sizeof(ppp_devnam));
+ if (existingSession) {
+ unsigned int mac[ETH_ALEN];
+ int i, ses;
+ if (sscanf(existingSession, "%d:%x:%x:%x:%x:%x:%x",
+ &ses, &mac[0], &mac[1], &mac[2],
+ &mac[3], &mac[4], &mac[5]) != 7) {
+ fatal("Illegal value for rp_pppoe_sess option");
+ }
+ conn->session = htons(ses);
+ for (i=0; i<ETH_ALEN; i++) {
+ conn->peerEth[i] = (unsigned char) mac[i];
+ }
+ } else {
+ discovery(conn);
+ if (conn->discoveryState != STATE_SESSION) {
+ fatal("Unable to complete PPPoE Discovery");
+ }
+ }
+
+ /* Make the session socket */
+ conn->sessionSocket = socket(AF_PPPOX, SOCK_STREAM, PX_PROTO_OE);
+ if (conn->sessionSocket < 0) {
+ fatal("Failed to create PPPoE socket: %m");
+ }
+ sp.sa_family = AF_PPPOX;
+ sp.sa_protocol = PX_PROTO_OE;
+ sp.sa_addr.pppoe.sid = conn->session;
+ memcpy(sp.sa_addr.pppoe.dev, conn->ifName, IFNAMSIZ);
+ memcpy(sp.sa_addr.pppoe.remote, conn->peerEth, ETH_ALEN);
+ if (connect(conn->sessionSocket, (struct sockaddr *) &sp,
+ sizeof(struct sockaddr_pppox)) < 0) {
+ fatal("Failed to connect PPPoE socket: %d %m", errno);
+ return -1;
+ }
+ return conn->sessionSocket;
+}
+
+static void
+PPPOESendConfig(int unit,
+ int mtu,
+ u_int32_t asyncmap,
+ int pcomp,
+ int accomp)
+{
+ int sock;
+ struct ifreq ifr;
+
+ if (mtu > MAX_PPPOE_MTU) {
+ warn("Couldn't increase MTU to %d", mtu);
+ }
+ sock = socket(AF_INET, SOCK_DGRAM, 0);
+ if (sock < 0) {
+ fatal("Couldn't create IP socket: %m");
+ }
+ strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+ ifr.ifr_mtu = mtu;
+ if (ioctl(sock, SIOCSIFMTU, &ifr) < 0) {
+ fatal("ioctl(SIOCSIFMTU): %m");
+ }
+ (void) close (sock);
+}
+
+
+static void
+PPPOERecvConfig(int unit,
+ int mru,
+ u_int32_t asyncmap,
+ int pcomp,
+ int accomp)
+{
+ if (mru > MAX_PPPOE_MTU) {
+ error("Couldn't increase MRU to %d", mru);
+ }
+}
+
+static void
+PPPOESetXaccm(int unit,
+ ext_accm accm)
+{
+ /* Do nothing */
+}
+
+/**********************************************************************
+ * %FUNCTION: PPPOEDisconnectDevice
+ * %ARGUMENTS:
+ * None
+ * %RETURNS:
+ * Nothing
+ * %DESCRIPTION:
+ * Disconnects PPPoE device
+ ***********************************************************************/
+static void
+PPPOEDisconnectDevice(void)
+{
+ struct sockaddr_pppox sp;
+
+ sp.sa_family = AF_PPPOX;
+ sp.sa_protocol = PX_PROTO_OE;
+ sp.sa_addr.pppoe.sid = 0;
+ memcpy(sp.sa_addr.pppoe.dev, conn->ifName, IFNAMSIZ);
+ memcpy(sp.sa_addr.pppoe.remote, conn->peerEth, ETH_ALEN);
+ if (connect(conn->sessionSocket, (struct sockaddr *) &sp,
+ sizeof(struct sockaddr_pppox)) < 0) {
+ fatal("Failed to disconnect PPPoE socket: %d %m", errno);
+ return;
+ }
+ close(conn->sessionSocket);
+}
+
+static int
+PPPOESetSpeed(const char *speed)
+{
+ return 0;
+}
+
+static void
+PPPOEDeviceCheckHook(void)
+{
+ if (!options_for_dev(_PATH_ETHOPT, devnam)) {
+ exit(EXIT_OPTION_ERROR);
+ }
+}
+
+/**********************************************************************
+ * %FUNCTION: PPPoEDevnameHook
+ * %ARGUMENTS:
+ * name -- name of device
+ * %RETURNS:
+ * 1 if we will handle this device; 0 otherwise.
+ * %DESCRIPTION:
+ * Checks if name is a valid interface name; if so, returns 1. Also
+ * sets up devnam (string representation of device) and sets devstat.st_mode
+ * so S_ISCHR(devstat.st_mode) != 1 for internal pppd consumption.
+ ***********************************************************************/
+static int
+PPPoEDevnameHook(const char *name)
+{
+ int r = 1;
+ int fd;
+ struct ifreq ifr;
+
+ /* Open a socket */
+ if ((fd = socket(PF_PACKET, SOCK_RAW, 0)) < 0) {
+ r = 0;
+ }
+
+ /* Try getting interface index */
+ if (r) {
+ strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+ if (ioctl(fd, SIOCGIFINDEX, &ifr) < 0) {
+ r = 0;
+ } else {
+ if (ioctl(fd, SIOCGIFHWADDR, &ifr) < 0) {
+ r = 0;
+ } else {
+ if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) {
+ error("Interface %s not Ethernet", name);
+ r=0;
+ }
+ }
+ }
+ }
+
+ /* Close socket */
+ close(fd);
+ if (r) {
+ strncpy(devnam, name, sizeof(devnam));
+ if (device_check_hook != PPPOEDeviceCheckHook) {
+ devstat.st_mode = S_IFSOCK;
+ device_init_hook = PPPOEInitDevice;
+ setspeed_hook = PPPOESetSpeed;
+ device_check_hook = PPPOEDeviceCheckHook;
+ connect_device_hook = PPPOEConnectDevice;
+ disconnect_device_hook = PPPOEDisconnectDevice;
+ send_config_hook = PPPOESendConfig;
+ recv_config_hook = PPPOERecvConfig;
+ set_xaccm_hook = PPPOESetXaccm;
+ modem = 0;
+
+ lcp_allowoptions[0].neg_accompression = 0;
+ lcp_wantoptions[0].neg_accompression = 0;
+
+ lcp_allowoptions[0].neg_asyncmap = 0;
+ lcp_wantoptions[0].neg_asyncmap = 0;
+
+ lcp_allowoptions[0].neg_pcompression = 0;
+ lcp_wantoptions[0].neg_pcompression = 0;
+
+ ccp_allowoptions[0].deflate = 0 ;
+ ccp_wantoptions[0].deflate = 0 ;
+
+ ipcp_allowoptions[0].neg_vj=0;
+ ipcp_wantoptions[0].neg_vj=0;
+
+ ccp_allowoptions[0].bsd_compress = 0;
+ ccp_wantoptions[0].bsd_compress = 0;
+
+ PPPOEInitDevice();
+ }
+ return 1;
+ }
+
+ if (OldDevnameHook) r = OldDevnameHook(name);
+ return r;
+}
+
+/**********************************************************************
+ * %FUNCTION: plugin_init
+ * %ARGUMENTS:
+ * None
+ * %RETURNS:
+ * Nothing
+ * %DESCRIPTION:
+ * Initializes hooks for pppd plugin
+ ***********************************************************************/
+void
+plugin_init(void)
+{
+ if (!new_style_driver) {
+ fatal("Linux kernel does not support PPPoE -- are you running 2.4.x?");
+ }
+ OldDevnameHook = setdevname_hook;
+ setdevname_hook = PPPoEDevnameHook;
+ add_options(Options);
+
+ info("Roaring Penguin PPPoE Plugin Initialized");
+}
+
+/**********************************************************************
+*%FUNCTION: fatalSys
+*%ARGUMENTS:
+* str -- error message
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Prints a message plus the errno value to stderr and syslog and exits.
+***********************************************************************/
+void
+fatalSys(char const *str)
+{
+ char buf[1024];
+ int i = errno;
+ sprintf(buf, "%.256s: %.256s", str, strerror(i));
+ printErr(buf);
+ sprintf(buf, "RP-PPPoE: %.256s: %.256s", str, strerror(i));
+ sendPADT(conn, buf);
+ exit(1);
+}
+
+/**********************************************************************
+*%FUNCTION: rp_fatal
+*%ARGUMENTS:
+* str -- error message
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Prints a message to stderr and syslog and exits.
+***********************************************************************/
+void
+rp_fatal(char const *str)
+{
+ char buf[1024];
+ printErr(str);
+ sprintf(buf, "RP-PPPoE: %.256s", str);
+ sendPADT(conn, buf);
+ exit(1);
+}
+/**********************************************************************
+*%FUNCTION: sysErr
+*%ARGUMENTS:
+* str -- error message
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Prints a message plus the errno value to syslog.
+***********************************************************************/
+void
+sysErr(char const *str)
+{
+ rp_fatal(str);
+}
diff --git a/mdk-stage1/rp-pppoe/src/ppp.c b/mdk-stage1/rp-pppoe/src/ppp.c
new file mode 100644
index 000000000..ffd2c835e
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/src/ppp.c
@@ -0,0 +1,258 @@
+/***********************************************************************
+*
+* ppp.c
+*
+* Implementation of user-space PPPoE redirector for Linux.
+*
+* Functions for talking to PPP daemon
+*
+* Copyright (C) 2000 by Roaring Penguin Software Inc.
+*
+* This program may be distributed according to the terms of the GNU
+* General Public License, version 2 or (at your option) any later version.
+*
+***********************************************************************/
+
+static char const RCSID[] =
+"$Id: ppp.c 195724 2001-06-11 13:49:39Z gc $";
+
+#include "pppoe.h"
+
+#ifdef HAVE_SYSLOG_H
+#include <syslog.h>
+#endif
+
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+#ifdef HAVE_SYS_UIO_H
+#include <sys/uio.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef HAVE_N_HDLC
+#ifndef N_HDLC
+#include <linux/termios.h>
+#endif
+#endif
+
+int PPPState;
+int PPPPacketSize;
+unsigned char PPPXorValue;
+
+UINT16_t fcstab[256] = {
+ 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
+ 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
+ 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
+ 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
+ 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
+ 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
+ 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
+ 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
+ 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
+ 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
+ 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
+ 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
+ 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
+ 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
+ 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
+ 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
+ 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
+ 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
+ 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
+ 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
+ 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
+ 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
+ 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
+ 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
+ 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
+ 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
+ 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
+ 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
+ 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
+ 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
+ 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
+ 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
+};
+
+/**********************************************************************
+*%FUNCTION: syncReadFromPPP
+*%ARGUMENTS:
+* conn -- PPPoEConnection structure
+* packet -- buffer in which to place PPPoE packet
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Reads from a synchronous PPP device and builds and transmits a PPPoE
+* packet
+***********************************************************************/
+void
+syncReadFromPPP(PPPoEConnection *conn, PPPoEPacket *packet)
+{
+ int r;
+#ifndef HAVE_N_HDLC
+ struct iovec vec[2];
+ unsigned char dummy[2];
+ vec[0].iov_base = (void *) dummy;
+ vec[0].iov_len = 2;
+ vec[1].iov_base = (void *) packet->payload;
+ vec[1].iov_len = ETH_DATA_LEN - PPPOE_OVERHEAD;
+
+ /* Use scatter-read to throw away the PPP frame address bytes */
+ r = readv(0, vec, 2);
+#else
+ /* Bloody hell... readv doesn't work with N_HDLC line discipline... GRR! */
+ unsigned char buf[ETH_DATA_LEN - PPPOE_OVERHEAD + 2];
+ r = read(0, buf, ETH_DATA_LEN - PPPOE_OVERHEAD + 2);
+ if (r >= 2) {
+ memcpy(packet->payload, buf+2, r-2);
+ }
+#endif
+ if (r < 0) {
+ /* Catch the Linux "select" bug */
+ if (errno == EAGAIN) {
+ rp_fatal("Linux select bug hit! This message is harmless, but please ask the Linux kernel developers to fix it.");
+ }
+ fatalSys("read (syncReadFromPPP)");
+ }
+ if (r == 0) {
+ syslog(LOG_INFO, "end-of-file in syncReadFromPPP");
+ sendPADT(conn, "RP-PPPoE: EOF in syncReadFromPPP");
+ exit(0);
+ }
+
+ if (r < 2) {
+ rp_fatal("too few characters read from PPP (syncReadFromPPP)");
+ }
+
+ sendSessionPacket(conn, packet, r-2);
+}
+
+/**********************************************************************
+*%FUNCTION: initPPP
+*%ARGUMENTS:
+* None
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Initializes the PPP state machine
+***********************************************************************/
+void
+initPPP(void)
+{
+ PPPState = STATE_WAITFOR_FRAME_ADDR;
+ PPPPacketSize = 0;
+ PPPXorValue = 0;
+
+}
+/**********************************************************************
+*%FUNCTION: asyncReadFromPPP
+*%ARGUMENTS:
+* conn -- PPPoEConnection structure
+* packet -- buffer in which to place PPPoE packet
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Reads from an async PPP device and builds a PPPoE packet to transmit
+***********************************************************************/
+void
+asyncReadFromPPP(PPPoEConnection *conn, PPPoEPacket *packet)
+{
+ unsigned char buf[READ_CHUNK];
+ unsigned char *ptr = buf;
+ unsigned char c;
+
+ int r;
+
+ r = read(0, buf, READ_CHUNK);
+ if (r < 0) {
+ fatalSys("read (asyncReadFromPPP)");
+ }
+
+ if (r == 0) {
+ syslog(LOG_INFO, "end-of-file in asyncReadFromPPP");
+ sendPADT(conn, "RP-PPPoE: EOF in asyncReadFromPPP");
+ exit(0);
+ }
+
+ while(r) {
+ if (PPPState == STATE_WAITFOR_FRAME_ADDR) {
+ while(r) {
+ --r;
+ if (*ptr++ == FRAME_ADDR) {
+ PPPState = STATE_DROP_PROTO;
+ break;
+ }
+ }
+ }
+
+ /* Still waiting... */
+ if (PPPState == STATE_WAITFOR_FRAME_ADDR) return;
+
+ while(r && PPPState == STATE_DROP_PROTO) {
+ --r;
+ if (*ptr++ == (FRAME_CTRL ^ FRAME_ENC)) {
+ PPPState = STATE_BUILDING_PACKET;
+ }
+ }
+
+ if (PPPState == STATE_DROP_PROTO) return;
+
+ /* Start building frame */
+ while(r && PPPState == STATE_BUILDING_PACKET) {
+ --r;
+ c = *ptr++;
+ switch(c) {
+ case FRAME_ESC:
+ PPPXorValue = FRAME_ENC;
+ break;
+ case FRAME_FLAG:
+ if (PPPPacketSize < 2) {
+ rp_fatal("Packet too short from PPP (asyncReadFromPPP)");
+ }
+ sendSessionPacket(conn, packet, PPPPacketSize-2);
+ PPPPacketSize = 0;
+ PPPXorValue = 0;
+ PPPState = STATE_WAITFOR_FRAME_ADDR;
+ break;
+ default:
+ if (PPPPacketSize >= ETH_DATA_LEN - 4) {
+ syslog(LOG_ERR, "Packet too big! Check MTU on PPP interface");
+ PPPPacketSize = 0;
+ PPPXorValue = 0;
+ PPPState = STATE_WAITFOR_FRAME_ADDR;
+ } else {
+ packet->payload[PPPPacketSize++] = c ^ PPPXorValue;
+ PPPXorValue = 0;
+ }
+ }
+ }
+ }
+}
+
+/**********************************************************************
+*%FUNCTION: pppFCS16
+*%ARGUMENTS:
+* fcs -- current fcs
+* cp -- a buffer's worth of data
+* len -- length of buffer "cp"
+*%RETURNS:
+* A new FCS
+*%DESCRIPTION:
+* Updates the PPP FCS.
+***********************************************************************/
+UINT16_t
+pppFCS16(UINT16_t fcs,
+ unsigned char * cp,
+ int len)
+{
+ while (len--)
+ fcs = (fcs >> 8) ^ fcstab[(fcs ^ *cp++) & 0xff];
+
+ return (fcs);
+}
+
diff --git a/mdk-stage1/rp-pppoe/src/pppoe-server.c b/mdk-stage1/rp-pppoe/src/pppoe-server.c
new file mode 100644
index 000000000..b53952b81
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/src/pppoe-server.c
@@ -0,0 +1,1247 @@
+/***********************************************************************
+*
+* pppoe.h
+*
+* Implementation of a user-space PPPoE server
+*
+* Copyright (C) 2000 Roaring Penguin Software Inc.
+*
+* This program may be distributed according to the terms of the GNU
+* General Public License, version 2 or (at your option) any later version.
+*
+* $Id: pppoe-server.c 195724 2001-06-11 13:49:39Z gc $
+*
+***********************************************************************/
+
+static char const RCSID[] =
+"$Id: pppoe-server.c 195724 2001-06-11 13:49:39Z gc $";
+
+#include "config.h"
+
+#if defined(HAVE_NETPACKET_PACKET_H) || defined(HAVE_LINUX_IF_PACKET_H)
+#define _POSIX_SOURCE 1 /* For sigaction defines */
+#endif
+
+#define _BSD_SOURCE 1 /* for gethostname */
+
+#include "pppoe.h"
+#include "md5.h"
+
+#ifdef HAVE_SYSLOG_H
+#include <syslog.h>
+#endif
+
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef HAVE_GETOPT_H
+#include <getopt.h>
+#endif
+
+#ifdef HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
+
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+
+#include <signal.h>
+
+/* Hack for daemonizing */
+#define CLOSEFD 64
+
+/* Max. 64 sessions by default */
+#define DEFAULT_MAX_SESSIONS 64
+
+/* A list of client sessions */
+struct ClientSession *Sessions = NULL;
+
+/* The number of session slots */
+size_t NumSessionSlots;
+
+/* Offset of first session */
+size_t SessOffset = 0;
+
+/* Socket for client's discovery phases */
+int Socket = -1;
+
+/* Pipe written on reception of SIGCHLD */
+int Pipe[2] = {-1, -1};
+int ReapPending = 0;
+
+/* Synchronous mode */
+int Synchronous = 0;
+
+/* Random seed for cookie generation */
+#define SEED_LEN 16
+#define MD5_LEN 16
+#define COOKIE_LEN (MD5_LEN + sizeof(pid_t)) /* Cookie is 16-byte MD5 + PID of server */
+
+unsigned char CookieSeed[SEED_LEN];
+
+/* Default interface if no -I option given */
+#define DEFAULT_IF "eth0"
+char *IfName = NULL;
+
+/* Access concentrator name */
+char *ACName = NULL;
+
+/* Options to pass to pppoe process */
+char PppoeOptions[SMALLBUF] = "";
+
+/* Our local IP address */
+unsigned char LocalIP[IPV4ALEN] = {10, 0, 0, 1};
+unsigned char RemoteIP[IPV4ALEN] = {10, 67, 15, 1}; /* Counter STARTS here */
+
+PPPoETag hostUniq;
+PPPoETag relayId;
+PPPoETag receivedCookie;
+PPPoETag requestedService;
+
+#define HOSTNAMELEN 256
+
+static void startPPPD(struct ClientSession *sess);
+static void sendErrorPADS(int sock, unsigned char *source, unsigned char *dest,
+ int errorTag, char *errorMsg);
+
+#define CHECK_ROOM(cursor, start, len) \
+do {\
+ if (((cursor)-(start))+(len) > MAX_PPPOE_PAYLOAD) { \
+ syslog(LOG_ERR, "Would create too-long packet"); \
+ return; \
+ } \
+} while(0)
+
+/* Use Linux kernel-mode PPPoE? */
+int UseLinuxKernelModePPPoE = 0;
+
+/**********************************************************************
+*%FUNCTION: parseAddressPool
+*%ARGUMENTS:
+* fname -- name of file containing IP address pool.
+* install -- if true, install IP addresses in sessions.
+*%RETURNS:
+* Number of valid IP addresses found.
+*%DESCRIPTION:
+* Reads a list of IP addresses from a file.
+***********************************************************************/
+static int
+parseAddressPool(char const *fname, int install)
+{
+ FILE *fp = fopen(fname, "r");
+ int numAddrs = 0;
+ unsigned int a, b, c, d;
+
+ if (!fp) {
+ sysErr("Cannot open address pool file");
+ }
+
+ while (!feof(fp)) {
+ if ((fscanf(fp, "%u.%u.%u.%u", &a, &b, &c, &d) == 4) &&
+ a < 256 && b < 256 && c < 256 && d < 256) {
+ if (install) {
+ Sessions[numAddrs].ip[0] = (unsigned char) a;
+ Sessions[numAddrs].ip[1] = (unsigned char) b;
+ Sessions[numAddrs].ip[2] = (unsigned char) c;
+ Sessions[numAddrs].ip[3] = (unsigned char) d;
+ }
+ numAddrs++;
+ }
+ }
+ if (!numAddrs) {
+ rp_fatal("No valid ip addresses found in pool file");
+ }
+ return numAddrs;
+}
+
+/**********************************************************************
+*%FUNCTION: parsePADITags
+*%ARGUMENTS:
+* type -- tag type
+* len -- tag length
+* data -- tag data
+* extra -- extra user data.
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Picks interesting tags out of a PADI packet
+***********************************************************************/
+void
+parsePADITags(UINT16_t type, UINT16_t len, unsigned char *data,
+ void *extra)
+{
+ switch(type) {
+ case TAG_SERVICE_NAME:
+ /* Should do something -- currently ignored */
+ break;
+ case TAG_RELAY_SESSION_ID:
+ relayId.type = htons(type);
+ relayId.length = htons(len);
+ memcpy(relayId.payload, data, len);
+ break;
+ case TAG_HOST_UNIQ:
+ hostUniq.type = htons(type);
+ hostUniq.length = htons(len);
+ memcpy(hostUniq.payload, data, len);
+ break;
+ }
+}
+
+/**********************************************************************
+*%FUNCTION: parsePADRTags
+*%ARGUMENTS:
+* type -- tag type
+* len -- tag length
+* data -- tag data
+* extra -- extra user data.
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Picks interesting tags out of a PADR packet
+***********************************************************************/
+void
+parsePADRTags(UINT16_t type, UINT16_t len, unsigned char *data,
+ void *extra)
+{
+ switch(type) {
+ case TAG_RELAY_SESSION_ID:
+ relayId.type = htons(type);
+ relayId.length = htons(len);
+ memcpy(relayId.payload, data, len);
+ break;
+ case TAG_HOST_UNIQ:
+ hostUniq.type = htons(type);
+ hostUniq.length = htons(len);
+ memcpy(hostUniq.payload, data, len);
+ break;
+ case TAG_AC_COOKIE:
+ receivedCookie.type = htons(type);
+ receivedCookie.length = htons(len);
+ memcpy(receivedCookie.payload, data, len);
+ break;
+ case TAG_SERVICE_NAME:
+ requestedService.type = htons(type);
+ requestedService.length = htons(len);
+ memcpy(requestedService.payload, data, len);
+ break;
+ }
+}
+
+/**********************************************************************
+*%FUNCTION: findSession
+*%ARGUMENTS:
+* pid -- PID of child which owns session. If PID is 0, searches for
+* empty session slots.
+*%RETURNS:
+* A pointer to the session, or NULL if no such session found.
+*%DESCRIPTION:
+* Searches for specified session.
+**********************************************************************/
+struct ClientSession *
+findSession(pid_t pid)
+{
+ size_t i;
+ for (i=0; i<NumSessionSlots; i++) {
+ if (Sessions[i].pid == pid) {
+ return &Sessions[i];
+ }
+ }
+ return NULL;
+}
+
+/**********************************************************************
+*%FUNCTION: reapSessions
+*%ARGUMENTS:
+* myAddr -- my Ethernet address
+* sock -- my discovery socket
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Reaps children which have exited and removes their sessions
+**********************************************************************/
+void
+reapSessions(unsigned char *myAddr, int sock)
+{
+ int status;
+ pid_t pid;
+ struct ClientSession *session;
+
+ /* Temporary structure for sending PADT's. */
+ PPPoEConnection conn;
+ memset(&conn, 0, sizeof(conn));
+
+ /* Initialize fields of conn which do not depend on peer */
+ memcpy(conn.myEth, myAddr, ETH_ALEN);
+ conn.useHostUniq = 0;
+ conn.discoverySocket = sock;
+
+ while((pid = waitpid(-1, &status, WNOHANG)) > 0) {
+ session = findSession(pid);
+ if (!session) {
+ syslog(LOG_ERR, "Child %d died but couldn't find session!",
+ (int) pid);
+ } else {
+ syslog(LOG_INFO,
+ "Session %d closed for client %02x:%02x:%02x:%02x:%02x:%02x (%d.%d.%d.%d)",
+ ntohs(session->sess),
+ session->eth[0], session->eth[1], session->eth[2],
+ session->eth[3], session->eth[4], session->eth[5],
+ (int) session->ip[0], (int) session->ip[1],
+ (int) session->ip[2], (int) session->ip[3]);
+ conn.session = session->sess;
+ memcpy(conn.peerEth, session->eth, ETH_ALEN);
+ if (session->recvdPADT) {
+ sendPADT(&conn, "RP-PPPoE: Received PADT from peer");
+ } else {
+ sendPADT(&conn, "RP-PPPoE: Child pppd process terminated");
+ }
+ session->pid = 0;
+ }
+ }
+}
+
+/**********************************************************************
+*%FUNCTION: fatalSys
+*%ARGUMENTS:
+* str -- error message
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Prints a message plus the errno value to stderr and syslog and exits.
+***********************************************************************/
+void
+fatalSys(char const *str)
+{
+ char buf[SMALLBUF];
+ snprintf(buf, SMALLBUF, "%s: %s", str, strerror(errno));
+ printErr(buf);
+ exit(EXIT_FAILURE);
+}
+
+/**********************************************************************
+*%FUNCTION: sysErr
+*%ARGUMENTS:
+* str -- error message
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Prints a message plus the errno value to syslog.
+***********************************************************************/
+void
+sysErr(char const *str)
+{
+ char buf[1024];
+ sprintf(buf, "%.256s: %.256s", str, strerror(errno));
+ printErr(buf);
+}
+
+/**********************************************************************
+*%FUNCTION: rp_fatal
+*%ARGUMENTS:
+* str -- error message
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Prints a message to stderr and syslog and exits.
+***********************************************************************/
+void
+rp_fatal(char const *str)
+{
+ printErr(str);
+ exit(EXIT_FAILURE);
+}
+
+/**********************************************************************
+*%FUNCTION: genCookie
+*%ARGUMENTS:
+* peerEthAddr -- peer Ethernet address (6 bytes)
+* myEthAddr -- my Ethernet address (6 bytes)
+* seed -- random cookie seed to make things tasty (16 bytes)
+* cookie -- buffer which is filled with server PID and
+* md5 sum of previous items
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Forms the md5 sum of peer MAC address, our MAC address and seed, useful
+* in a PPPoE Cookie tag.
+***********************************************************************/
+void
+genCookie(unsigned char const *peerEthAddr,
+ unsigned char const *myEthAddr,
+ unsigned char const *seed,
+ unsigned char *cookie)
+{
+ struct MD5Context ctx;
+ pid_t pid = getpid();
+
+ MD5Init(&ctx);
+ MD5Update(&ctx, peerEthAddr, ETH_ALEN);
+ MD5Update(&ctx, myEthAddr, ETH_ALEN);
+ MD5Update(&ctx, seed, SEED_LEN);
+ MD5Final(cookie, &ctx);
+ memcpy(cookie+MD5_LEN, &pid, sizeof(pid));
+}
+
+/**********************************************************************
+*%FUNCTION: processPADI
+*%ARGUMENTS:
+* sock -- Ethernet socket
+* myAddr -- my Ethernet address
+* packet -- PPPoE PADI packet
+* len -- length of received packet
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Sends a PADO packet back to client
+***********************************************************************/
+void
+processPADI(int sock, unsigned char *myAddr,
+ PPPoEPacket *packet, int len)
+{
+ PPPoEPacket pado;
+ PPPoETag acname;
+ PPPoETag servname;
+ PPPoETag cookie;
+ size_t acname_len;
+ unsigned char *cursor = pado.payload;
+ UINT16_t plen;
+
+ /* Ignore PADI's which don't come from a unicast address */
+ if (NOT_UNICAST(packet->ethHdr.h_source)) {
+ syslog(LOG_ERR, "PADI packet from non-unicast source address");
+ return;
+ }
+
+ acname.type = htons(TAG_AC_NAME);
+ acname_len = strlen(ACName);
+ acname.length = htons(acname_len);
+ memcpy(acname.payload, ACName, acname_len);
+
+ servname.type = htons(TAG_SERVICE_NAME);
+ servname.length = 0;
+
+ relayId.type = 0;
+ hostUniq.type = 0;
+ parsePacket(packet, parsePADITags, NULL);
+
+ /* Generate a cookie */
+ cookie.type = htons(TAG_AC_COOKIE);
+ cookie.length = htons(COOKIE_LEN);
+ genCookie(packet->ethHdr.h_source, myAddr, CookieSeed, cookie.payload);
+
+ /* Construct a PADO packet */
+ memcpy(pado.ethHdr.h_dest, packet->ethHdr.h_source, ETH_ALEN);
+ memcpy(pado.ethHdr.h_source, myAddr, ETH_ALEN);
+ pado.ethHdr.h_proto = htons(Eth_PPPOE_Discovery);
+ pado.ver = 1;
+ pado.type = 1;
+ pado.code = CODE_PADO;
+ pado.session = 0;
+ plen = TAG_HDR_SIZE + acname_len;
+
+ CHECK_ROOM(cursor, pado.payload, acname_len+TAG_HDR_SIZE);
+ memcpy(cursor, &acname, acname_len + TAG_HDR_SIZE);
+ cursor += acname_len + TAG_HDR_SIZE;
+
+ CHECK_ROOM(cursor, pado.payload, TAG_HDR_SIZE);
+ memcpy(cursor, &servname, TAG_HDR_SIZE);
+ cursor += TAG_HDR_SIZE;
+ plen += TAG_HDR_SIZE;
+
+ CHECK_ROOM(cursor, pado.payload, TAG_HDR_SIZE + COOKIE_LEN);
+ memcpy(cursor, &cookie, TAG_HDR_SIZE + COOKIE_LEN);
+ cursor += TAG_HDR_SIZE + COOKIE_LEN;
+ plen += TAG_HDR_SIZE + COOKIE_LEN;
+
+ if (relayId.type) {
+ CHECK_ROOM(cursor, pado.payload, ntohs(relayId.length) + TAG_HDR_SIZE);
+ memcpy(cursor, &relayId, ntohs(relayId.length) + TAG_HDR_SIZE);
+ cursor += ntohs(relayId.length) + TAG_HDR_SIZE;
+ plen += ntohs(relayId.length) + TAG_HDR_SIZE;
+ }
+ if (hostUniq.type) {
+ CHECK_ROOM(cursor, pado.payload, ntohs(hostUniq.length)+TAG_HDR_SIZE);
+ memcpy(cursor, &hostUniq, ntohs(hostUniq.length) + TAG_HDR_SIZE);
+ cursor += ntohs(hostUniq.length) + TAG_HDR_SIZE;
+ plen += ntohs(hostUniq.length) + TAG_HDR_SIZE;
+ }
+ pado.length = htons(plen);
+ sendPacket(NULL, sock, &pado, (int) (plen + HDR_SIZE));
+}
+
+/**********************************************************************
+*%FUNCTION: processPADT
+*%ARGUMENTS:
+* sock -- Ethernet socket
+* myAddr -- my Ethernet address
+* packet -- PPPoE PADT packet
+* len -- length of received packet
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Kills session whose session-ID is in PADT packet.
+***********************************************************************/
+void
+processPADT(int sock, unsigned char *myAddr,
+ PPPoEPacket *packet, int len)
+{
+ size_t i;
+
+ /* Ignore PADT's not directed at us */
+ if (memcmp(packet->ethHdr.h_dest, myAddr, ETH_ALEN)) return;
+
+ /* Get session's index */
+ i = ntohs(packet->session) - 1 - SessOffset;
+ if (i >= NumSessionSlots) return;
+ if (Sessions[i].sess != packet->session) {
+ syslog(LOG_ERR, "Session index %u doesn't match session number %u",
+ (unsigned int) i, (unsigned int) ntohs(packet->session));
+ return;
+ }
+ if (Sessions[i].pid) {
+ Sessions[i].recvdPADT = 1;
+ parsePacket(packet, parseLogErrs, NULL);
+ kill(Sessions[i].pid, SIGTERM);
+ }
+}
+
+/**********************************************************************
+*%FUNCTION: processPADR
+*%ARGUMENTS:
+* sock -- Ethernet socket
+* myAddr -- my Ethernet address
+* packet -- PPPoE PADR packet
+* len -- length of received packet
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Sends a PADS packet back to client and starts a PPP session if PADR
+* packet is OK.
+***********************************************************************/
+void
+processPADR(int sock, unsigned char *myAddr,
+ PPPoEPacket *packet, int len)
+{
+ unsigned char cookieBuffer[COOKIE_LEN];
+ struct ClientSession *cliSession;
+ pid_t child;
+ PPPoEPacket pads;
+ unsigned char *cursor = pads.payload;
+ UINT16_t plen;
+ PPPoETag servname;
+
+ /* Initialize some globals */
+ relayId.type = 0;
+ hostUniq.type = 0;
+ receivedCookie.type = 0;
+ requestedService.type = 0;
+
+ /* Ignore PADR's not directed at us */
+ if (memcmp(packet->ethHdr.h_dest, myAddr, ETH_ALEN)) return;
+
+ /* Ignore PADR's from non-unicast addresses */
+ if (NOT_UNICAST(packet->ethHdr.h_source)) {
+ syslog(LOG_ERR, "PADR packet from non-unicast source address");
+ return;
+ }
+
+ parsePacket(packet, parsePADRTags, NULL);
+
+ /* Check that everything's cool */
+ if (!receivedCookie.type) {
+ /* Drop it -- do not send error PADS */
+ return;
+ }
+
+ /* Is cookie kosher? */
+ if (receivedCookie.length != htons(COOKIE_LEN)) {
+ /* Drop it -- do not send error PADS */
+ return;
+ }
+
+ genCookie(packet->ethHdr.h_source, myAddr, CookieSeed, cookieBuffer);
+ if (memcmp(receivedCookie.payload, cookieBuffer, COOKIE_LEN)) {
+ /* Drop it -- do not send error PADS */
+ return;
+ }
+
+ /* Check service name -- we only offer service "" */
+ if (!requestedService.type) {
+ syslog(LOG_ERR, "Received PADR packet with no SERVICE_NAME tag");
+ sendErrorPADS(sock, myAddr, packet->ethHdr.h_source,
+ TAG_SERVICE_NAME_ERROR, "RP-PPPoE: Server: No service name tag");
+ return;
+ }
+
+ if (requestedService.length) {
+ syslog(LOG_ERR, "Received PADR packet asking for unsupported service %.*s", (int) ntohs(requestedService.length), requestedService.payload);
+ sendErrorPADS(sock, myAddr, packet->ethHdr.h_source,
+ TAG_SERVICE_NAME_ERROR, "RP-PPPoE: Server: Invalid service name tag");
+ return;
+ }
+
+ /* Looks cool... find a slot for the session */
+ cliSession = findSession(0);
+ if (!cliSession) {
+ syslog(LOG_ERR, "No client slots available (%02x:%02x:%02x:%02x:%02x:%02x)",
+ (unsigned int) packet->ethHdr.h_source[0],
+ (unsigned int) packet->ethHdr.h_source[1],
+ (unsigned int) packet->ethHdr.h_source[2],
+ (unsigned int) packet->ethHdr.h_source[3],
+ (unsigned int) packet->ethHdr.h_source[4],
+ (unsigned int) packet->ethHdr.h_source[5]);
+ sendErrorPADS(sock, myAddr, packet->ethHdr.h_source,
+ TAG_AC_SYSTEM_ERROR, "RP-PPPoE: Server: No client slots available");
+ return;
+ }
+
+ /* Set up client session peer Ethernet address */
+ memcpy(cliSession->eth, packet->ethHdr.h_source, ETH_ALEN);
+ cliSession->recvdPADT = 0;
+
+ /* Create child process, send PADS packet back */
+ child = fork();
+ if (child < 0) {
+ sendErrorPADS(sock, myAddr, packet->ethHdr.h_source,
+ TAG_AC_SYSTEM_ERROR, "RP-PPPoE: Server: Unable to start session process");
+ return;
+ }
+ if (child != 0) {
+ /* In the parent process. Mark pid in session slot */
+ cliSession->pid = child;
+ return;
+ }
+
+ /* In the child process. */
+
+ /* pppd has a nasty habit of killing all processes in its process group.
+ Start a new session to stop pppd from killing us! */
+ setsid();
+
+ /* Send PADS and Start pppd */
+ memcpy(pads.ethHdr.h_dest, packet->ethHdr.h_source, ETH_ALEN);
+ memcpy(pads.ethHdr.h_source, myAddr, ETH_ALEN);
+ pads.ethHdr.h_proto = htons(Eth_PPPOE_Discovery);
+ pads.ver = 1;
+ pads.type = 1;
+ pads.code = CODE_PADS;
+
+ pads.session = cliSession->sess;
+ plen = 0;
+
+ servname.type = htons(TAG_SERVICE_NAME);
+ servname.length = 0;
+
+ memcpy(cursor, &servname, TAG_HDR_SIZE);
+ cursor += TAG_HDR_SIZE;
+ plen += TAG_HDR_SIZE;
+
+ if (relayId.type) {
+ memcpy(cursor, &relayId, ntohs(relayId.length) + TAG_HDR_SIZE);
+ cursor += ntohs(relayId.length) + TAG_HDR_SIZE;
+ plen += ntohs(relayId.length) + TAG_HDR_SIZE;
+ }
+ if (hostUniq.type) {
+ memcpy(cursor, &hostUniq, ntohs(hostUniq.length) + TAG_HDR_SIZE);
+ cursor += ntohs(hostUniq.length) + TAG_HDR_SIZE;
+ plen += ntohs(hostUniq.length) + TAG_HDR_SIZE;
+ }
+ pads.length = htons(plen);
+ sendPacket(NULL, sock, &pads, (int) (plen + HDR_SIZE));
+ startPPPD(cliSession);
+}
+
+/**********************************************************************
+*%FUNCTION: childHandler
+*%ARGUMENTS:
+* sig -- signal number
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Called by SIGCHLD. Writes one byte to Pipe to wake up the select
+* loop and cause reaping of dead sessions
+***********************************************************************/
+void
+childHandler(int sig)
+{
+ if (!ReapPending) {
+ ReapPending = 1;
+ write(Pipe[1], &ReapPending, 1);
+ }
+}
+
+/**********************************************************************
+*%FUNCTION: usage
+*%ARGUMENTS:
+* argv0 -- argv[0] from main
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Prints usage instructions
+***********************************************************************/
+void
+usage(char const *argv0)
+{
+ fprintf(stderr, "Usage: %s [options]\n", argv0);
+ fprintf(stderr, "Options:\n");
+#ifdef USE_BPF
+ fprintf(stderr, " -I if_name -- Specify interface (REQUIRED)\n");
+#else
+ fprintf(stderr, " -I if_name -- Specify interface (default %s.)\n",
+ DEFAULT_IF);
+#endif
+ fprintf(stderr, " -T timeout -- Specify inactivity timeout in seconds.\n");
+ fprintf(stderr, " -C name -- Set access concentrator name.\n");
+ fprintf(stderr, " -m MSS -- Clamp incoming and outgoing MSS options.\n");
+ fprintf(stderr, " -L ip -- Set local IP address.\n");
+ fprintf(stderr, " -R ip -- Set start address of remote IP pool.\n");
+ fprintf(stderr, " -p fname -- Optain IP address pool from specified file.\n");
+ fprintf(stderr, " -N num -- Allow 'num' concurrent sessions.\n");
+ fprintf(stderr, " -o offset -- Assign session numbers starting at offset+1.\n");
+ fprintf(stderr, " -f disc:sess -- Set Ethernet frame types (hex).\n");
+ fprintf(stderr, " -s -- Use synchronous PPP mode.\n");
+#ifdef HAVE_LINUX_KERNEL_PPPOE
+ fprintf(stderr, " -k -- Use kernel-mode PPPoE.\n");
+#endif
+ fprintf(stderr, " -h -- Print usage information.\n\n");
+ fprintf(stderr, "PPPoE-Server Version %s, Copyright (C) 2001 Roaring Penguin Software Inc.\n", VERSION);
+ fprintf(stderr, "PPPoE-Server comes with ABSOLUTELY NO WARRANTY.\n");
+ fprintf(stderr, "This is free software, and you are welcome to redistribute it\n");
+ fprintf(stderr, "under the terms of the GNU General Public License, version 2\n");
+ fprintf(stderr, "or (at your option) any later version.\n");
+ fprintf(stderr, "http://www.roaringpenguin.com\n");
+}
+
+/**********************************************************************
+*%FUNCTION: main
+*%ARGUMENTS:
+* argc, argv -- usual suspects
+*%RETURNS:
+* Exit status
+*%DESCRIPTION:
+* Main program of PPPoE server
+***********************************************************************/
+int
+main(int argc, char **argv)
+{
+
+ FILE *fp;
+ int i;
+ int opt;
+ unsigned char myAddr[ETH_ALEN];
+ PPPoEPacket packet;
+ int len;
+ int sock;
+ int d[IPV4ALEN];
+ int beDaemon = 1;
+ struct sigaction act;
+ int maxFD;
+ unsigned int discoveryType, sessionType;
+ char *addressPoolFname = NULL;
+
+#ifndef HAVE_LINUX_KERNEL_PPPOE
+ char *options = "hI:C:L:R:T:m:FN:f:o:sp:";
+#else
+ char *options = "hI:C:L:R:T:m:FN:f:o:skp:";
+#endif
+
+ /* Initialize syslog */
+ openlog("pppoe-server", LOG_PID, LOG_DAEMON);
+
+ /* Default number of session slots */
+ NumSessionSlots = DEFAULT_MAX_SESSIONS;
+
+ /* Parse command-line options */
+ while((opt = getopt(argc, argv, options)) != -1) {
+ switch(opt) {
+#ifdef HAVE_LINUX_KERNEL_PPPOE
+ case 'k':
+ UseLinuxKernelModePPPoE = 1;
+ break;
+#endif
+ case 'p':
+ addressPoolFname = optarg;
+ break;
+ case 's':
+ Synchronous = 1;
+ /* Pass the Synchronous option on to pppoe */
+ snprintf(PppoeOptions + strlen(PppoeOptions),
+ SMALLBUF-strlen(PppoeOptions),
+ " -s");
+ break;
+ case 'f':
+ if (sscanf(optarg, "%x:%x", &discoveryType, &sessionType) != 2) {
+ fprintf(stderr, "Illegal argument to -f: Should be disc:sess in hex\n");
+ exit(EXIT_FAILURE);
+ }
+ Eth_PPPOE_Discovery = (UINT16_t) discoveryType;
+ Eth_PPPOE_Session = (UINT16_t) sessionType;
+ /* This option gets passed to pppoe */
+ snprintf(PppoeOptions + strlen(PppoeOptions),
+ SMALLBUF-strlen(PppoeOptions),
+ " -%c %s", opt, optarg);
+ break;
+ case 'F':
+ beDaemon = 0;
+ break;
+ case 'N':
+ if (sscanf(optarg, "%d", &opt) != 1) {
+ usage(argv[0]);
+ exit(EXIT_FAILURE);
+ }
+ if (opt <= 0) {
+ fprintf(stderr, "-N: Value must be positive\n");
+ exit(EXIT_FAILURE);
+ }
+ NumSessionSlots = opt;
+ break;
+ case 'o':
+ if (sscanf(optarg, "%d", &opt) != 1) {
+ usage(argv[0]);
+ exit(EXIT_FAILURE);
+ }
+ if (opt < 0) {
+ fprintf(stderr, "-o: Value must be non-negative\n");
+ exit(EXIT_FAILURE);
+ }
+ SessOffset = (size_t) opt;
+ break;
+
+ case 'I':
+ SET_STRING(IfName, optarg);
+ break;
+ case 'C':
+ SET_STRING(ACName, optarg);
+ break;
+ case 'L':
+ case 'R':
+ /* Get local/remote IP address */
+ if (sscanf(optarg, "%d.%d.%d.%d", &d[0], &d[1], &d[2], &d[3]) != 4) {
+ usage(argv[0]);
+ exit(EXIT_FAILURE);
+ }
+ for (i=0; i<IPV4ALEN; i++) {
+ if (d[i] < 0 || d[i] > 255) {
+ usage(argv[0]);
+ exit(EXIT_FAILURE);
+ }
+ if (opt == 'L') {
+ LocalIP[i] = (unsigned char) d[i];
+ } else {
+ RemoteIP[i] = (unsigned char) d[i];
+ }
+ }
+ break;
+ case 'T':
+ case 'm':
+ /* These just get passed to pppoe */
+ snprintf(PppoeOptions + strlen(PppoeOptions),
+ SMALLBUF-strlen(PppoeOptions),
+ " -%c %s", opt, optarg);
+ break;
+ case 'h':
+ usage(argv[0]);
+ exit(EXIT_SUCCESS);
+ }
+ }
+
+#ifdef USE_LINUX_PACKET
+#ifndef HAVE_STRUCT_SOCKADDR_LL
+ fprintf(stderr, "The PPPoE relay does not work on Linux 2.0 kernels.\n");
+ exit(EXIT_FAILURE);
+#endif
+#endif
+
+ if (!IfName) {
+ IfName = DEFAULT_IF;
+ }
+
+ if (!ACName) {
+ ACName = malloc(HOSTNAMELEN);
+ if (gethostname(ACName, HOSTNAMELEN) < 0) {
+ fatalSys("gethostname");
+ }
+ }
+
+ /* If address pool filename given, count number of addresses */
+ if (addressPoolFname) {
+ NumSessionSlots = parseAddressPool(addressPoolFname, 0);
+ }
+
+ /* Max 65534 - SessOffset sessions */
+ if (NumSessionSlots + SessOffset > 65534) {
+ fprintf(stderr, "-N and -o options must add up to at most 65534\n");
+ exit(EXIT_FAILURE);
+ }
+
+ /* Allocate memory for sessions */
+ Sessions = calloc(NumSessionSlots, sizeof(struct ClientSession));
+ if (!Sessions) {
+ rp_fatal("Cannot allocate memory for session slots");
+ }
+
+ /* Fill in remote IP addresses from pool */
+ if (addressPoolFname) {
+ (void) parseAddressPool(addressPoolFname, 1);
+ }
+
+ /* For testing -- generate sequential remote IP addresses */
+ for(i=0; i<NumSessionSlots; i++) {
+ Sessions[i].pid = 0;
+ Sessions[i].sess = htons(i+1+SessOffset);
+
+ if (!addressPoolFname) {
+ memcpy(Sessions[i].ip, RemoteIP, sizeof(RemoteIP));
+
+ /* Increment IP */
+ RemoteIP[3]++;
+ if (!RemoteIP[3]) {
+ RemoteIP[3] = 0;
+ RemoteIP[2]++;
+ if (!RemoteIP[2]) {
+ RemoteIP[1]++;
+ if (!RemoteIP[1]) {
+ RemoteIP[0]++;
+ }
+ }
+ }
+ }
+ }
+
+ /* Daemonize -- UNIX Network Programming, Vol. 1, Stevens */
+ if (beDaemon) {
+ i = fork();
+ if (i < 0) {
+ fatalSys("fork");
+ } else if (i != 0) {
+ /* parent */
+ exit(EXIT_SUCCESS);
+ }
+ setsid();
+ signal(SIGHUP, SIG_IGN);
+ i = fork();
+ if (i < 0) {
+ fatalSys("fork");
+ } else if (i != 0) {
+ exit(EXIT_SUCCESS);
+ }
+
+ chdir("/");
+ closelog();
+ for (i=0; i<CLOSEFD; i++) close(i);
+ /* We nuked our syslog descriptor... */
+ openlog("pppoe-server", LOG_PID, LOG_DAEMON);
+ }
+
+ /* Initialize our random cookie. Try /dev/urandom; if that fails,
+ use PID and rand() */
+ fp = fopen("/dev/urandom", "r");
+ if (fp) {
+ fread(&CookieSeed, 1, SEED_LEN, fp);
+ fclose(fp);
+ } else {
+ CookieSeed[0] = getpid() & 0xFF;
+ CookieSeed[1] = (getpid() >> 8) & 0xFF;
+ for (i=2; i<SEED_LEN; i++) {
+ CookieSeed[i] = (rand() >> (i % 9)) & 0xFF;
+ }
+ }
+
+ sock = openInterface(IfName, Eth_PPPOE_Discovery, myAddr);
+
+ /* Set signal handler for SIGCHLD */
+ act.sa_handler = childHandler;
+ sigemptyset(&act.sa_mask);
+ act.sa_flags = SA_NOCLDSTOP | SA_RESTART;
+ if (sigaction(SIGCHLD, &act, NULL) < 0) {
+ fatalSys("sigaction");
+ }
+
+ /* Set up pipe for signal handler */
+ if (pipe(Pipe) < 0) {
+ fatalSys("pipe");
+ }
+
+ /* Main server loop */
+ maxFD = sock;
+ if (Pipe[0] > maxFD) maxFD = Pipe[0];
+ maxFD++;
+
+ for(;;) {
+ fd_set readable;
+ FD_ZERO(&readable);
+ FD_SET(sock, &readable);
+ FD_SET(Pipe[0], &readable);
+
+ while(1) {
+ i = select(maxFD, &readable, NULL, NULL, NULL);
+ if (i >= 0 || errno != EINTR) break;
+ }
+ if (i < 0) {
+ fatalSys("select");
+ }
+
+ if (FD_ISSET(Pipe[0], &readable)) {
+ /* Clear pipe */
+ char buf[SMALLBUF];
+ read(Pipe[0], buf, SMALLBUF);
+ }
+
+ if (ReapPending) {
+ ReapPending = 0;
+ reapSessions(myAddr, sock);
+ }
+ if (!FD_ISSET(sock, &readable)) {
+ continue;
+ }
+
+ if (receivePacket(sock, &packet, &len) < 0) {
+ continue;
+ }
+
+ /* Check length */
+ if (ntohs(packet.length) + HDR_SIZE > len) {
+ syslog(LOG_ERR, "Bogus PPPoE length field (%u)",
+ (unsigned int) ntohs(packet.length));
+ continue;
+ }
+
+ /* Sanity check on packet */
+ if (packet.ver != 1 || packet.type != 1) {
+ /* Syslog an error */
+ continue;
+ }
+ switch(packet.code) {
+ case CODE_PADI:
+ processPADI(sock, myAddr, &packet, len);
+ break;
+ case CODE_PADR:
+ processPADR(sock, myAddr, &packet, len);
+ break;
+ case CODE_PADT:
+ /* Kill the child */
+ processPADT(sock, myAddr, &packet, len);
+ break;
+ case CODE_SESS:
+ /* Ignore SESS -- children will handle them */
+ break;
+ case CODE_PADO:
+ case CODE_PADS:
+ /* Ignore PADO and PADS totally */
+ break;
+ default:
+ /* Syslog an error */
+ break;
+ }
+ }
+ return 0;
+}
+
+/**********************************************************************
+*%FUNCTION: sendErrorPADS
+*%ARGUMENTS:
+* sock -- socket to write to
+* source -- source Ethernet address
+* dest -- destination Ethernet address
+* errorTag -- error tag
+* errorMsg -- error message
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Sends a PADS packet with an error message
+***********************************************************************/
+void
+sendErrorPADS(int sock,
+ unsigned char *source,
+ unsigned char *dest,
+ int errorTag,
+ char *errorMsg)
+{
+ PPPoEPacket pads;
+ unsigned char *cursor = pads.payload;
+ UINT16_t plen;
+ PPPoETag err;
+ int elen = strlen(errorMsg);
+
+ memcpy(pads.ethHdr.h_dest, dest, ETH_ALEN);
+ memcpy(pads.ethHdr.h_source, source, ETH_ALEN);
+ pads.ethHdr.h_proto = htons(Eth_PPPOE_Discovery);
+ pads.ver = 1;
+ pads.type = 1;
+ pads.code = CODE_PADS;
+
+ pads.session = htons(0);
+ plen = 0;
+
+ err.type = htons(errorTag);
+ err.length = htons(elen);
+
+ memcpy(err.payload, errorMsg, elen);
+ memcpy(cursor, &err, TAG_HDR_SIZE+elen);
+ cursor += TAG_HDR_SIZE + elen;
+ plen += TAG_HDR_SIZE + elen;
+
+ if (relayId.type) {
+ memcpy(cursor, &relayId, ntohs(relayId.length) + TAG_HDR_SIZE);
+ cursor += ntohs(relayId.length) + TAG_HDR_SIZE;
+ plen += ntohs(relayId.length) + TAG_HDR_SIZE;
+ }
+ if (hostUniq.type) {
+ memcpy(cursor, &hostUniq, ntohs(hostUniq.length) + TAG_HDR_SIZE);
+ cursor += ntohs(hostUniq.length) + TAG_HDR_SIZE;
+ plen += ntohs(hostUniq.length) + TAG_HDR_SIZE;
+ }
+ pads.length = htons(plen);
+ sendPacket(NULL, sock, &pads, (int) (plen + HDR_SIZE));
+}
+
+
+/**********************************************************************
+*%FUNCTION: startPPPDUserMode
+*%ARGUMENTS:
+* session -- client session record
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Starts PPPD for user-mode PPPoE
+***********************************************************************/
+void
+startPPPDUserMode(struct ClientSession *session)
+{
+ /* Leave some room */
+ char *argv[20];
+
+ char buffer[SMALLBUF];
+
+ argv[0] = "pppd";
+ argv[1] = "pty";
+
+ snprintf(buffer, SMALLBUF, "%s -n -I %s -e %d:%02x:%02x:%02x:%02x:%02x:%02x%s",
+ PPPOE_PATH, IfName,
+ ntohs(session->sess),
+ session->eth[0], session->eth[1], session->eth[2],
+ session->eth[3], session->eth[4], session->eth[5],
+ PppoeOptions);
+ argv[2] = strdup(buffer);
+ if (!argv[2]) {
+ /* TODO: Send a PADT */
+ exit(EXIT_FAILURE);
+ }
+
+ argv[3] = "file";
+ argv[4] = PPPOE_SERVER_OPTIONS;
+
+ snprintf(buffer, SMALLBUF, "%d.%d.%d.%d:%d.%d.%d.%d",
+ (int) LocalIP[0], (int) LocalIP[1],
+ (int) LocalIP[2], (int) LocalIP[3],
+ (int) session->ip[0], (int) session->ip[1],
+ (int) session->ip[2], (int) session->ip[3]);
+ syslog(LOG_INFO,
+ "Session %d created for client %02x:%02x:%02x:%02x:%02x:%02x (%d.%d.%d.%d)",
+ ntohs(session->sess),
+ session->eth[0], session->eth[1], session->eth[2],
+ session->eth[3], session->eth[4], session->eth[5],
+ (int) session->ip[0], (int) session->ip[1],
+ (int) session->ip[2], (int) session->ip[3]);
+ argv[5] = buffer; /* No need for strdup -- about to execv! */
+ argv[6] = "nodetach";
+ argv[7] = "noaccomp";
+ argv[8] = "nobsdcomp";
+ argv[9] = "nodeflate";
+ argv[10] = "nopcomp";
+ argv[11] = "novj";
+ argv[12] = "novjccomp";
+ argv[13] = "default-asyncmap";
+ if (Synchronous) {
+ argv[14] = "sync";
+ argv[15] = NULL;
+ } else {
+ argv[14] = NULL;
+ }
+
+ execv(PPPD_PATH, argv);
+ exit(EXIT_FAILURE);
+}
+
+/**********************************************************************
+*%FUNCTION: startPPPDLinuxKernelMode
+*%ARGUMENTS:
+* session -- client session record
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Starts PPPD for kernel-mode PPPoE on Linux
+***********************************************************************/
+void
+startPPPDLinuxKernelMode(struct ClientSession *session)
+{
+ /* Leave some room */
+ char *argv[20];
+
+ char buffer[SMALLBUF];
+
+ argv[0] = "pppd";
+ argv[1] = "plugin";
+ argv[2] = PLUGIN_PATH;
+ argv[3] = IfName;
+ snprintf(buffer, SMALLBUF, "%d:%02x:%02x:%02x:%02x:%02x:%02x",
+ ntohs(session->sess),
+ session->eth[0], session->eth[1], session->eth[2],
+ session->eth[3], session->eth[4], session->eth[5]);
+ argv[4] = "rp_pppoe_sess";
+ argv[5] = strdup(buffer);
+ if (!argv[5]) {
+ /* TODO: Send a PADT */
+ exit(EXIT_FAILURE);
+ }
+ argv[6] = "file";
+ argv[7] = PPPOE_SERVER_OPTIONS;
+
+ snprintf(buffer, SMALLBUF, "%d.%d.%d.%d:%d.%d.%d.%d",
+ (int) LocalIP[0], (int) LocalIP[1],
+ (int) LocalIP[2], (int) LocalIP[3],
+ (int) session->ip[0], (int) session->ip[1],
+ (int) session->ip[2], (int) session->ip[3]);
+ syslog(LOG_INFO,
+ "Session %d created for client %02x:%02x:%02x:%02x:%02x:%02x (%d.%d.%d.%d)",
+ ntohs(session->sess),
+ session->eth[0], session->eth[1], session->eth[2],
+ session->eth[3], session->eth[4], session->eth[5],
+ (int) session->ip[0], (int) session->ip[1],
+ (int) session->ip[2], (int) session->ip[3]);
+ argv[8] = buffer;
+ argv[9] = "nodetach";
+ argv[10] = "noaccomp";
+ argv[11] = "nobsdcomp";
+ argv[12] = "nodeflate";
+ argv[13] = "nopcomp";
+ argv[14] = "novj";
+ argv[15] = "novjccomp";
+ argv[16] = "default-asyncmap";
+ argv[17] = NULL;
+ execv(PPPD_PATH, argv);
+ exit(EXIT_FAILURE);
+}
+
+/**********************************************************************
+*%FUNCTION: startPPPD
+*%ARGUMENTS:
+* session -- client session record
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Starts PPPD
+***********************************************************************/
+void
+startPPPD(struct ClientSession *session)
+{
+ if (UseLinuxKernelModePPPoE) startPPPDLinuxKernelMode(session);
+ else startPPPDUserMode(session);
+}
+
diff --git a/mdk-stage1/rp-pppoe/src/pppoe-sniff.c b/mdk-stage1/rp-pppoe/src/pppoe-sniff.c
new file mode 100644
index 000000000..8a11b05c2
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/src/pppoe-sniff.c
@@ -0,0 +1,258 @@
+/***********************************************************************
+*
+* pppoe-sniff.c
+*
+* Sniff a network for likely-looking PPPoE frames and deduce the value
+* to supply to PPPOE_EXTRA in /etc/ppp/pppoe.conf. USE AT YOUR OWN RISK.
+*
+* Copyright (C) 2000 by Roaring Penguin Software Inc.
+*
+* This program may be distributed according to the terms of the GNU
+* General Public License, version 2 or (at your option) any later version.
+*
+***********************************************************************/
+
+static char const RCSID[] =
+"$Id: pppoe-sniff.c 195724 2001-06-11 13:49:39Z gc $";
+
+#include "pppoe.h"
+
+#ifdef HAVE_GETOPT_H
+#include <getopt.h>
+#endif
+
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+
+#ifdef USE_DLPI
+#include <sys/dlpi.h>
+/* function declarations */
+void dlpromisconreq( int fd, u_long level);
+void dlokack(int fd, char *bufp);
+#endif
+
+/* Default interface if no -I option given */
+#define DEFAULT_IF "eth0"
+
+/* Global vars */
+int SeenPADR = 0;
+int SeenSess = 0;
+UINT16_t SessType, DiscType;
+
+char *IfName = NULL; /* Interface name */
+char *ServiceName = NULL; /* Service name */
+
+/**********************************************************************
+*%FUNCTION: parsePADRTags
+*%ARGUMENTS:
+* type -- tag type
+* len -- tag length
+* data -- tag data
+* extra -- extra user data.
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Picks interesting tags out of a PADR packet
+***********************************************************************/
+void
+parsePADRTags(UINT16_t type, UINT16_t len, unsigned char *data,
+ void *extra)
+{
+ switch(type) {
+ case TAG_SERVICE_NAME:
+ ServiceName = malloc(len+1);
+ if (ServiceName) {
+ memcpy(ServiceName, data, len);
+ ServiceName[len] = 0;
+ }
+ break;
+ }
+}
+
+/**********************************************************************
+*%FUNCTION: fatalSys
+*%ARGUMENTS:
+* str -- error message
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Prints a message plus the errno value to stderr and exits.
+***********************************************************************/
+void
+fatalSys(char const *str)
+{
+ char buf[1024];
+ sprintf(buf, "%.256s: %.256s", str, strerror(errno));
+ printErr(buf);
+ exit(1);
+}
+
+/**********************************************************************
+*%FUNCTION: rp_fatal
+*%ARGUMENTS:
+* str -- error message
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Prints a message to stderr and syslog and exits.
+***********************************************************************/
+void
+rp_fatal(char const *str)
+{
+ printErr(str);
+ exit(1);
+}
+
+/**********************************************************************
+*%FUNCTION: usage
+*%ARGUMENTS:
+* argv0 -- program name
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Prints usage information and exits.
+***********************************************************************/
+void
+usage(char const *argv0)
+{
+ fprintf(stderr, "Usage: %s [options]\n", argv0);
+ fprintf(stderr, "Options:\n");
+ fprintf(stderr, " -I if_name -- Specify interface (default %s.)\n",
+ DEFAULT_IF);
+ fprintf(stderr, " -V -- Print version and exit.\n");
+ fprintf(stderr, "\nPPPoE Version %s, Copyright (C) 2000 Roaring Penguin Software Inc.\n", VERSION);
+ fprintf(stderr, "PPPoE comes with ABSOLUTELY NO WARRANTY.\n");
+ fprintf(stderr, "This is free software, and you are welcome to redistribute it under the terms\n");
+ fprintf(stderr, "of the GNU General Public License, version 2 or any later version.\n");
+ fprintf(stderr, "http://www.roaringpenguin.com\n");
+ exit(0);
+}
+
+#if !defined(USE_LINUX_PACKET) && !defined(USE_DLPI)
+
+int
+main()
+{
+ fprintf(stderr, "Sorry, pppoe-sniff works only on Linux.\n");
+ return 1;
+}
+
+#else
+
+/**********************************************************************
+*%FUNCTION: main
+*%ARGUMENTS:
+* argc, argv -- count and values of command-line arguments
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Main program
+***********************************************************************/
+int
+main(int argc, char *argv[])
+{
+ int opt;
+ int sock;
+ PPPoEPacket pkt;
+ int size;
+#ifdef USE_DLPI
+ long buf[MAXDLBUF];
+#endif
+
+ while((opt = getopt(argc, argv, "I:V")) != -1) {
+ switch(opt) {
+ case 'I':
+ SET_STRING(IfName, optarg);
+ break;
+ case 'V':
+ printf("pppoe-sniff: Roaring Penguin PPPoE Version %s\n", VERSION);
+ exit(0);
+ default:
+ usage(argv[0]);
+ }
+ }
+
+ /* Pick a default interface name */
+ if (!IfName) {
+ IfName = DEFAULT_IF;
+ }
+
+ /* Open the interface */
+#ifdef USE_DLPI
+ sock = openInterface(IfName, Eth_PPPOE_Discovery, NULL);
+ dlpromisconreq(sock, DL_PROMISC_PHYS);
+ dlokack(sock, (char *)buf);
+ dlpromisconreq(sock, DL_PROMISC_SAP);
+ dlokack(sock, (char *)buf);
+#else
+
+ sock = openInterface(IfName, ETH_P_ALL, NULL);
+
+#endif
+
+ /* We assume interface is in promiscuous mode -- use ifconfig to
+ ensure this */
+ fprintf(stderr, "Sniffing for PADR. Start your connection on another machine...\n");
+ while (!SeenPADR) {
+ if (receivePacket(sock, &pkt, &size) < 0) continue;
+ if (ntohs(pkt.length) + HDR_SIZE > size) continue;
+ if (pkt.ver != 1 || pkt.type != 1) continue;
+ if (pkt.code != CODE_PADR) continue;
+
+ /* Looks promising... parse it */
+ if (parsePacket(&pkt, parsePADRTags, NULL) < 0) {
+ continue;
+ }
+ DiscType = ntohs(pkt.ethHdr.h_proto);
+ fprintf(stderr, "\nExcellent! Sniffed a likely-looking PADR.\n");
+ break;
+ }
+
+ while (!SeenSess) {
+ if (receivePacket(sock, &pkt, &size) < 0) continue;
+ if (ntohs(pkt.length) + HDR_SIZE > size) continue;
+ if (pkt.ver != 1 || pkt.type != 1) continue;
+ if (pkt.code != CODE_SESS) continue;
+
+ /* Cool! */
+ SessType = ntohs(pkt.ethHdr.h_proto);
+ break;
+ }
+
+ fprintf(stderr, "Wonderful! Sniffed a likely-looking session packet.\n");
+ if ((ServiceName == NULL || *ServiceName == 0) &&
+ DiscType == ETH_PPPOE_DISCOVERY &&
+ SessType == ETH_PPPOE_SESSION) {
+ fprintf(stderr, "\nGreat! It looks like a standard PPPoE service.\nYou should not need anything special in the configuration file.\n");
+ return 0;
+ }
+
+ fprintf(stderr, "\nOK, looks like you need something special in the configuration file.\nTry this:\n\n");
+ if (ServiceName != NULL && *ServiceName != 0) {
+ fprintf(stderr, "SERVICENAME='%s'\n", ServiceName);
+ }
+ if (DiscType != ETH_PPPOE_DISCOVERY || SessType != ETH_PPPOE_SESSION) {
+ fprintf(stderr, " PPPOE_EXTRA='-f %x:%x'\n", DiscType, SessType);
+ }
+ return 0;
+}
+
+#endif
+/**********************************************************************
+*%FUNCTION: sysErr
+*%ARGUMENTS:
+* str -- error message
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Prints a message plus the errno value to syslog.
+***********************************************************************/
+void
+sysErr(char const *str)
+{
+ char buf[1024];
+ sprintf(buf, "%.256s: %.256s", str, strerror(errno));
+ printErr(buf);
+}
diff --git a/mdk-stage1/rp-pppoe/src/pppoe.c b/mdk-stage1/rp-pppoe/src/pppoe.c
new file mode 100644
index 000000000..8d383d38c
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/src/pppoe.c
@@ -0,0 +1,834 @@
+/***********************************************************************
+*
+* pppoe.c
+*
+* Implementation of user-space PPPoE redirector for Linux.
+*
+* Copyright (C) 2000-2001 by Roaring Penguin Software Inc.
+*
+* This program may be distributed according to the terms of the GNU
+* General Public License, version 2 or (at your option) any later version.
+*
+***********************************************************************/
+
+static char const RCSID[] =
+"$Id: pppoe.c 224882 2007-07-16 22:03:12Z blino $";
+
+#include "pppoe.h"
+
+#ifdef HAVE_SYSLOG_H
+#include <syslog.h>
+#endif
+
+#ifdef HAVE_GETOPT_H
+#include <getopt.h>
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+
+#ifdef HAVE_SYS_UIO_H
+#include <sys/uio.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef USE_LINUX_PACKET
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#endif
+
+#include <signal.h>
+
+#ifdef HAVE_N_HDLC
+#ifndef N_HDLC
+#include <termios.h>
+#endif
+#endif
+
+/* Default interface if no -I option given */
+#define DEFAULT_IF "eth0"
+
+/* Global variables -- options */
+int optInactivityTimeout = 0; /* Inactivity timeout */
+int optClampMSS = 0; /* Clamp MSS to this value */
+int optSkipSession = 0; /* Perform discovery, print session info
+ and exit */
+
+PPPoEConnection *Connection = NULL; /* Must be global -- used
+ in signal handler */
+/***********************************************************************
+*%FUNCTION: sendSessionPacket
+*%ARGUMENTS:
+* conn -- PPPoE connection
+* packet -- the packet to send
+* len -- length of data to send
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Transmits a session packet to the peer.
+***********************************************************************/
+void
+sendSessionPacket(PPPoEConnection *conn, PPPoEPacket *packet, int len)
+{
+ packet->length = htons(len);
+ if (optClampMSS) {
+ clampMSS(packet, "outgoing", optClampMSS);
+ }
+ if (sendPacket(conn, conn->sessionSocket, packet, len + HDR_SIZE) < 0) {
+ exit(EXIT_FAILURE);
+ }
+ if (conn->debugFile) {
+ dumpPacket(conn->debugFile, packet, "SENT");
+ fprintf(conn->debugFile, "\n");
+ fflush(conn->debugFile);
+ }
+}
+
+#ifdef USE_BPF
+/**********************************************************************
+*%FUNCTION: sessionDiscoveryPacket
+*%ARGUMENTS:
+* packet -- the discovery packet that was received
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* We got a discovery packet during the session stage. This most likely
+* means a PADT.
+*
+* The BSD version uses a single socket for both discovery and session
+* packets. When a packet comes in over the wire once we are in
+* session mode, either syncReadFromEth() or asyncReadFromEth() will
+* have already read the packet and determined it to be a discovery
+* packet before passing it here.
+***********************************************************************/
+void
+sessionDiscoveryPacket(PPPoEPacket *packet)
+{
+ /* Sanity check */
+ if (packet->code != CODE_PADT) {
+ return;
+ }
+
+ /* It's a PADT, all right. Is it for us? */
+ if (packet->session != Connection->session) {
+ /* Nope, ignore it */
+ return;
+ }
+
+ syslog(LOG_INFO,
+ "Session terminated -- received PADT from access concentrator");
+ parsePacket(packet, parseLogErrs, NULL);
+ exit(EXIT_SUCCESS);
+}
+#else
+/**********************************************************************
+*%FUNCTION: sessionDiscoveryPacket
+*%ARGUMENTS:
+* conn -- PPPoE connection
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* We got a discovery packet during the session stage. This most likely
+* means a PADT.
+***********************************************************************/
+void
+sessionDiscoveryPacket(PPPoEConnection *conn)
+{
+ PPPoEPacket packet;
+ int len;
+
+ if (receivePacket(conn->discoverySocket, &packet, &len) < 0) {
+ return;
+ }
+
+ /* Check length */
+ if (ntohs(packet.length) + HDR_SIZE > len) {
+ syslog(LOG_ERR, "Bogus PPPoE length field (%u)",
+ (unsigned int) ntohs(packet.length));
+ return;
+ }
+
+ if (conn->debugFile) {
+ dumpPacket(conn->debugFile, &packet, "RCVD");
+ fprintf(conn->debugFile, "\n");
+ fflush(conn->debugFile);
+ }
+
+ if (packet.code != CODE_PADT) {
+ /* Not PADT; ignore it */
+ return;
+ }
+
+ /* It's a PADT, all right. Is it for us? */
+ if (packet.session != conn->session) {
+ /* Nope, ignore it */
+ return;
+ }
+
+ syslog(LOG_INFO,
+ "Session terminated -- received PADT from peer");
+ parsePacket(&packet, parseLogErrs, NULL);
+ exit(EXIT_SUCCESS);
+}
+#endif /* USE_BPF */
+
+/**********************************************************************
+*%FUNCTION: session
+*%ARGUMENTS:
+* conn -- PPPoE connection info
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Handles the "session" phase of PPPoE
+***********************************************************************/
+void
+session(PPPoEConnection *conn)
+{
+ fd_set readable;
+ PPPoEPacket packet;
+ struct timeval tv;
+ struct timeval *tvp = NULL;
+ int maxFD = 0;
+ int r;
+
+ /* Open a session socket */
+ conn->sessionSocket = openInterface(conn->ifName, Eth_PPPOE_Session, conn->myEth);
+
+ /* Prepare for select() */
+ if (conn->sessionSocket > maxFD) maxFD = conn->sessionSocket;
+ if (conn->discoverySocket > maxFD) maxFD = conn->discoverySocket;
+ maxFD++;
+
+ /* Fill in the constant fields of the packet to save time */
+ memcpy(packet.ethHdr.h_dest, conn->peerEth, ETH_ALEN);
+ memcpy(packet.ethHdr.h_source, conn->myEth, ETH_ALEN);
+ packet.ethHdr.h_proto = htons(Eth_PPPOE_Session);
+ packet.ver = 1;
+ packet.type = 1;
+ packet.code = CODE_SESS;
+ packet.session = conn->session;
+
+ initPPP();
+
+#ifdef USE_BPF
+ /* check for buffered session data */
+ while (BPF_BUFFER_HAS_DATA) {
+ if (conn->synchronous) {
+ syncReadFromEth(conn, conn->sessionSocket, optClampMSS);
+ } else {
+ asyncReadFromEth(conn, conn->sessionSocket, optClampMSS);
+ }
+ }
+#endif
+
+ for (;;) {
+ if (optInactivityTimeout > 0) {
+ tv.tv_sec = optInactivityTimeout;
+ tv.tv_usec = 0;
+ tvp = &tv;
+ }
+ FD_ZERO(&readable);
+ FD_SET(0, &readable); /* ppp packets come from stdin */
+ if (conn->discoverySocket >= 0) {
+ FD_SET(conn->discoverySocket, &readable);
+ }
+ FD_SET(conn->sessionSocket, &readable);
+ while(1) {
+ r = select(maxFD, &readable, NULL, NULL, tvp);
+ if (r >= 0 || errno != EINTR) break;
+ }
+ if (r < 0) {
+ fatalSys("select (session)");
+ }
+ if (r == 0) { /* Inactivity timeout */
+ syslog(LOG_ERR, "Inactivity timeout... something wicked happened");
+ sendPADT(conn, "RP-PPPoE: Inactivity timeout");
+ exit(EXIT_FAILURE);
+ }
+
+ /* Handle ready sockets */
+ if (FD_ISSET(0, &readable)) {
+ if (conn->synchronous) {
+ syncReadFromPPP(conn, &packet);
+ } else {
+ asyncReadFromPPP(conn, &packet);
+ }
+ }
+
+ if (FD_ISSET(conn->sessionSocket, &readable)) {
+ do {
+ if (conn->synchronous) {
+ syncReadFromEth(conn, conn->sessionSocket, optClampMSS);
+ } else {
+ asyncReadFromEth(conn, conn->sessionSocket, optClampMSS);
+ }
+ } while (BPF_BUFFER_HAS_DATA);
+ }
+
+#ifndef USE_BPF
+ /* BSD uses a single socket, see *syncReadFromEth() */
+ /* for calls to sessionDiscoveryPacket() */
+ if (conn->discoverySocket >= 0) {
+ if (FD_ISSET(conn->discoverySocket, &readable)) {
+ sessionDiscoveryPacket(conn);
+ }
+ }
+#endif
+
+ }
+}
+
+
+/***********************************************************************
+*%FUNCTION: sigPADT
+*%ARGUMENTS:
+* src -- signal received
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* If an established session exists send PADT to terminate from session
+* from our end
+***********************************************************************/
+void
+sigPADT(int src)
+{
+ syslog(LOG_DEBUG,"Received signal %d.",(int)src);
+ sendPADT(Connection, "RP-PPPoE: Received signal");
+ exit(EXIT_SUCCESS);
+}
+
+/**********************************************************************
+*%FUNCTION: usage
+*%ARGUMENTS:
+* argv0 -- program name
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Prints usage information and exits.
+***********************************************************************/
+void
+usage(char const *argv0)
+{
+ fprintf(stderr, "Usage: %s [options]\n", argv0);
+ fprintf(stderr, "Options:\n");
+#ifdef USE_BPF
+ fprintf(stderr, " -I if_name -- Specify interface (REQUIRED)\n");
+#else
+ fprintf(stderr, " -I if_name -- Specify interface (default %s.)\n",
+ DEFAULT_IF);
+#endif
+ fprintf(stderr, " -T timeout -- Specify inactivity timeout in seconds.\n");
+ fprintf(stderr, " -D filename -- Log debugging information in filename.\n");
+ fprintf(stderr, " -V -- Print version and exit.\n");
+ fprintf(stderr, " -A -- Print access concentrator names and exit.\n");
+ fprintf(stderr, " -S name -- Set desired service name.\n");
+ fprintf(stderr, " -C name -- Set desired access concentrator name.\n");
+ fprintf(stderr, " -U -- Use Host-Unique to allow multiple PPPoE sessions.\n");
+ fprintf(stderr, " -s -- Use synchronous PPP encapsulation.\n");
+ fprintf(stderr, " -m MSS -- Clamp incoming and outgoing MSS options.\n");
+ fprintf(stderr, " -p pidfile -- Write process-ID to pidfile.\n");
+ fprintf(stderr, " -e sess:mac -- Skip discovery phase; use existing session.\n");
+ fprintf(stderr, " -n -- Do not open discovery socket.\n");
+ fprintf(stderr, " -k -- Kill a session with PADT (requires -e)\n");
+ fprintf(stderr, " -d -- Perform discovery, print session info and exit.\n");
+ fprintf(stderr, " -f disc:sess -- Set Ethernet frame types (hex).\n");
+ fprintf(stderr, " -h -- Print usage information.\n\n");
+ fprintf(stderr, "PPPoE Version %s, Copyright (C) 2001 Roaring Penguin Software Inc.\n", VERSION);
+ fprintf(stderr, "PPPoE comes with ABSOLUTELY NO WARRANTY.\n");
+ fprintf(stderr, "This is free software, and you are welcome to redistribute it under the terms\n");
+ fprintf(stderr, "of the GNU General Public License, version 2 or any later version.\n");
+ fprintf(stderr, "http://www.roaringpenguin.com\n");
+ exit(EXIT_SUCCESS);
+}
+
+/**********************************************************************
+*%FUNCTION: main
+*%ARGUMENTS:
+* argc, argv -- count and values of command-line arguments
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Main program
+***********************************************************************/
+int
+main(int argc, char *argv[])
+{
+ int opt;
+ int n;
+ unsigned int m[6]; /* MAC address in -e option */
+ unsigned int s; /* Temporary to hold session */
+ FILE *pidfile;
+ unsigned int discoveryType, sessionType;
+
+ PPPoEConnection conn;
+
+#ifdef HAVE_N_HDLC
+ int disc = N_HDLC;
+ long flags;
+#endif
+
+ /* Initialize connection info */
+ memset(&conn, 0, sizeof(conn));
+ conn.discoverySocket = -1;
+ conn.sessionSocket = -1;
+
+ /* For signal handler */
+ Connection = &conn;
+
+ /* Initialize syslog */
+ openlog("pppoe", LOG_PID, LOG_DAEMON);
+
+ while((opt = getopt(argc, argv, "I:VAT:D:hS:C:Usm:np:e:kdf:")) != -1) {
+ switch(opt) {
+ case 'f':
+ if (sscanf(optarg, "%x:%x", &discoveryType, &sessionType) != 2) {
+ fprintf(stderr, "Illegal argument to -f: Should be disc:sess in hex\n");
+ exit(EXIT_FAILURE);
+ }
+ Eth_PPPOE_Discovery = (UINT16_t) discoveryType;
+ Eth_PPPOE_Session = (UINT16_t) sessionType;
+ break;
+ case 'd':
+ optSkipSession = 1;
+ break;
+
+ case 'k':
+ conn.killSession = 1;
+ break;
+
+ case 'n':
+ /* Do not even open a discovery socket -- used when invoked
+ by pppoe-server */
+ conn.noDiscoverySocket = 1;
+ break;
+
+ case 'e':
+ /* Existing session: "sess:xx:yy:zz:aa:bb:cc" where "sess" is
+ session-ID, and xx:yy:zz:aa:bb:cc is MAC-address of peer */
+ n = sscanf(optarg, "%u:%2x:%2x:%2x:%2x:%2x:%2x",
+ &s, &m[0], &m[1], &m[2], &m[3], &m[4], &m[5]);
+ if (n != 7) {
+ fprintf(stderr, "Illegal argument to -e: Should be sess:xx:yy:zz:aa:bb:cc\n");
+ exit(EXIT_FAILURE);
+ }
+
+ /* Copy MAC address of peer */
+ for (n=0; n<6; n++) {
+ conn.peerEth[n] = (unsigned char) m[n];
+ }
+
+ /* Convert session */
+ conn.session = htons(s);
+
+ /* Skip discovery phase! */
+ conn.skipDiscovery = 1;
+ break;
+
+ case 'p':
+ pidfile = fopen(optarg, "w");
+ if (pidfile) {
+ fprintf(pidfile, "%lu\n", (unsigned long) getpid());
+ fclose(pidfile);
+ }
+ break;
+ case 'S':
+ SET_STRING(conn.serviceName, optarg);
+ break;
+ case 'C':
+ SET_STRING(conn.acName, optarg);
+ break;
+ case 's':
+ conn.synchronous = 1;
+ break;
+ case 'U':
+ conn.useHostUniq = 1;
+ break;
+ case 'D':
+ conn.debugFile = fopen(optarg, "w");
+ if (!conn.debugFile) {
+ fprintf(stderr, "Could not open %s: %s\n",
+ optarg, strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+ fprintf(conn.debugFile, "rp-pppoe-%s\n", VERSION);
+ fflush(conn.debugFile);
+ break;
+ case 'T':
+ optInactivityTimeout = (int) strtol(optarg, NULL, 10);
+ if (optInactivityTimeout < 0) {
+ optInactivityTimeout = 0;
+ }
+ break;
+ case 'm':
+ optClampMSS = (int) strtol(optarg, NULL, 10);
+ if (optClampMSS < 536) {
+ fprintf(stderr, "-m: %d is too low (min 536)\n", optClampMSS);
+ exit(EXIT_FAILURE);
+ }
+ if (optClampMSS > 1452) {
+ fprintf(stderr, "-m: %d is too high (max 1452)\n", optClampMSS);
+ exit(EXIT_FAILURE);
+ }
+ break;
+ case 'I':
+ SET_STRING(conn.ifName, optarg);
+ break;
+ case 'V':
+ printf("Roaring Penguin PPPoE Version %s\n", VERSION);
+ exit(EXIT_SUCCESS);
+ case 'A':
+ conn.printACNames = 1;
+ break;
+ case 'h':
+ usage(argv[0]);
+ break;
+ default:
+ usage(argv[0]);
+ }
+ }
+
+ /* Pick a default interface name */
+ if (!conn.ifName) {
+#ifdef USE_BPF
+ fprintf(stderr, "No interface specified (-I option)\n");
+ exit(EXIT_FAILURE);
+#else
+ SET_STRING(conn.ifName, DEFAULT_IF);
+#endif
+ }
+
+ /* Set signal handlers: send PADT on TERM, HUP and INT */
+ if (!conn.printACNames) {
+ signal(SIGTERM, sigPADT);
+ signal(SIGHUP, sigPADT);
+ signal(SIGINT, sigPADT);
+
+#ifdef HAVE_N_HDLC
+ if (conn.synchronous) {
+ if (ioctl(0, TIOCSETD, &disc) < 0) {
+ printErr("Unable to set line discipline to N_HDLC -- synchronous mode probably will fail");
+ } else {
+ syslog(LOG_INFO,
+ "Changed pty line discipline to N_HDLC for synchronous mode");
+ }
+ /* There is a bug in Linux's select which returns a descriptor
+ * as readable if N_HDLC line discipline is on, even if
+ * it isn't really readable. This return happens only when
+ * select() times out. To avoid blocking forever in read(),
+ * make descriptor 0 non-blocking */
+ flags = fcntl(0, F_GETFL);
+ if (flags < 0) fatalSys("fcntl(F_GETFL)");
+ if (fcntl(0, F_SETFL, (long) flags | O_NONBLOCK) < 0) {
+ fatalSys("fcntl(F_SETFL)");
+ }
+ }
+#endif
+
+ }
+
+ discovery(&conn);
+ if (optSkipSession) {
+ printf("%u:%02x:%02x:%02x:%02x:%02x:%02x\n",
+ ntohs(conn.session),
+ conn.peerEth[0],
+ conn.peerEth[1],
+ conn.peerEth[2],
+ conn.peerEth[3],
+ conn.peerEth[4],
+ conn.peerEth[5]);
+ exit(EXIT_SUCCESS);
+ }
+ session(&conn);
+ return 0;
+}
+
+/**********************************************************************
+*%FUNCTION: fatalSys
+*%ARGUMENTS:
+* str -- error message
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Prints a message plus the errno value to stderr and syslog and exits.
+***********************************************************************/
+void
+fatalSys(char const *str)
+{
+ char buf[1024];
+ sprintf(buf, "%.256s: %.256s", str, strerror(errno));
+ printErr(buf);
+ sendPADT(Connection, "RP-PPPoE: System call error");
+ exit(EXIT_FAILURE);
+}
+
+/**********************************************************************
+*%FUNCTION: sysErr
+*%ARGUMENTS:
+* str -- error message
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Prints a message plus the errno value to syslog.
+***********************************************************************/
+void
+sysErr(char const *str)
+{
+ char buf[1024];
+ sprintf(buf, "%.256s: %.256s", str, strerror(errno));
+ printErr(buf);
+}
+
+/**********************************************************************
+*%FUNCTION: rp_fatal
+*%ARGUMENTS:
+* str -- error message
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Prints a message to stderr and syslog and exits.
+***********************************************************************/
+void
+rp_fatal(char const *str)
+{
+ char buf[1024];
+ printErr(str);
+ sprintf(buf, "RP-PPPoE: %.256s", str);
+ sendPADT(Connection, buf);
+ exit(EXIT_FAILURE);
+}
+
+/**********************************************************************
+*%FUNCTION: asyncReadFromEth
+*%ARGUMENTS:
+* conn -- PPPoE connection info
+* sock -- Ethernet socket
+* clampMss -- if non-zero, do MSS-clamping
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Reads a packet from the Ethernet interface and sends it to async PPP
+* device.
+***********************************************************************/
+void
+asyncReadFromEth(PPPoEConnection *conn, int sock, int clampMss)
+{
+ PPPoEPacket packet;
+ int len;
+ int plen;
+ int i;
+ unsigned char pppBuf[4096];
+ unsigned char *ptr = pppBuf;
+ unsigned char c;
+ UINT16_t fcs;
+ unsigned char header[2] = {FRAME_ADDR, FRAME_CTRL};
+ unsigned char tail[2];
+#ifdef USE_BPF
+ int type;
+#endif
+
+ if (receivePacket(sock, &packet, &len) < 0) {
+ return;
+ }
+
+ /* Check length */
+ if (ntohs(packet.length) + HDR_SIZE > len) {
+ syslog(LOG_ERR, "Bogus PPPoE length field (%u)",
+ (unsigned int) ntohs(packet.length));
+ return;
+ }
+ if (conn->debugFile) {
+ dumpPacket(conn->debugFile, &packet, "RCVD");
+ fprintf(conn->debugFile, "\n");
+ fflush(conn->debugFile);
+ }
+
+#ifdef USE_BPF
+ /* Make sure this is a session packet before processing further */
+ type = etherType(&packet);
+ if (type == Eth_PPPOE_Discovery) {
+ sessionDiscoveryPacket(&packet);
+ } else if (type != Eth_PPPOE_Session) {
+ return;
+ }
+#endif
+
+ /* Sanity check */
+ if (packet.code != CODE_SESS) {
+ syslog(LOG_ERR, "Unexpected packet code %d", (int) packet.code);
+ return;
+ }
+ if (packet.ver != 1) {
+ syslog(LOG_ERR, "Unexpected packet version %d", (int) packet.ver);
+ return;
+ }
+ if (packet.type != 1) {
+ syslog(LOG_ERR, "Unexpected packet type %d", (int) packet.type);
+ return;
+ }
+ if (memcmp(packet.ethHdr.h_source, conn->peerEth, ETH_ALEN)) {
+ /* Not for us -- must be another session. This is not an error,
+ so don't log anything. */
+ return;
+ }
+
+ if (packet.session != conn->session) {
+ /* Not for us -- must be another session. This is not an error,
+ so don't log anything. */
+ return;
+ }
+ plen = ntohs(packet.length);
+ if (plen + HDR_SIZE > len) {
+ syslog(LOG_ERR, "Bogus length field in session packet %d (%d)",
+ (int) plen, (int) len);
+ return;
+ }
+
+ /* Clamp MSS */
+ if (clampMss) {
+ clampMSS(&packet, "incoming", clampMss);
+ }
+
+ /* Compute FCS */
+ fcs = pppFCS16(PPPINITFCS16, header, 2);
+ fcs = pppFCS16(fcs, packet.payload, plen) ^ 0xffff;
+ tail[0] = fcs & 0x00ff;
+ tail[1] = (fcs >> 8) & 0x00ff;
+
+ /* Build a buffer to send to PPP */
+ *ptr++ = FRAME_FLAG;
+ *ptr++ = FRAME_ADDR;
+ *ptr++ = FRAME_ESC;
+ *ptr++ = FRAME_CTRL ^ FRAME_ENC;
+
+ for (i=0; i<plen; i++) {
+ c = packet.payload[i];
+ if (c == FRAME_FLAG || c == FRAME_ADDR || c == FRAME_ESC || c < 0x20) {
+ *ptr++ = FRAME_ESC;
+ *ptr++ = c ^ FRAME_ENC;
+ } else {
+ *ptr++ = c;
+ }
+ }
+ for (i=0; i<2; i++) {
+ c = tail[i];
+ if (c == FRAME_FLAG || c == FRAME_ADDR || c == FRAME_ESC || c < 0x20) {
+ *ptr++ = FRAME_ESC;
+ *ptr++ = c ^ FRAME_ENC;
+ } else {
+ *ptr++ = c;
+ }
+ }
+ *ptr++ = FRAME_FLAG;
+
+ /* Ship it out */
+ if (write(1, pppBuf, (ptr-pppBuf)) < 0) {
+ fatalSys("asyncReadFromEth: write");
+ }
+}
+
+/**********************************************************************
+*%FUNCTION: syncReadFromEth
+*%ARGUMENTS:
+* conn -- PPPoE connection info
+* sock -- Ethernet socket
+* clampMss -- if true, clamp MSS.
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Reads a packet from the Ethernet interface and sends it to sync PPP
+* device.
+***********************************************************************/
+void
+syncReadFromEth(PPPoEConnection *conn, int sock, int clampMss)
+{
+ PPPoEPacket packet;
+ int len;
+ int plen;
+ struct iovec vec[2];
+ unsigned char dummy[2];
+#ifdef USE_BPF
+ int type;
+#endif
+
+ if (receivePacket(sock, &packet, &len) < 0) {
+ return;
+ }
+
+ /* Check length */
+ if (ntohs(packet.length) + HDR_SIZE > len) {
+ syslog(LOG_ERR, "Bogus PPPoE length field (%u)",
+ (unsigned int) ntohs(packet.length));
+ return;
+ }
+ if (conn->debugFile) {
+ dumpPacket(conn->debugFile, &packet, "RCVD");
+ fprintf(conn->debugFile, "\n");
+ fflush(conn->debugFile);
+ }
+
+#ifdef USE_BPF
+ /* Make sure this is a session packet before processing further */
+ type = etherType(&packet);
+ if (type == Eth_PPPOE_Discovery) {
+ sessionDiscoveryPacket(&packet);
+ } else if (type != Eth_PPPOE_Session) {
+ return;
+ }
+#endif
+
+ /* Sanity check */
+ if (packet.code != CODE_SESS) {
+ syslog(LOG_ERR, "Unexpected packet code %d", (int) packet.code);
+ return;
+ }
+ if (packet.ver != 1) {
+ syslog(LOG_ERR, "Unexpected packet version %d", (int) packet.ver);
+ return;
+ }
+ if (packet.type != 1) {
+ syslog(LOG_ERR, "Unexpected packet type %d", (int) packet.type);
+ return;
+ }
+ if (memcmp(packet.ethHdr.h_source, conn->peerEth, ETH_ALEN)) {
+ /* Not for us -- must be another session. This is not an error,
+ so don't log anything. */
+ return;
+ }
+ if (packet.session != conn->session) {
+ /* Not for us -- must be another session. This is not an error,
+ so don't log anything. */
+ return;
+ }
+ plen = ntohs(packet.length);
+ if (plen + HDR_SIZE > len) {
+ syslog(LOG_ERR, "Bogus length field in session packet %d (%d)",
+ (int) plen, (int) len);
+ return;
+ }
+
+ /* Clamp MSS */
+ if (clampMss) {
+ clampMSS(&packet, "incoming", clampMss);
+ }
+
+ /* Ship it out */
+ vec[0].iov_base = (void *) dummy;
+ dummy[0] = FRAME_ADDR;
+ dummy[1] = FRAME_CTRL;
+ vec[0].iov_len = 2;
+ vec[1].iov_base = (void *) packet.payload;
+ vec[1].iov_len = plen;
+
+ if (writev(1, vec, 2) < 0) {
+ fatalSys("syncReadFromEth: write");
+ }
+}
+
diff --git a/mdk-stage1/rp-pppoe/src/pppoe.h b/mdk-stage1/rp-pppoe/src/pppoe.h
new file mode 100644
index 000000000..21e58ca99
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/src/pppoe.h
@@ -0,0 +1,331 @@
+/***********************************************************************
+*
+* pppoe.h
+*
+* Declaration of various PPPoE constants
+*
+* Copyright (C) 2000 Roaring Penguin Software Inc.
+*
+* This program may be distributed according to the terms of the GNU
+* General Public License, version 2 or (at your option) any later version.
+*
+* $Id: pppoe.h 195724 2001-06-11 13:49:39Z gc $
+*
+***********************************************************************/
+
+#ifdef __sun__
+#define __EXTENSIONS__
+#endif
+
+#include "config.h"
+
+#if defined(HAVE_NETPACKET_PACKET_H) || defined(HAVE_LINUX_IF_PACKET_H)
+#define _POSIX_SOURCE 1 /* For sigaction defines */
+#endif
+
+#include <stdio.h> /* For FILE */
+#include <sys/types.h> /* For pid_t */
+
+/* How do we access raw Ethernet devices? */
+#undef USE_LINUX_PACKET
+#undef USE_BPF
+
+#if defined(HAVE_NETPACKET_PACKET_H) || defined(HAVE_LINUX_IF_PACKET_H)
+#define USE_LINUX_PACKET 1
+#elif defined(HAVE_NET_BPF_H)
+#define USE_BPF 1
+#elif defined(HAVE_SYS_DLPI_H)
+#define USE_DLPI
+#endif
+
+/* Sanity check */
+#if !defined(USE_BPF) && !defined(USE_LINUX_PACKET) && !defined(USE_DLPI)
+#error Unknown method for accessing raw Ethernet frames
+#endif
+
+#ifdef HAVE_SYS_CDEFS_H
+#include <sys/cdefs.h>
+#endif
+
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+
+/* Ugly header files on some Linux boxes... */
+#if defined(HAVE_LINUX_IF_H)
+#include <linux/if.h>
+#elif defined(HAVE_NET_IF_H)
+#include <net/if.h>
+#endif
+
+#ifdef HAVE_NET_IF_TYPES_H
+#include <net/if_types.h>
+#endif
+
+#ifdef HAVE_NET_IF_DL_H
+#include <net/if_dl.h>
+#endif
+
+/* I'm not sure why this is needed... I do not have OpenBSD */
+#if defined(__OpenBSD__)
+#include <net/ppp_defs.h>
+#include <net/if_ppp.h>
+#endif
+
+#ifdef USE_BPF
+extern int bpfSize;
+struct PPPoEPacketStruct;
+void sessionDiscoveryPacket(struct PPPoEPacketStruct *packet);
+#define BPF_BUFFER_IS_EMPTY (bpfSize <= 0)
+#define BPF_BUFFER_HAS_DATA (bpfSize > 0)
+#define ethhdr ether_header
+#define h_dest ether_dhost
+#define h_source ether_shost
+#define h_proto ether_type
+#define ETH_DATA_LEN ETHERMTU
+#define ETH_ALEN ETHER_ADDR_LEN
+#else
+#undef USE_BPF
+#define BPF_BUFFER_IS_EMPTY 1
+#define BPF_BUFFER_HAS_DATA 0
+#endif
+
+#ifdef USE_DLPI
+#include <sys/ethernet.h>
+#define ethhdr ether_header
+#define ETH_DATA_LEN ETHERMTU
+#define ETH_ALEN ETHERADDRL
+#define h_dest ether_dhost.ether_addr_octet
+#define h_source ether_shost.ether_addr_octet
+#define h_proto ether_type
+
+/* cloned from dltest.h */
+#define MAXDLBUF 8192
+#define MAXDLADDR 1024
+#define MAXWAIT 15
+#define OFFADDR(s, n) (u_char*)((char*)(s) + (int)(n))
+#define CASERET(s) case s: return ("s")
+
+#endif
+
+/* Define various integer types -- assumes a char is 8 bits */
+#if SIZEOF_UNSIGNED_SHORT == 2
+typedef unsigned short UINT16_t;
+#elif SIZEOF_UNSIGNED_INT == 2
+typedef unsigned int UINT16_t;
+#else
+#error Could not find a 16-bit integer type
+#endif
+
+#if SIZEOF_UNSIGNED_SHORT == 4
+typedef unsigned short UINT32_t;
+#elif SIZEOF_UNSIGNED_INT == 4
+typedef unsigned int UINT32_t;
+#elif SIZEOF_UNSIGNED_LONG == 4
+typedef unsigned long UINT32_t;
+#else
+#error Could not find a 16-bit integer type
+#endif
+
+#ifdef HAVE_LINUX_IF_ETHER_H
+#include <linux/if_ether.h>
+#endif
+
+#include <netinet/in.h>
+
+#ifdef HAVE_NETINET_IF_ETHER_H
+#include <sys/types.h>
+
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#ifndef HAVE_SYS_DLPI_H
+#include <netinet/if_ether.h>
+#endif
+#endif
+
+
+
+/* Ethernet frame types according to RFC 2516 */
+#define ETH_PPPOE_DISCOVERY 0x8863
+#define ETH_PPPOE_SESSION 0x8864
+
+/* But some brain-dead peers disobey the RFC, so frame types are variables */
+extern UINT16_t Eth_PPPOE_Discovery;
+extern UINT16_t Eth_PPPOE_Session;
+
+/* PPPoE codes */
+#define CODE_PADI 0x09
+#define CODE_PADO 0x07
+#define CODE_PADR 0x19
+#define CODE_PADS 0x65
+#define CODE_PADT 0xA7
+#define CODE_SESS 0x00
+
+/* PPPoE Tags */
+#define TAG_END_OF_LIST 0x0000
+#define TAG_SERVICE_NAME 0x0101
+#define TAG_AC_NAME 0x0102
+#define TAG_HOST_UNIQ 0x0103
+#define TAG_AC_COOKIE 0x0104
+#define TAG_VENDOR_SPECIFIC 0x0105
+#define TAG_RELAY_SESSION_ID 0x0110
+#define TAG_SERVICE_NAME_ERROR 0x0201
+#define TAG_AC_SYSTEM_ERROR 0x0202
+#define TAG_GENERIC_ERROR 0x0203
+
+/* Discovery phase states */
+#define STATE_SENT_PADI 0
+#define STATE_RECEIVED_PADO 1
+#define STATE_SENT_PADR 2
+#define STATE_SESSION 3
+#define STATE_TERMINATED 4
+
+/* How many PADI/PADS attempts? */
+#define MAX_PADI_ATTEMPTS 3
+
+/* Initial timeout for PADO/PADS */
+#define PADI_TIMEOUT 5
+
+/* States for scanning PPP frames */
+#define STATE_WAITFOR_FRAME_ADDR 0
+#define STATE_DROP_PROTO 1
+#define STATE_BUILDING_PACKET 2
+
+/* Special PPP frame characters */
+#define FRAME_ESC 0x7D
+#define FRAME_FLAG 0x7E
+#define FRAME_ADDR 0xFF
+#define FRAME_CTRL 0x03
+#define FRAME_ENC 0x20
+
+#define IPV4ALEN 4
+#define SMALLBUF 256
+
+/* A PPPoE Packet, including Ethernet headers */
+typedef struct PPPoEPacketStruct {
+ struct ethhdr ethHdr; /* Ethernet header */
+#ifdef PACK_BITFIELDS_REVERSED
+ unsigned int type:4; /* PPPoE Type (must be 1) */
+ unsigned int ver:4; /* PPPoE Version (must be 1) */
+#else
+ unsigned int ver:4; /* PPPoE Version (must be 1) */
+ unsigned int type:4; /* PPPoE Type (must be 1) */
+#endif
+ unsigned int code:8; /* PPPoE code */
+ unsigned int session:16; /* PPPoE session */
+ unsigned int length:16; /* Payload length */
+ unsigned char payload[ETH_DATA_LEN]; /* A bit of room to spare */
+} PPPoEPacket;
+
+/* Header size of a PPPoE packet */
+#define PPPOE_OVERHEAD 6 /* type, code, session, length */
+#define HDR_SIZE (sizeof(struct ethhdr) + PPPOE_OVERHEAD)
+#define MAX_PPPOE_PAYLOAD (ETH_DATA_LEN - PPPOE_OVERHEAD)
+#define MAX_PPPOE_MTU (MAX_PPPOE_PAYLOAD - 2)
+
+/* PPPoE Tag */
+
+typedef struct PPPoETagStruct {
+ unsigned int type:16; /* tag type */
+ unsigned int length:16; /* Length of payload */
+ unsigned char payload[ETH_DATA_LEN]; /* A LOT of room to spare */
+} PPPoETag;
+/* Header size of a PPPoE tag */
+#define TAG_HDR_SIZE 4
+
+/* Chunk to read from stdin */
+#define READ_CHUNK 4096
+
+/* Function passed to parsePacket */
+typedef void ParseFunc(UINT16_t type,
+ UINT16_t len,
+ unsigned char *data,
+ void *extra);
+
+/* Structures used by PPPoE server */
+struct ClientSession {
+ pid_t pid; /* PID of child handling session */
+ unsigned char ip[IPV4ALEN]; /* IP address of peer */
+ UINT16_t sess; /* Session number */
+ unsigned char eth[ETH_ALEN]; /* Peer's Ethernet address */
+ int recvdPADT; /* Peer sent a PADT */
+};
+
+#define PPPINITFCS16 0xffff /* Initial FCS value */
+
+/* Keep track of the state of a connection -- collect everything in
+ one spot */
+
+typedef struct PPPoEConnectionStruct {
+ int discoveryState; /* Where we are in discovery */
+ int discoverySocket; /* Raw socket for discovery frames */
+ int sessionSocket; /* Raw socket for session frames */
+ unsigned char myEth[ETH_ALEN]; /* My MAC address */
+ unsigned char peerEth[ETH_ALEN]; /* Peer's MAC address */
+ UINT16_t session; /* Session ID */
+ char *ifName; /* Interface name */
+ char *serviceName; /* Desired service name, if any */
+ char *acName; /* Desired AC name, if any */
+ int synchronous; /* Use synchronous PPP */
+ int useHostUniq; /* Use Host-Uniq tag */
+ int printACNames; /* Just print AC names */
+ int skipDiscovery; /* Skip discovery */
+ int noDiscoverySocket; /* Don't even open discovery socket */
+ int killSession; /* Kill session and exit */
+ FILE *debugFile; /* Debug file for dumping packets */
+ int numPADOs; /* Number of PADO packets received */
+ PPPoETag cookie; /* We have to send this if we get it */
+ PPPoETag relayId; /* Ditto */
+} PPPoEConnection;
+
+/* Structure used to determine acceptable PADO or PADS packet */
+struct PacketCriteria {
+ PPPoEConnection *conn;
+ int acNameOK;
+ int serviceNameOK;
+};
+
+/* Function Prototypes */
+UINT16_t etherType(PPPoEPacket *packet);
+int openInterface(char const *ifname, UINT16_t type, unsigned char *hwaddr);
+int sendPacket(PPPoEConnection *conn, int sock, PPPoEPacket *pkt, int size);
+int receivePacket(int sock, PPPoEPacket *pkt, int *size);
+void fatalSys(char const *str);
+void rp_fatal(char const *str);
+void printErr(char const *str);
+void sysErr(char const *str);
+void dumpPacket(FILE *fp, PPPoEPacket *packet, char const *dir);
+void dumpHex(FILE *fp, unsigned char const *buf, int len);
+int parsePacket(PPPoEPacket *packet, ParseFunc *func, void *extra);
+void parseLogErrs(UINT16_t typ, UINT16_t len, unsigned char *data, void *xtra);
+void syncReadFromPPP(PPPoEConnection *conn, PPPoEPacket *packet);
+void asyncReadFromPPP(PPPoEConnection *conn, PPPoEPacket *packet);
+void asyncReadFromEth(PPPoEConnection *conn, int sock, int clampMss);
+void syncReadFromEth(PPPoEConnection *conn, int sock, int clampMss);
+char *strDup(char const *str);
+void sendPADT(PPPoEConnection *conn, char const *msg);
+void sendSessionPacket(PPPoEConnection *conn,
+ PPPoEPacket *packet, int len);
+void initPPP(void);
+void clampMSS(PPPoEPacket *packet, char const *dir, int clampMss);
+UINT16_t computeTCPChecksum(unsigned char *ipHdr, unsigned char *tcpHdr);
+UINT16_t pppFCS16(UINT16_t fcs, unsigned char *cp, int len);
+void discovery(PPPoEConnection *conn);
+unsigned char *findTag(PPPoEPacket *packet, UINT16_t tagType,
+ PPPoETag *tag);
+
+#define SET_STRING(var, val) do { if (var) free(var); var = strDup(val); } while(0);
+
+#define CHECK_ROOM(cursor, start, len) \
+do {\
+ if (((cursor)-(start))+(len) > MAX_PPPOE_PAYLOAD) { \
+ syslog(LOG_ERR, "Would create too-long packet"); \
+ return; \
+ } \
+} while(0)
+
+/* True if Ethernet address is broadcast or multicast */
+#define NOT_UNICAST(e) ((e[0] & 0x01) != 0)
+#define BROADCAST(e) ((e[0] & e[1] & e[2] & e[3] & e[4] & e[5]) == 0xFF)
+#define NOT_BROADCAST(e) ((e[0] & e[1] & e[2] & e[3] & e[4] & e[5]) != 0xFF)
diff --git a/mdk-stage1/rp-pppoe/src/relay.c b/mdk-stage1/rp-pppoe/src/relay.c
new file mode 100644
index 000000000..c42669b05
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/src/relay.c
@@ -0,0 +1,1541 @@
+/***********************************************************************
+*
+* relay.c
+*
+* Implementation of PPPoE relay
+*
+* Copyright (C) 2001 Roaring Penguin Software Inc.
+*
+* This program may be distributed according to the terms of the GNU
+* General Public License, version 2 or (at your option) any later version.
+*
+* $Id: relay.c 195724 2001-06-11 13:49:39Z gc $
+*
+***********************************************************************/
+static char const RCSID[] =
+"$Id: relay.c 195724 2001-06-11 13:49:39Z gc $";
+
+#define _GNU_SOURCE 1 /* For SA_RESTART */
+
+#include "relay.h"
+
+#include <signal.h>
+
+#ifdef HAVE_SYSLOG_H
+#include <syslog.h>
+#endif
+
+#ifdef HAVE_GETOPT_H
+#include <getopt.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+
+#ifdef HAVE_SYS_UIO_H
+#include <sys/uio.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+
+/* Interfaces (max MAX_INTERFACES) */
+PPPoEInterface Interfaces[MAX_INTERFACES];
+int NumInterfaces;
+
+/* Relay info */
+int NumSessions;
+int MaxSessions;
+PPPoESession *AllSessions;
+PPPoESession *FreeSessions;
+PPPoESession *ActiveSessions;
+
+SessionHash *AllHashes;
+SessionHash *FreeHashes;
+SessionHash *Buckets[HASHTAB_SIZE];
+
+volatile unsigned int Epoch = 0;
+volatile unsigned int CleanCounter = 0;
+
+/* How often to clean up stale sessions? */
+#define MIN_CLEAN_PERIOD 30 /* Minimum period to run cleaner */
+#define TIMEOUT_DIVISOR 20 /* How often to run cleaner per timeout period */
+unsigned int CleanPeriod = MIN_CLEAN_PERIOD;
+
+/* How long a session can be idle before it is cleaned up? */
+unsigned int IdleTimeout = MIN_CLEAN_PERIOD * TIMEOUT_DIVISOR;
+
+/* Pipe for breaking select() to initiate periodic cleaning */
+int CleanPipe[2];
+
+/* Our relay: if_index followed by peer_mac */
+#define MY_RELAY_TAG_LEN (sizeof(int) + ETH_ALEN)
+
+/* Hack for daemonizing */
+#define CLOSEFD 64
+
+/**********************************************************************
+*%FUNCTION: keepDescriptor
+*%ARGUMENTS:
+* fd -- a file descriptor
+*%RETURNS:
+* 1 if descriptor should NOT be closed during daemonizing; 0 otherwise.
+***********************************************************************/
+static int
+keepDescriptor(int fd)
+{
+ int i;
+ if (fd == CleanPipe[0] || fd == CleanPipe[1]) return 1;
+ for (i=0; i<NumInterfaces; i++) {
+ if (fd == Interfaces[i].discoverySock ||
+ fd == Interfaces[i].sessionSock) return 1;
+ }
+ return 0;
+}
+
+/**********************************************************************
+*%FUNCTION: addTag
+*%ARGUMENTS:
+* packet -- a PPPoE packet
+* tag -- tag to add
+*%RETURNS:
+* -1 if no room in packet; number of bytes added otherwise.
+*%DESCRIPTION:
+* Inserts a tag as the first tag in a PPPoE packet.
+***********************************************************************/
+int
+addTag(PPPoEPacket *packet, PPPoETag const *tag)
+{
+ return insertBytes(packet, packet->payload, tag,
+ ntohs(tag->length) + TAG_HDR_SIZE);
+}
+
+/**********************************************************************
+*%FUNCTION: insertBytes
+*%ARGUMENTS:
+* packet -- a PPPoE packet
+* loc -- location at which to insert bytes of data
+* bytes -- the data to insert
+* len -- length of data to insert
+*%RETURNS:
+* -1 if no room in packet; len otherwise.
+*%DESCRIPTION:
+* Inserts "len" bytes of data at location "loc" in "packet", moving all
+* other data up to make room.
+***********************************************************************/
+int
+insertBytes(PPPoEPacket *packet,
+ unsigned char *loc,
+ void const *bytes,
+ int len)
+{
+ int toMove;
+ int plen = ntohs(packet->length);
+ /* Sanity checks */
+ if (loc < packet->payload ||
+ loc > packet->payload + plen ||
+ len + plen > MAX_PPPOE_PAYLOAD) {
+ return -1;
+ }
+
+ toMove = (packet->payload + plen) - loc;
+ memmove(loc+len, loc, toMove);
+ memcpy(loc, bytes, len);
+ packet->length = htons(plen + len);
+ return len;
+}
+
+/**********************************************************************
+*%FUNCTION: removeBytes
+*%ARGUMENTS:
+* packet -- a PPPoE packet
+* loc -- location at which to remove bytes of data
+* len -- length of data to remove
+*%RETURNS:
+* -1 if there was a problem, len otherwise
+*%DESCRIPTION:
+* Removes "len" bytes of data from location "loc" in "packet", moving all
+* other data down to close the gap
+***********************************************************************/
+int
+removeBytes(PPPoEPacket *packet,
+ unsigned char *loc,
+ int len)
+{
+ int toMove;
+ int plen = ntohs(packet->length);
+ /* Sanity checks */
+ if (len < 0 || len > plen ||
+ loc < packet->payload ||
+ loc + len > packet->payload + plen) {
+ return -1;
+ }
+
+ toMove = ((packet->payload + plen) - loc) - len;
+ memmove(loc, loc+len, toMove);
+ packet->length = htons(plen - len);
+ return len;
+}
+
+/**********************************************************************
+*%FUNCTION: usage
+*%ARGUMENTS:
+* argv0 -- program name
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Prints usage information and exits.
+***********************************************************************/
+void
+usage(char const *argv0)
+{
+ fprintf(stderr, "Usage: %s [options]\n", argv0);
+ fprintf(stderr, "Options:\n");
+ fprintf(stderr, " -S if_name -- Specify interface for PPPoE Server\n");
+ fprintf(stderr, " -C if_name -- Specify interface for PPPoE Client\n");
+ fprintf(stderr, " -B if_name -- Specify interface for both clients and server\n");
+ fprintf(stderr, " -n nsess -- Maxmimum number of sessions to relay\n");
+ fprintf(stderr, " -i timeout -- Idle timeout in seconds (0 = no timeout)\n");
+ fprintf(stderr, " -F -- Do not fork into background\n");
+ fprintf(stderr, " -h -- Print this help message\n");
+
+ fprintf(stderr, "\nPPPoE Version %s, Copyright (C) 2001 Roaring Penguin Software Inc.\n", VERSION);
+ fprintf(stderr, "PPPoE comes with ABSOLUTELY NO WARRANTY.\n");
+ fprintf(stderr, "This is free software, and you are welcome to redistribute it under the terms\n");
+ fprintf(stderr, "of the GNU General Public License, version 2 or any later version.\n");
+ fprintf(stderr, "http://www.roaringpenguin.com\n");
+ exit(EXIT_SUCCESS);
+}
+
+/**********************************************************************
+*%FUNCTION: main
+*%ARGUMENTS:
+* argc, argv -- usual suspects
+*%RETURNS:
+* EXIT_SUCCESS or EXIT_FAILURE
+*%DESCRIPTION:
+* Main program. Options:
+* -C ifname -- Use interface for PPPoE clients
+* -S ifname -- Use interface for PPPoE servers
+* -B ifname -- Use interface for both clients and servers
+* -n sessions -- Maximum of "n" sessions
+***********************************************************************/
+int
+main(int argc, char *argv[])
+{
+ int opt;
+ int nsess = DEFAULT_SESSIONS;
+ struct sigaction sa;
+ int beDaemon = 1;
+ openlog("pppoe-relay", LOG_PID, LOG_DAEMON);
+
+ while((opt = getopt(argc, argv, "hC:S:B:n:i:F")) != -1) {
+ switch(opt) {
+ case 'h':
+ usage(argv[0]);
+ break;
+ case 'F':
+ beDaemon = 0;
+ break;
+ case 'C':
+ addInterface(optarg, 1, 0);
+ break;
+ case 'S':
+ addInterface(optarg, 0, 1);
+ break;
+ case 'B':
+ addInterface(optarg, 1, 1);
+ break;
+ case 'i':
+ if (sscanf(optarg, "%u", &IdleTimeout) != 1) {
+ fprintf(stderr, "Illegal argument to -i: should be -i timeout\n");
+ exit(EXIT_FAILURE);
+ }
+ CleanPeriod = IdleTimeout / TIMEOUT_DIVISOR;
+ if (CleanPeriod < MIN_CLEAN_PERIOD) CleanPeriod = MIN_CLEAN_PERIOD;
+ break;
+ case 'n':
+ if (sscanf(optarg, "%d", &nsess) != 1) {
+ fprintf(stderr, "Illegal argument to -n: should be -n #sessions\n");
+ exit(EXIT_FAILURE);
+ }
+ if (nsess < 1 || nsess > 65534) {
+ fprintf(stderr, "Illegal argument to -n: must range from 1 to 65534\n");
+ exit(EXIT_FAILURE);
+ }
+ break;
+ default:
+ usage(argv[0]);
+ }
+ }
+
+#ifdef USE_LINUX_PACKET
+#ifndef HAVE_STRUCT_SOCKADDR_LL
+ fprintf(stderr, "The PPPoE relay does not work on Linux 2.0 kernels.\n");
+ exit(EXIT_FAILURE);
+#endif
+#endif
+
+ /* Check that at least two interfaces were defined */
+ if (NumInterfaces < 2) {
+ fprintf(stderr, "%s: Must define at least two interfaces\n",
+ argv[0]);
+ exit(EXIT_FAILURE);
+ }
+
+ /* Make a pipe for the cleaner */
+ if (pipe(CleanPipe) < 0) {
+ fatalSys("pipe");
+ }
+
+ /* Set up alarm handler */
+ sa.sa_handler = alarmHandler;
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = SA_RESTART;
+ if (sigaction(SIGALRM, &sa, NULL) < 0) {
+ fatalSys("sigaction");
+ }
+
+ /* Allocate memory for sessions, etc. */
+ initRelay(nsess);
+
+ /* Daemonize -- UNIX Network Programming, Vol. 1, Stevens */
+ if (beDaemon) {
+ int i;
+ i = fork();
+ if (i < 0) {
+ fatalSys("fork");
+ } else if (i != 0) {
+ /* parent */
+ exit(0);
+ }
+ setsid();
+ signal(SIGHUP, SIG_IGN);
+ i = fork();
+ if (i < 0) {
+ fatalSys("fork");
+ } else if (i != 0) {
+ exit(0);
+ }
+
+ chdir("/");
+ closelog();
+ for (i=0; i<CLOSEFD; i++) {
+ if (!keepDescriptor(i)) {
+ close(i);
+ }
+ }
+ /* We nuked our syslog descriptor... */
+ openlog("pppoe-relay", LOG_PID, LOG_DAEMON);
+ }
+
+ /* Kick off SIGALRM if there is an idle timeout */
+ if (IdleTimeout) alarm(1);
+
+ /* Enter the relay loop */
+ relayLoop();
+
+ /* Shouldn't ever get here... */
+ return EXIT_FAILURE;
+}
+
+/**********************************************************************
+*%FUNCTION: addInterface
+*%ARGUMENTS:
+* ifname -- interface name
+* clientOK -- true if this interface should relay PADI, PADR packets.
+* acOK -- true if this interface should relay PADO, PADS packets.
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Opens an interface; sets up discovery and session sockets.
+***********************************************************************/
+void
+addInterface(char const *ifname,
+ int clientOK,
+ int acOK)
+{
+ PPPoEInterface *i;
+ if (NumInterfaces >= MAX_INTERFACES) {
+ fprintf(stderr, "Too many interfaces (%d max)\n",
+ MAX_INTERFACES);
+ exit(EXIT_FAILURE);
+ }
+ i = &Interfaces[NumInterfaces++];
+ strncpy(i->name, ifname, IFNAMSIZ);
+ i->name[IFNAMSIZ] = 0;
+
+ i->discoverySock = openInterface(ifname, Eth_PPPOE_Discovery, i->mac);
+ i->sessionSock = openInterface(ifname, Eth_PPPOE_Session, NULL);
+ i->clientOK = clientOK;
+ i->acOK = acOK;
+}
+
+/**********************************************************************
+*%FUNCTION: initRelay
+*%ARGUMENTS:
+* nsess -- maximum allowable number of sessions
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Initializes relay hash table and session tables.
+***********************************************************************/
+void
+initRelay(int nsess)
+{
+ int i;
+ NumSessions = 0;
+ MaxSessions = nsess;
+
+ AllSessions = calloc(MaxSessions, sizeof(PPPoESession));
+ if (!AllSessions) {
+ rp_fatal("Unable to allocate memory for PPPoE session table");
+ }
+ AllHashes = calloc(MaxSessions*2, sizeof(SessionHash));
+ if (!AllHashes) {
+ rp_fatal("Unable to allocate memory for PPPoE hash table");
+ }
+
+ /* Initialize sessions in a linked list */
+ AllSessions[0].prev = NULL;
+ if (MaxSessions > 1) {
+ AllSessions[0].next = &AllSessions[1];
+ } else {
+ AllSessions[0].next = NULL;
+ }
+ for (i=1; i<MaxSessions-1; i++) {
+ AllSessions[i].prev = &AllSessions[i-1];
+ AllSessions[i].next = &AllSessions[i+1];
+ }
+ if (MaxSessions > 1) {
+ AllSessions[MaxSessions-1].prev = &AllSessions[MaxSessions-2];
+ AllSessions[MaxSessions-1].next = NULL;
+ }
+
+ FreeSessions = AllSessions;
+ ActiveSessions = NULL;
+
+ /* Initialize session numbers which we hand out */
+ for (i=0; i<MaxSessions; i++) {
+ AllSessions[i].sesNum = htons((UINT16_t) i+1);
+ }
+
+ /* Initialize hashes in a linked list */
+ AllHashes[0].prev = NULL;
+ AllHashes[0].next = &AllHashes[1];
+ for (i=1; i<2*MaxSessions-1; i++) {
+ AllHashes[i].prev = &AllHashes[i-1];
+ AllHashes[i].next = &AllHashes[i+1];
+ }
+ AllHashes[2*MaxSessions-1].prev = &AllHashes[2*MaxSessions-2];
+ AllHashes[2*MaxSessions-1].next = NULL;
+
+ FreeHashes = AllHashes;
+}
+
+/**********************************************************************
+*%FUNCTION: createSession
+*%ARGUMENTS:
+* ac -- Ethernet interface on access-concentrator side
+* cli -- Ethernet interface on client side
+* acMac -- Access concentrator's MAC address
+* cliMac -- Client's MAC address
+* acSess -- Access concentrator's session ID.
+*%RETURNS:
+* PPPoESession structure; NULL if one could not be allocated
+*%DESCRIPTION:
+* Initializes relay hash table and session tables.
+***********************************************************************/
+PPPoESession *
+createSession(PPPoEInterface const *ac,
+ PPPoEInterface const *cli,
+ unsigned char const *acMac,
+ unsigned char const *cliMac,
+ UINT16_t acSes)
+{
+ PPPoESession *sess;
+ SessionHash *acHash, *cliHash;
+
+ if (NumSessions >= MaxSessions) {
+ printErr("Maximum number of sessions reached -- cannot create new session");
+ return NULL;
+ }
+
+ /* Grab a free session */
+ sess = FreeSessions;
+ FreeSessions = sess->next;
+ NumSessions++;
+
+ /* Link it to the active list */
+ sess->next = ActiveSessions;
+ if (sess->next) {
+ sess->next->prev = sess;
+ }
+ ActiveSessions = sess;
+ sess->prev = NULL;
+
+ sess->epoch = Epoch;
+
+ /* Get two hash entries */
+ acHash = FreeHashes;
+ cliHash = acHash->next;
+ FreeHashes = cliHash->next;
+
+ acHash->peer = cliHash;
+ cliHash->peer = acHash;
+
+ sess->acHash = acHash;
+ sess->clientHash = cliHash;
+
+ acHash->interface = ac;
+ cliHash->interface = cli;
+
+ memcpy(acHash->peerMac, acMac, ETH_ALEN);
+ acHash->sesNum = acSes;
+ acHash->ses = sess;
+
+ memcpy(cliHash->peerMac, cliMac, ETH_ALEN);
+ cliHash->sesNum = sess->sesNum;
+ cliHash->ses = sess;
+
+ addHash(acHash);
+ addHash(cliHash);
+
+ /* Log */
+ syslog(LOG_INFO,
+ "Opened session: server=%02x:%02x:%02x:%02x:%02x:%02x(%s:%d), client=%02x:%02x:%02x:%02x:%02x:%02x(%s:%d)",
+ acHash->peerMac[0], acHash->peerMac[1],
+ acHash->peerMac[2], acHash->peerMac[3],
+ acHash->peerMac[4], acHash->peerMac[5],
+ acHash->interface->name,
+ ntohs(acHash->sesNum),
+ cliHash->peerMac[0], cliHash->peerMac[1],
+ cliHash->peerMac[2], cliHash->peerMac[3],
+ cliHash->peerMac[4], cliHash->peerMac[5],
+ cliHash->interface->name,
+ ntohs(cliHash->sesNum));
+
+ return sess;
+}
+
+/**********************************************************************
+*%FUNCTION: freeSession
+*%ARGUMENTS:
+* ses -- session to free
+* msg -- extra message to log on syslog.
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Frees data used by a PPPoE session -- adds hashes and session back
+* to the free list
+***********************************************************************/
+void
+freeSession(PPPoESession *ses, char const *msg)
+{
+ syslog(LOG_INFO,
+ "Closed session: server=%02x:%02x:%02x:%02x:%02x:%02x(%s:%d), client=%02x:%02x:%02x:%02x:%02x:%02x(%s:%d): %s",
+ ses->acHash->peerMac[0], ses->acHash->peerMac[1],
+ ses->acHash->peerMac[2], ses->acHash->peerMac[3],
+ ses->acHash->peerMac[4], ses->acHash->peerMac[5],
+ ses->acHash->interface->name,
+ ntohs(ses->acHash->sesNum),
+ ses->clientHash->peerMac[0], ses->clientHash->peerMac[1],
+ ses->clientHash->peerMac[2], ses->clientHash->peerMac[3],
+ ses->clientHash->peerMac[4], ses->clientHash->peerMac[5],
+ ses->clientHash->interface->name,
+ ntohs(ses->clientHash->sesNum), msg);
+
+ /* Unlink from active sessions */
+ if (ses->prev) {
+ ses->prev->next = ses->next;
+ } else {
+ ActiveSessions = ses->next;
+ }
+ if (ses->next) {
+ ses->next->prev = ses->prev;
+ }
+
+ /* Link onto free list -- this is a singly-linked list, so
+ we do not care about prev */
+ ses->next = FreeSessions;
+ FreeSessions = ses;
+
+ unhash(ses->acHash);
+ unhash(ses->clientHash);
+ NumSessions--;
+}
+
+/**********************************************************************
+*%FUNCTION: unhash
+*%ARGUMENTS:
+* sh -- session hash to free
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Frees a session hash -- takes it out of hash table and puts it on
+* free list.
+***********************************************************************/
+void
+unhash(SessionHash *sh)
+{
+ unsigned int b = hash(sh->peerMac, sh->sesNum) % HASHTAB_SIZE;
+ if (sh->prev) {
+ sh->prev->next = sh->next;
+ } else {
+ Buckets[b] = sh->next;
+ }
+
+ if (sh->next) {
+ sh->next->prev = sh->prev;
+ }
+
+ /* Add to free list (singly-linked) */
+ sh->next = FreeHashes;
+ FreeHashes = sh;
+}
+
+/**********************************************************************
+*%FUNCTION: addHash
+*%ARGUMENTS:
+* sh -- a session hash
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Adds a SessionHash to the hash table
+***********************************************************************/
+void
+addHash(SessionHash *sh)
+{
+ unsigned int b = hash(sh->peerMac, sh->sesNum) % HASHTAB_SIZE;
+ sh->next = Buckets[b];
+ sh->prev = NULL;
+ if (sh->next) {
+ sh->next->prev = sh;
+ }
+ Buckets[b] = sh;
+}
+
+/**********************************************************************
+*%FUNCTION: hash
+*%ARGUMENTS:
+* mac -- an Ethernet address
+* sesNum -- a session number
+*%RETURNS:
+* A hash value combining Ethernet address with session number.
+* Currently very simplistic; we may need to experiment with different
+* hash values.
+***********************************************************************/
+unsigned int
+hash(unsigned char const *mac, UINT16_t sesNum)
+{
+ unsigned int ans1 =
+ ((unsigned int) mac[0]) |
+ (((unsigned int) mac[1]) << 8) |
+ (((unsigned int) mac[2]) << 16) |
+ (((unsigned int) mac[3]) << 24);
+ unsigned int ans2 =
+ ((unsigned int) sesNum) |
+ (((unsigned int) mac[4]) << 16) |
+ (((unsigned int) mac[5]) << 24);
+ return ans1 ^ ans2;
+}
+
+/**********************************************************************
+*%FUNCTION: findSession
+*%ARGUMENTS:
+* mac -- an Ethernet address
+* sesNum -- a session number
+*%RETURNS:
+* The session hash for peer address "mac", session number sesNum
+***********************************************************************/
+SessionHash *
+findSession(unsigned char const *mac, UINT16_t sesNum)
+{
+ unsigned int b = hash(mac, sesNum) % HASHTAB_SIZE;
+ SessionHash *sh = Buckets[b];
+ while(sh) {
+ if (!memcmp(mac, sh->peerMac, ETH_ALEN) && sesNum == sh->sesNum) {
+ return sh;
+ }
+ sh = sh->next;
+ }
+ return NULL;
+}
+
+/**********************************************************************
+*%FUNCTION: fatalSys
+*%ARGUMENTS:
+* str -- error message
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Prints a message plus the errno value to stderr and syslog and exits.
+***********************************************************************/
+void
+fatalSys(char const *str)
+{
+ char buf[1024];
+ sprintf(buf, "%.256s: %.256s", str, strerror(errno));
+ printErr(buf);
+ exit(EXIT_FAILURE);
+}
+
+/**********************************************************************
+*%FUNCTION: sysErr
+*%ARGUMENTS:
+* str -- error message
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Prints a message plus the errno value to syslog.
+***********************************************************************/
+void
+sysErr(char const *str)
+{
+ char buf[1024];
+ sprintf(buf, "%.256s: %.256s", str, strerror(errno));
+ printErr(buf);
+}
+
+/**********************************************************************
+*%FUNCTION: rp_fatal
+*%ARGUMENTS:
+* str -- error message
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Prints a message to stderr and syslog and exits.
+***********************************************************************/
+void
+rp_fatal(char const *str)
+{
+ printErr(str);
+ exit(EXIT_FAILURE);
+}
+
+/**********************************************************************
+*%FUNCTION: relayLoop
+*%ARGUMENTS:
+* None
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Runs the relay loop. This function never returns
+***********************************************************************/
+void
+relayLoop()
+{
+ fd_set readable, readableCopy;
+ int maxFD;
+ int i, r;
+ int sock;
+
+ /* Build the select set */
+ FD_ZERO(&readable);
+ maxFD = 0;
+ for (i=0; i<NumInterfaces; i++) {
+ sock = Interfaces[i].discoverySock;
+ if (sock > maxFD) maxFD = sock;
+ FD_SET(sock, &readable);
+ sock = Interfaces[i].sessionSock;
+ if (sock > maxFD) maxFD = sock;
+ FD_SET(sock, &readable);
+ if (CleanPipe[0] > maxFD) maxFD = CleanPipe[0];
+ FD_SET(CleanPipe[0], &readable);
+ }
+ maxFD++;
+ for(;;) {
+ readableCopy = readable;
+ for(;;) {
+ r = select(maxFD, &readableCopy, NULL, NULL, NULL);
+ if (r >= 0 || errno != EINTR) break;
+ }
+ if (r < 0) {
+ sysErr("select (relayLoop)");
+ continue;
+ }
+
+ /* Handle session packets first */
+ for (i=0; i<NumInterfaces; i++) {
+ if (FD_ISSET(Interfaces[i].sessionSock, &readableCopy)) {
+ relayGotSessionPacket(&Interfaces[i]);
+ }
+ }
+
+ /* Now handle discovery packets */
+ for (i=0; i<NumInterfaces; i++) {
+ if (FD_ISSET(Interfaces[i].discoverySock, &readableCopy)) {
+ relayGotDiscoveryPacket(&Interfaces[i]);
+ }
+ }
+
+ /* Handle the session-cleaning process */
+ if (FD_ISSET(CleanPipe[0], &readableCopy)) {
+ char dummy;
+ CleanCounter = 0;
+ read(CleanPipe[0], &dummy, 1);
+ if (IdleTimeout) cleanSessions();
+ }
+ }
+}
+
+/**********************************************************************
+*%FUNCTION: relayGotDiscoveryPacket
+*%ARGUMENTS:
+* iface -- interface on which packet is waiting
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Receives and processes a discovery packet.
+***********************************************************************/
+void
+relayGotDiscoveryPacket(PPPoEInterface const *iface)
+{
+ PPPoEPacket packet;
+ int size;
+
+ if (receivePacket(iface->discoverySock, &packet, &size) < 0) {
+ return;
+ }
+ /* Ignore unknown code/version */
+ if (packet.ver != 1 || packet.type != 1) {
+ return;
+ }
+
+ /* Validate length */
+ if (ntohs(packet.length) + HDR_SIZE > size) {
+ syslog(LOG_ERR, "Bogus PPPoE length field (%u)",
+ (unsigned int) ntohs(packet.length));
+ return;
+ }
+
+ /* Drop Ethernet frame padding */
+ if (size > ntohs(packet.length) + HDR_SIZE) {
+ size = ntohs(packet.length) + HDR_SIZE;
+ }
+
+ switch(packet.code) {
+ case CODE_PADT:
+ relayHandlePADT(iface, &packet, size);
+ break;
+ case CODE_PADI:
+ relayHandlePADI(iface, &packet, size);
+ break;
+ case CODE_PADO:
+ relayHandlePADO(iface, &packet, size);
+ break;
+ case CODE_PADR:
+ relayHandlePADR(iface, &packet, size);
+ break;
+ case CODE_PADS:
+ relayHandlePADS(iface, &packet, size);
+ break;
+ default:
+ syslog(LOG_ERR, "Discovery packet on %s with unknown code %d",
+ iface->name, (int) packet.code);
+ }
+}
+
+/**********************************************************************
+*%FUNCTION: relayGotSessionPacket
+*%ARGUMENTS:
+* iface -- interface on which packet is waiting
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Receives and processes a session packet.
+***********************************************************************/
+void
+relayGotSessionPacket(PPPoEInterface const *iface)
+{
+ PPPoEPacket packet;
+ int size;
+ SessionHash *sh;
+ PPPoESession *ses;
+
+ if (receivePacket(iface->sessionSock, &packet, &size) < 0) {
+ return;
+ }
+
+ /* Ignore unknown code/version */
+ if (packet.ver != 1 || packet.type != 1) {
+ return;
+ }
+
+ /* Must be a session packet */
+ if (packet.code != CODE_SESS) {
+ syslog(LOG_ERR, "Session packet with code %d", (int) packet.code);
+ return;
+ }
+
+ /* Ignore session packets whose destination address isn't ours */
+ if (memcmp(packet.ethHdr.h_dest, iface->mac, ETH_ALEN)) {
+ return;
+ }
+
+ /* Validate length */
+ if (ntohs(packet.length) + HDR_SIZE > size) {
+ syslog(LOG_ERR, "Bogus PPPoE length field (%u)",
+ (unsigned int) ntohs(packet.length));
+ return;
+ }
+
+ /* Drop Ethernet frame padding */
+ if (size > ntohs(packet.length) + HDR_SIZE) {
+ size = ntohs(packet.length) + HDR_SIZE;
+ }
+
+ /* We're in business! Find the hash */
+ sh = findSession(packet.ethHdr.h_source, packet.session);
+ if (!sh) {
+ /* Don't log this. Someone could be running the client and the
+ relay on the same box. */
+ return;
+ }
+
+ /* Relay it */
+ ses = sh->ses;
+ ses->epoch = Epoch;
+ sh = sh->peer;
+ packet.session = sh->sesNum;
+ memcpy(packet.ethHdr.h_source, sh->interface->mac, ETH_ALEN);
+ memcpy(packet.ethHdr.h_dest, sh->peerMac, ETH_ALEN);
+#if 0
+ fprintf(stderr, "Relaying %02x:%02x:%02x:%02x:%02x:%02x(%s:%d) to %02x:%02x:%02x:%02x:%02x:%02x(%s:%d)\n",
+ sh->peer->peerMac[0], sh->peer->peerMac[1], sh->peer->peerMac[2],
+ sh->peer->peerMac[3], sh->peer->peerMac[4], sh->peer->peerMac[5],
+ sh->peer->interface->name, ntohs(sh->peer->sesNum),
+ sh->peerMac[0], sh->peerMac[1], sh->peerMac[2],
+ sh->peerMac[3], sh->peerMac[4], sh->peerMac[5],
+ sh->interface->name, ntohs(sh->sesNum));
+#endif
+ sendPacket(NULL, sh->interface->sessionSock, &packet, size);
+}
+
+/**********************************************************************
+*%FUNCTION: relayHandlePADT
+*%ARGUMENTS:
+* iface -- interface on which packet was received
+* packet -- the PADT packet
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Receives and processes a PADT packet.
+***********************************************************************/
+void
+relayHandlePADT(PPPoEInterface const *iface,
+ PPPoEPacket *packet,
+ int size)
+{
+ SessionHash *sh;
+ PPPoESession *ses;
+
+ sh = findSession(packet->ethHdr.h_source, packet->session);
+ if (!sh) {
+ return;
+ }
+ /* Relay the PADT to the peer */
+ sh = sh->peer;
+ ses = sh->ses;
+ packet->session = sh->sesNum;
+ memcpy(packet->ethHdr.h_source, sh->interface->mac, ETH_ALEN);
+ memcpy(packet->ethHdr.h_dest, sh->peerMac, ETH_ALEN);
+ sendPacket(NULL, sh->interface->sessionSock, packet, size);
+
+ /* Destroy the session */
+ freeSession(ses, "Received PADT");
+}
+
+/**********************************************************************
+*%FUNCTION: relayHandlePADI
+*%ARGUMENTS:
+* iface -- interface on which packet was received
+* packet -- the PADI packet
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Receives and processes a PADI packet.
+***********************************************************************/
+void
+relayHandlePADI(PPPoEInterface const *iface,
+ PPPoEPacket *packet,
+ int size)
+{
+ PPPoETag tag;
+ unsigned char *loc;
+ int i, r;
+
+ int ifIndex;
+
+ /* Can a client legally be behind this interface? */
+ if (!iface->clientOK) {
+ syslog(LOG_ERR,
+ "PADI packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s not permitted",
+ packet->ethHdr.h_source[0],
+ packet->ethHdr.h_source[1],
+ packet->ethHdr.h_source[2],
+ packet->ethHdr.h_source[3],
+ packet->ethHdr.h_source[4],
+ packet->ethHdr.h_source[5],
+ iface->name);
+ return;
+ }
+
+ /* Source address must be unicast */
+ if (NOT_UNICAST(packet->ethHdr.h_source)) {
+ syslog(LOG_ERR,
+ "PADI packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s not from a unicast address",
+ packet->ethHdr.h_source[0],
+ packet->ethHdr.h_source[1],
+ packet->ethHdr.h_source[2],
+ packet->ethHdr.h_source[3],
+ packet->ethHdr.h_source[4],
+ packet->ethHdr.h_source[5],
+ iface->name);
+ return;
+ }
+
+ /* Destination address must be broadcast */
+ if (NOT_BROADCAST(packet->ethHdr.h_dest)) {
+ syslog(LOG_ERR,
+ "PADI packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s not to a broadcast address",
+ packet->ethHdr.h_source[0],
+ packet->ethHdr.h_source[1],
+ packet->ethHdr.h_source[2],
+ packet->ethHdr.h_source[3],
+ packet->ethHdr.h_source[4],
+ packet->ethHdr.h_source[5],
+ iface->name);
+ return;
+ }
+
+ /* Get array index of interface */
+ ifIndex = iface - Interfaces;
+
+ loc = findTag(packet, TAG_RELAY_SESSION_ID, &tag);
+ if (!loc) {
+ tag.type = htons(TAG_RELAY_SESSION_ID);
+ tag.length = htons(MY_RELAY_TAG_LEN);
+ memcpy(tag.payload, &ifIndex, sizeof(ifIndex));
+ memcpy(tag.payload+sizeof(ifIndex), packet->ethHdr.h_source, ETH_ALEN);
+ /* Add a relay tag if there's room */
+ r = addTag(packet, &tag);
+ if (r < 0) return;
+ size += r;
+ } else {
+ /* We do not re-use relay-id tags. Drop the frame. The RFC says the
+ relay agent SHOULD return a Generic-Error tag, but this does not
+ make sense for PADI packets. */
+ return;
+ }
+
+ /* Broadcast the PADI on all AC-capable interfaces except the interface
+ on which it came */
+ for (i=0; i < NumInterfaces; i++) {
+ if (iface == &Interfaces[i]) continue;
+ if (!Interfaces[i].acOK) continue;
+ memcpy(packet->ethHdr.h_source, Interfaces[i].mac, ETH_ALEN);
+ sendPacket(NULL, Interfaces[i].discoverySock, packet, size);
+ }
+
+}
+
+/**********************************************************************
+*%FUNCTION: relayHandlePADO
+*%ARGUMENTS:
+* iface -- interface on which packet was received
+* packet -- the PADO packet
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Receives and processes a PADO packet.
+***********************************************************************/
+void
+relayHandlePADO(PPPoEInterface const *iface,
+ PPPoEPacket *packet,
+ int size)
+{
+ PPPoETag tag;
+ unsigned char *loc;
+ int ifIndex;
+ int acIndex;
+
+ /* Can a server legally be behind this interface? */
+ if (!iface->acOK) {
+ syslog(LOG_ERR,
+ "PADO packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s not permitted",
+ packet->ethHdr.h_source[0],
+ packet->ethHdr.h_source[1],
+ packet->ethHdr.h_source[2],
+ packet->ethHdr.h_source[3],
+ packet->ethHdr.h_source[4],
+ packet->ethHdr.h_source[5],
+ iface->name);
+ return;
+ }
+
+ acIndex = iface - Interfaces;
+
+ /* Source address must be unicast */
+ if (NOT_UNICAST(packet->ethHdr.h_source)) {
+ syslog(LOG_ERR,
+ "PADO packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s not from a unicast address",
+ packet->ethHdr.h_source[0],
+ packet->ethHdr.h_source[1],
+ packet->ethHdr.h_source[2],
+ packet->ethHdr.h_source[3],
+ packet->ethHdr.h_source[4],
+ packet->ethHdr.h_source[5],
+ iface->name);
+ return;
+ }
+
+ /* Destination address must be interface's MAC address */
+ if (memcmp(packet->ethHdr.h_dest, iface->mac, ETH_ALEN)) {
+ return;
+ }
+
+ /* Find relay tag */
+ loc = findTag(packet, TAG_RELAY_SESSION_ID, &tag);
+ if (!loc) {
+ syslog(LOG_ERR,
+ "PADO packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s does not have Relay-Session-Id tag",
+ packet->ethHdr.h_source[0],
+ packet->ethHdr.h_source[1],
+ packet->ethHdr.h_source[2],
+ packet->ethHdr.h_source[3],
+ packet->ethHdr.h_source[4],
+ packet->ethHdr.h_source[5],
+ iface->name);
+ return;
+ }
+
+ /* If it's the wrong length, ignore it */
+ if (ntohs(tag.length) != MY_RELAY_TAG_LEN) {
+ syslog(LOG_ERR,
+ "PADO packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s does not have correct length Relay-Session-Id tag",
+ packet->ethHdr.h_source[0],
+ packet->ethHdr.h_source[1],
+ packet->ethHdr.h_source[2],
+ packet->ethHdr.h_source[3],
+ packet->ethHdr.h_source[4],
+ packet->ethHdr.h_source[5],
+ iface->name);
+ return;
+ }
+
+ /* Extract interface index */
+ memcpy(&ifIndex, tag.payload, sizeof(ifIndex));
+
+ if (ifIndex < 0 || ifIndex >= NumInterfaces ||
+ !Interfaces[ifIndex].clientOK ||
+ iface == &Interfaces[ifIndex]) {
+ syslog(LOG_ERR,
+ "PADO packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s has invalid interface in Relay-Session-Id tag",
+ packet->ethHdr.h_source[0],
+ packet->ethHdr.h_source[1],
+ packet->ethHdr.h_source[2],
+ packet->ethHdr.h_source[3],
+ packet->ethHdr.h_source[4],
+ packet->ethHdr.h_source[5],
+ iface->name);
+ return;
+ }
+
+ /* Replace Relay-ID tag with opposite-direction tag */
+ memcpy(loc+TAG_HDR_SIZE, &acIndex, sizeof(acIndex));
+ memcpy(loc+TAG_HDR_SIZE+sizeof(ifIndex), packet->ethHdr.h_source, ETH_ALEN);
+
+ /* Set destination address to MAC address in relay ID */
+ memcpy(packet->ethHdr.h_dest, tag.payload + sizeof(ifIndex), ETH_ALEN);
+
+ /* Set source address to MAC address of interface */
+ memcpy(packet->ethHdr.h_source, Interfaces[ifIndex].mac, ETH_ALEN);
+
+ /* Send the PADO to the proper client */
+ sendPacket(NULL, Interfaces[ifIndex].discoverySock, packet, size);
+}
+
+/**********************************************************************
+*%FUNCTION: relayHandlePADR
+*%ARGUMENTS:
+* iface -- interface on which packet was received
+* packet -- the PADR packet
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Receives and processes a PADR packet.
+***********************************************************************/
+void
+relayHandlePADR(PPPoEInterface const *iface,
+ PPPoEPacket *packet,
+ int size)
+{
+ PPPoETag tag;
+ unsigned char *loc;
+ int ifIndex;
+ int cliIndex;
+
+ /* Can a client legally be behind this interface? */
+ if (!iface->clientOK) {
+ syslog(LOG_ERR,
+ "PADR packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s not permitted",
+ packet->ethHdr.h_source[0],
+ packet->ethHdr.h_source[1],
+ packet->ethHdr.h_source[2],
+ packet->ethHdr.h_source[3],
+ packet->ethHdr.h_source[4],
+ packet->ethHdr.h_source[5],
+ iface->name);
+ return;
+ }
+
+ cliIndex = iface - Interfaces;
+
+ /* Source address must be unicast */
+ if (NOT_UNICAST(packet->ethHdr.h_source)) {
+ syslog(LOG_ERR,
+ "PADR packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s not from a unicast address",
+ packet->ethHdr.h_source[0],
+ packet->ethHdr.h_source[1],
+ packet->ethHdr.h_source[2],
+ packet->ethHdr.h_source[3],
+ packet->ethHdr.h_source[4],
+ packet->ethHdr.h_source[5],
+ iface->name);
+ return;
+ }
+
+ /* Destination address must be interface's MAC address */
+ if (memcmp(packet->ethHdr.h_dest, iface->mac, ETH_ALEN)) {
+ return;
+ }
+
+ /* Find relay tag */
+ loc = findTag(packet, TAG_RELAY_SESSION_ID, &tag);
+ if (!loc) {
+ syslog(LOG_ERR,
+ "PADR packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s does not have Relay-Session-Id tag",
+ packet->ethHdr.h_source[0],
+ packet->ethHdr.h_source[1],
+ packet->ethHdr.h_source[2],
+ packet->ethHdr.h_source[3],
+ packet->ethHdr.h_source[4],
+ packet->ethHdr.h_source[5],
+ iface->name);
+ return;
+ }
+
+ /* If it's the wrong length, ignore it */
+ if (ntohs(tag.length) != MY_RELAY_TAG_LEN) {
+ syslog(LOG_ERR,
+ "PADR packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s does not have correct length Relay-Session-Id tag",
+ packet->ethHdr.h_source[0],
+ packet->ethHdr.h_source[1],
+ packet->ethHdr.h_source[2],
+ packet->ethHdr.h_source[3],
+ packet->ethHdr.h_source[4],
+ packet->ethHdr.h_source[5],
+ iface->name);
+ return;
+ }
+
+ /* Extract interface index */
+ memcpy(&ifIndex, tag.payload, sizeof(ifIndex));
+
+ if (ifIndex < 0 || ifIndex >= NumInterfaces ||
+ !Interfaces[ifIndex].acOK ||
+ iface == &Interfaces[ifIndex]) {
+ syslog(LOG_ERR,
+ "PADR packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s has invalid interface in Relay-Session-Id tag",
+ packet->ethHdr.h_source[0],
+ packet->ethHdr.h_source[1],
+ packet->ethHdr.h_source[2],
+ packet->ethHdr.h_source[3],
+ packet->ethHdr.h_source[4],
+ packet->ethHdr.h_source[5],
+ iface->name);
+ return;
+ }
+
+ /* Replace Relay-ID tag with opposite-direction tag */
+ memcpy(loc+TAG_HDR_SIZE, &cliIndex, sizeof(cliIndex));
+ memcpy(loc+TAG_HDR_SIZE+sizeof(ifIndex), packet->ethHdr.h_source, ETH_ALEN);
+
+ /* Set destination address to MAC address in relay ID */
+ memcpy(packet->ethHdr.h_dest, tag.payload + sizeof(ifIndex), ETH_ALEN);
+
+ /* Set source address to MAC address of interface */
+ memcpy(packet->ethHdr.h_source, Interfaces[ifIndex].mac, ETH_ALEN);
+
+ /* Send the PADR to the proper access concentrator */
+ sendPacket(NULL, Interfaces[ifIndex].discoverySock, packet, size);
+}
+
+/**********************************************************************
+*%FUNCTION: relayHandlePADS
+*%ARGUMENTS:
+* iface -- interface on which packet was received
+* packet -- the PADS packet
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Receives and processes a PADS packet.
+***********************************************************************/
+void
+relayHandlePADS(PPPoEInterface const *iface,
+ PPPoEPacket *packet,
+ int size)
+{
+ PPPoETag tag;
+ unsigned char *loc;
+ int ifIndex;
+ int acIndex;
+ PPPoESession *ses = NULL;
+ SessionHash *sh;
+
+ /* Can a server legally be behind this interface? */
+ if (!iface->acOK) {
+ syslog(LOG_ERR,
+ "PADS packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s not permitted",
+ packet->ethHdr.h_source[0],
+ packet->ethHdr.h_source[1],
+ packet->ethHdr.h_source[2],
+ packet->ethHdr.h_source[3],
+ packet->ethHdr.h_source[4],
+ packet->ethHdr.h_source[5],
+ iface->name);
+ return;
+ }
+
+ acIndex = iface - Interfaces;
+
+ /* Source address must be unicast */
+ if (NOT_UNICAST(packet->ethHdr.h_source)) {
+ syslog(LOG_ERR,
+ "PADS packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s not from a unicast address",
+ packet->ethHdr.h_source[0],
+ packet->ethHdr.h_source[1],
+ packet->ethHdr.h_source[2],
+ packet->ethHdr.h_source[3],
+ packet->ethHdr.h_source[4],
+ packet->ethHdr.h_source[5],
+ iface->name);
+ return;
+ }
+
+ /* Destination address must be interface's MAC address */
+ if (memcmp(packet->ethHdr.h_dest, iface->mac, ETH_ALEN)) {
+ return;
+ }
+
+ /* Find relay tag */
+ loc = findTag(packet, TAG_RELAY_SESSION_ID, &tag);
+ if (!loc) {
+ syslog(LOG_ERR,
+ "PADS packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s does not have Relay-Session-Id tag",
+ packet->ethHdr.h_source[0],
+ packet->ethHdr.h_source[1],
+ packet->ethHdr.h_source[2],
+ packet->ethHdr.h_source[3],
+ packet->ethHdr.h_source[4],
+ packet->ethHdr.h_source[5],
+ iface->name);
+ return;
+ }
+
+ /* If it's the wrong length, ignore it */
+ if (ntohs(tag.length) != MY_RELAY_TAG_LEN) {
+ syslog(LOG_ERR,
+ "PADS packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s does not have correct length Relay-Session-Id tag",
+ packet->ethHdr.h_source[0],
+ packet->ethHdr.h_source[1],
+ packet->ethHdr.h_source[2],
+ packet->ethHdr.h_source[3],
+ packet->ethHdr.h_source[4],
+ packet->ethHdr.h_source[5],
+ iface->name);
+ return;
+ }
+
+ /* Extract interface index */
+ memcpy(&ifIndex, tag.payload, sizeof(ifIndex));
+
+ if (ifIndex < 0 || ifIndex >= NumInterfaces ||
+ !Interfaces[ifIndex].clientOK ||
+ iface == &Interfaces[ifIndex]) {
+ syslog(LOG_ERR,
+ "PADS packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s has invalid interface in Relay-Session-Id tag",
+ packet->ethHdr.h_source[0],
+ packet->ethHdr.h_source[1],
+ packet->ethHdr.h_source[2],
+ packet->ethHdr.h_source[3],
+ packet->ethHdr.h_source[4],
+ packet->ethHdr.h_source[5],
+ iface->name);
+ return;
+ }
+
+ /* If session ID is zero, it's the AC respoding with an error.
+ Just relay it; do not create a session */
+ if (packet->session != htons(0)) {
+ /* Check for existing session */
+ sh = findSession(packet->ethHdr.h_source, packet->session);
+ if (sh) ses = sh->ses;
+
+ /* If already an existing session, assume it's a duplicate PADS. Send
+ the frame, but do not create a new session. Is this the right
+ thing to do? Arguably, should send an error to the client and
+ a PADT to the server, because this could happen due to a
+ server crash and reboot. */
+
+ if (!ses) {
+ /* Create a new session */
+ ses = createSession(iface, &Interfaces[ifIndex],
+ packet->ethHdr.h_source,
+ loc + TAG_HDR_SIZE + sizeof(ifIndex), packet->session);
+ if (!ses) {
+ /* Can't allocate session -- send error PADS to client and
+ PADT to server */
+ PPPoETag hostUniq, *hu;
+ if (findTag(packet, TAG_HOST_UNIQ, &hostUniq)) {
+ hu = &hostUniq;
+ } else {
+ hu = NULL;
+ }
+ relaySendError(CODE_PADS, htons(0), &Interfaces[ifIndex],
+ loc + TAG_HDR_SIZE + sizeof(ifIndex),
+ hu, "RP-PPPoE: Relay: Unable to allocate session");
+ relaySendError(CODE_PADT, packet->session, iface,
+ packet->ethHdr.h_source, NULL,
+ "RP-PPPoE: Relay: Unable to allocate session");
+ return;
+ }
+ }
+ /* Replace session number */
+ packet->session = ses->sesNum;
+ }
+
+ /* Remove relay-ID tag */
+ removeBytes(packet, loc, MY_RELAY_TAG_LEN + TAG_HDR_SIZE);
+ size -= (MY_RELAY_TAG_LEN + TAG_HDR_SIZE);
+
+ /* Set destination address to MAC address in relay ID */
+ memcpy(packet->ethHdr.h_dest, tag.payload + sizeof(ifIndex), ETH_ALEN);
+
+ /* Set source address to MAC address of interface */
+ memcpy(packet->ethHdr.h_source, Interfaces[ifIndex].mac, ETH_ALEN);
+
+ /* Send the PADS to the proper client */
+ sendPacket(NULL, Interfaces[ifIndex].discoverySock, packet, size);
+}
+
+/**********************************************************************
+*%FUNCTION: relaySendError
+*%ARGUMENTS:
+* code -- PPPoE packet code (PADS or PADT, typically)
+* session -- PPPoE session number
+* iface -- interface on which to send frame
+* mac -- Ethernet address to which frame should be sent
+* hostUniq -- if non-NULL, a hostUniq tag to add to error frame
+* errMsg -- error message to insert into Generic-Error tag.
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Sends either a PADS or PADT packet with a Generic-Error tag and an
+* error message.
+***********************************************************************/
+void
+relaySendError(unsigned char code,
+ UINT16_t session,
+ PPPoEInterface const *iface,
+ unsigned char const *mac,
+ PPPoETag const *hostUniq,
+ char const *errMsg)
+{
+ PPPoEPacket packet;
+ PPPoETag errTag;
+ int size;
+
+ memcpy(packet.ethHdr.h_source, iface->mac, ETH_ALEN);
+ memcpy(packet.ethHdr.h_dest, mac, ETH_ALEN);
+ packet.ethHdr.h_proto = htons(Eth_PPPOE_Discovery);
+ packet.type = 1;
+ packet.ver = 1;
+ packet.code = code;
+ packet.session = session;
+ packet.length = htons(0);
+ if (hostUniq) {
+ if (addTag(&packet, hostUniq) < 0) return;
+ }
+ errTag.type = htons(TAG_GENERIC_ERROR);
+ errTag.length = htons(strlen(errMsg));
+ strcpy(errTag.payload, errMsg);
+ if (addTag(&packet, &errTag) < 0) return;
+ size = ntohs(packet.length) + HDR_SIZE;
+ if (code == CODE_PADT) {
+ sendPacket(NULL, iface->discoverySock, &packet, size);
+ } else {
+ sendPacket(NULL, iface->sessionSock, &packet, size);
+ }
+}
+
+/**********************************************************************
+*%FUNCTION: alarmHandler
+*%ARGUMENTS:
+* sig -- signal number
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* SIGALRM handler. Increments Epoch; if necessary, writes a byte of
+* data to the alarm pipe to trigger the stale-session cleaner.
+***********************************************************************/
+void
+alarmHandler(int sig)
+{
+ alarm(1);
+ Epoch++;
+ CleanCounter++;
+ if (CleanCounter == CleanPeriod) {
+ write(CleanPipe[1], "", 1);
+ }
+}
+
+/**********************************************************************
+*%FUNCTION: cleanSessions
+*%ARGUMENTS:
+* None
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Goes through active sessions and cleans sessions idle for longer
+* than IdleTimeout seconds.
+***********************************************************************/
+void cleanSessions(void)
+{
+ PPPoESession *cur, *next;
+ cur = ActiveSessions;
+ while(cur) {
+ next = cur->next;
+ if (Epoch - cur->epoch > IdleTimeout) {
+ /* Send PADT to each peer */
+ relaySendError(CODE_PADT, cur->acHash->sesNum,
+ cur->acHash->interface,
+ cur->acHash->peerMac, NULL,
+ "RP-PPPoE: Relay: Session exceeded idle timeout");
+ relaySendError(CODE_PADT, cur->clientHash->sesNum,
+ cur->clientHash->interface,
+ cur->clientHash->peerMac, NULL,
+ "RP-PPPoE: Relay: Session exceeded idle timeout");
+ freeSession(cur, "Idle Timeout");
+ }
+ cur = next;
+ }
+}
diff --git a/mdk-stage1/rp-pppoe/src/relay.h b/mdk-stage1/rp-pppoe/src/relay.h
new file mode 100644
index 000000000..232357a31
--- /dev/null
+++ b/mdk-stage1/rp-pppoe/src/relay.h
@@ -0,0 +1,97 @@
+/**********************************************************************
+*
+* relay.h
+*
+* Definitions for PPPoE relay
+*
+* Copyright (C) 2001 Roaring Penguin Software Inc.
+*
+* This program may be distributed according to the terms of the GNU
+* General Public License, version 2 or (at your option) any later version.
+*
+* $Id: relay.h 195724 2001-06-11 13:49:39Z gc $
+*
+***********************************************************************/
+
+#include "pppoe.h"
+
+/* Description for each active Ethernet interface */
+typedef struct InterfaceStruct {
+ char name[IFNAMSIZ+1]; /* Interface name */
+ int discoverySock; /* Socket for discovery frames */
+ int sessionSock; /* Socket for session frames */
+ int clientOK; /* Client requests allowed (PADI, PADR) */
+ int acOK; /* AC replies allowed (PADO, PADS) */
+ unsigned char mac[ETH_ALEN]; /* MAC address */
+} PPPoEInterface;
+
+/* Session state for relay */
+struct SessionHashStruct;
+typedef struct SessionStruct {
+ struct SessionStruct *next; /* Free list link */
+ struct SessionStruct *prev; /* Free list link */
+ struct SessionHashStruct *acHash; /* Hash bucket for AC MAC/Session */
+ struct SessionHashStruct *clientHash; /* Hash bucket for client MAC/Session */
+ unsigned int epoch; /* Epoch when last activity was seen */
+ UINT16_t sesNum; /* Session number assigned by relay */
+} PPPoESession;
+
+/* Hash table entry to find sessions */
+typedef struct SessionHashStruct {
+ struct SessionHashStruct *next; /* Link in hash chain */
+ struct SessionHashStruct *prev; /* Link in hash chain */
+ struct SessionHashStruct *peer; /* Peer for this session */
+ PPPoEInterface const *interface; /* Interface */
+ unsigned char peerMac[ETH_ALEN]; /* Peer's MAC address */
+ UINT16_t sesNum; /* Session number */
+ PPPoESession *ses; /* Session data */
+} SessionHash;
+
+/* Function prototypes */
+
+void relayGotSessionPacket(PPPoEInterface const *i);
+void relayGotDiscoveryPacket(PPPoEInterface const *i);
+PPPoEInterface *findInterface(int sock);
+unsigned int hash(unsigned char const *mac, UINT16_t sesNum);
+SessionHash *findSession(unsigned char const *mac, UINT16_t sesNum);
+void deleteHash(SessionHash *hash);
+PPPoESession *createSession(PPPoEInterface const *ac,
+ PPPoEInterface const *cli,
+ unsigned char const *acMac,
+ unsigned char const *cliMac,
+ UINT16_t acSes);
+void freeSession(PPPoESession *ses, char const *msg);
+void addInterface(char const *ifname, int clientOK, int acOK);
+void usage(char const *progname);
+void initRelay(int nsess);
+void relayLoop(void);
+void addHash(SessionHash *sh);
+void unhash(SessionHash *sh);
+
+void relayHandlePADT(PPPoEInterface const *iface, PPPoEPacket *packet, int size);
+void relayHandlePADI(PPPoEInterface const *iface, PPPoEPacket *packet, int size);
+void relayHandlePADO(PPPoEInterface const *iface, PPPoEPacket *packet, int size);
+void relayHandlePADR(PPPoEInterface const *iface, PPPoEPacket *packet, int size);
+void relayHandlePADS(PPPoEInterface const *iface, PPPoEPacket *packet, int size);
+
+int addTag(PPPoEPacket *packet, PPPoETag const *tag);
+int insertBytes(PPPoEPacket *packet, unsigned char *loc,
+ void const *bytes, int length);
+int removeBytes(PPPoEPacket *packet, unsigned char *loc,
+ int length);
+void relaySendError(unsigned char code,
+ UINT16_t session,
+ PPPoEInterface const *iface,
+ unsigned char const *mac,
+ PPPoETag const *hostUniq,
+ char const *errMsg);
+
+void alarmHandler(int sig);
+void cleanSessions(void);
+
+#define MAX_INTERFACES 8
+#define DEFAULT_SESSIONS 5000
+
+/* Hash table size -- a prime number; gives load factor of around 6
+ for 65534 sessions */
+#define HASHTAB_SIZE 18917
diff --git a/mdk-stage1/slang/Makefile b/mdk-stage1/slang/Makefile
new file mode 100644
index 000000000..111062578
--- /dev/null
+++ b/mdk-stage1/slang/Makefile
@@ -0,0 +1,42 @@
+ #******************************************************************************
+ #
+ # Guillaume Cottenceau (gc@mandrakesoft.com)
+ #
+ # Copyright 2000 Mandrakesoft
+ #
+ # This software may be freely redistributed under the terms of the GNU
+ # public license.
+ #
+ # 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.
+ #
+ #*****************************************************************************
+
+top_dir = ..
+
+include $(top_dir)/Makefile.common
+
+
+LIBNAME = libslang
+
+OBJS = sltermin.o sldisply.o slutty.o slang.o slarray.o slclass.o slcmd.o slerr.o slgetkey.o slkeymap.o slmalloc.o slmath.o slmemchr.o slmemcmp.o slmemcpy.o slmemset.o slmisc.o slparse.o slprepr.o slregexp.o slrline.o slsearch.o slsmg.o slstd.o sltoken.o sltypes.o slxstrng.o slcurses.o slscroll.o slsignal.o slkeypad.o slerrno.o slstring.o slstruct.o slcmplex.o slarrfun.o slimport.o slpath.o slarith.o slassoc.o slcompat.o slposdir.o slstdio.o slproc.o sltime.o slstrops.o slbstr.o slpack.o slintall.o slistruc.o slposio.o slnspace.o slarrmis.o slospath.o slscanf.o
+
+DEFS = -Dunix -DSLANG
+
+INCS =
+
+
+TARGETS = $(LIBNAME).a
+
+all: $(TARGETS)
+
+clean:
+ rm -f *.o *.a
+
+$(LIBNAME).a: $(OBJS)
+ ar -cru $@ $^
+ ranlib $@
+
+$(OBJS): %.o: %.c
+ $(DIET) gcc $(CFLAGS) $(DEFS) $(INCS) $(INCLUDES) -c $< -o $@
diff --git a/mdk-stage1/slang/_slang.h b/mdk-stage1/slang/_slang.h
new file mode 100644
index 000000000..02ee13505
--- /dev/null
+++ b/mdk-stage1/slang/_slang.h
@@ -0,0 +1,743 @@
+#ifndef _PRIVATE_SLANG_H_
+#define _PRIVATE_SLANG_H_
+/* header file for S-Lang internal structures that users do not (should not)
+ need. Use slang.h for that purpose. */
+/* Copyright (c) 1992, 1999, 2001 John E. Davis
+ * This file is part of the S-Lang library.
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Perl Artistic License.
+ */
+
+/* #include "config.h" */
+#include "jdmacros.h"
+#include "sllimits.h"
+
+#ifdef VMS
+# define SLANG_SYSTEM_NAME "_VMS"
+#else
+# if defined (IBMPC_SYSTEM)
+# define SLANG_SYSTEM_NAME "_IBMPC"
+# else
+# define SLANG_SYSTEM_NAME "_UNIX"
+# endif
+#endif /* VMS */
+
+/* These quantities are main_types for byte-compiled code. They are used
+ * by the inner_interp routine. The _BC_ means byte-code.
+ */
+
+#define _SLANG_BC_LVARIABLE SLANG_LVARIABLE /* 0x01 */
+#define _SLANG_BC_GVARIABLE SLANG_GVARIABLE /* 0x02 */
+#define _SLANG_BC_IVARIABLE SLANG_IVARIABLE /* 0x03 */
+#define _SLANG_BC_RVARIABLE SLANG_RVARIABLE /* 0x04 */
+#define _SLANG_BC_INTRINSIC SLANG_INTRINSIC /* 0x05 */
+#define _SLANG_BC_FUNCTION SLANG_FUNCTION /* 0x06 */
+#define _SLANG_BC_MATH_UNARY SLANG_MATH_UNARY /* 0x07 */
+#define _SLANG_BC_APP_UNARY SLANG_APP_UNARY /* 0x08 */
+#define _SLANG_BC_ICONST SLANG_ICONSTANT /* 0x09 */
+#define _SLANG_BC_DCONST SLANG_DCONSTANT /* 0x0A */
+#define _SLANG_BC_PVARIABLE SLANG_PVARIABLE /* 0x0B */
+#define _SLANG_BC_PFUNCTION SLANG_PFUNCTION /* 0x0C */
+
+#define _SLANG_BC_BINARY 0x10
+#define _SLANG_BC_LITERAL 0x11 /* constant objects */
+#define _SLANG_BC_LITERAL_INT 0x12
+#define _SLANG_BC_LITERAL_STR 0x13
+#define _SLANG_BC_BLOCK 0x14
+
+/* These 3 MUST be in this order too ! */
+#define _SLANG_BC_RETURN 0x15
+#define _SLANG_BC_BREAK 0x16
+#define _SLANG_BC_CONTINUE 0x17
+
+#define _SLANG_BC_EXCH 0x18
+#define _SLANG_BC_LABEL 0x19
+#define _SLANG_BC_LOBJPTR 0x1A
+#define _SLANG_BC_GOBJPTR 0x1B
+#define _SLANG_BC_X_ERROR 0x1C
+/* These must be in this order */
+#define _SLANG_BC_X_USER0 0x1D
+#define _SLANG_BC_X_USER1 0x1E
+#define _SLANG_BC_X_USER2 0x1F
+#define _SLANG_BC_X_USER3 0x20
+#define _SLANG_BC_X_USER4 0x21
+
+#define _SLANG_BC_CALL_DIRECT 0x24
+#define _SLANG_BC_CALL_DIRECT_FRAME 0x25
+#define _SLANG_BC_UNARY 0x26
+#define _SLANG_BC_UNARY_FUNC 0x27
+
+#define _SLANG_BC_DEREF_ASSIGN 0x30
+#define _SLANG_BC_SET_LOCAL_LVALUE 0x31
+#define _SLANG_BC_SET_GLOBAL_LVALUE 0x32
+#define _SLANG_BC_SET_INTRIN_LVALUE 0x33
+#define _SLANG_BC_SET_STRUCT_LVALUE 0x34
+#define _SLANG_BC_FIELD 0x35
+#define _SLANG_BC_SET_ARRAY_LVALUE 0x36
+
+#define _SLANG_BC_LINE_NUM 0x40
+
+#define _SLANG_BC_TMP 0x50
+#define _SLANG_BC_LVARIABLE_AGET 0x60
+#define _SLANG_BC_LVARIABLE_APUT 0x61
+#define _SLANG_BC_INTEGER_PLUS 0x62
+#define _SLANG_BC_INTEGER_MINUS 0x63
+#define _SLANG_BC_ARG_LVARIABLE 0x64
+#define _SLANG_BC_EARG_LVARIABLE 0x65
+
+#define _SLANG_BC_CALL_DIRECT_INTRINSIC 0x80
+#define _SLANG_BC_INTRINSIC_CALL_DIRECT 0x81
+#define _SLANG_BC_CALL_DIRECT_LSTR 0x82
+#define _SLANG_BC_CALL_DIRECT_SLFUN 0x83
+#define _SLANG_BC_CALL_DIRECT_INTRSTOP 0x84
+#define _SLANG_BC_INTRINSIC_STOP 0x85
+#define _SLANG_BC_CALL_DIRECT_EARG_LVAR 0x86
+#define _SLANG_BC_CALL_DIRECT_LINT 0x87
+#define _SLANG_BC_CALL_DIRECT_LVAR 0x88
+
+
+/* Byte-Code Sub Types (_BCST_) */
+
+/* These are sub_types of _SLANG_BC_BLOCK */
+#define _SLANG_BCST_ERROR_BLOCK 0x01
+#define _SLANG_BCST_EXIT_BLOCK 0x02
+#define _SLANG_BCST_USER_BLOCK0 0x03
+#define _SLANG_BCST_USER_BLOCK1 0x04
+#define _SLANG_BCST_USER_BLOCK2 0x05
+#define _SLANG_BCST_USER_BLOCK3 0x06
+#define _SLANG_BCST_USER_BLOCK4 0x07
+/* The user blocks MUST be in the above order */
+#define _SLANG_BCST_LOOP 0x10
+#define _SLANG_BCST_WHILE 0x11
+#define _SLANG_BCST_FOR 0x12
+#define _SLANG_BCST_FOREVER 0x13
+#define _SLANG_BCST_CFOR 0x14
+#define _SLANG_BCST_DOWHILE 0x15
+#define _SLANG_BCST_FOREACH 0x16
+
+#define _SLANG_BCST_IF 0x20
+#define _SLANG_BCST_IFNOT 0x21
+#define _SLANG_BCST_ELSE 0x22
+#define _SLANG_BCST_ANDELSE 0x23
+#define _SLANG_BCST_ORELSE 0x24
+#define _SLANG_BCST_SWITCH 0x25
+#define _SLANG_BCST_NOTELSE 0x26
+
+/* assignment (_SLANG_BC_SET_*_LVALUE) subtypes. The order MUST correspond
+ * to the assignment token order with the ASSIGN_TOKEN as the first!
+ */
+#define _SLANG_BCST_ASSIGN 0x01
+#define _SLANG_BCST_PLUSEQS 0x02
+#define _SLANG_BCST_MINUSEQS 0x03
+#define _SLANG_BCST_TIMESEQS 0x04
+#define _SLANG_BCST_DIVEQS 0x05
+#define _SLANG_BCST_BOREQS 0x06
+#define _SLANG_BCST_BANDEQS 0x07
+#define _SLANG_BCST_PLUSPLUS 0x08
+#define _SLANG_BCST_POST_PLUSPLUS 0x09
+#define _SLANG_BCST_MINUSMINUS 0x0A
+#define _SLANG_BCST_POST_MINUSMINUS 0x0B
+
+/* These use SLANG_PLUS, SLANG_MINUS, SLANG_PLUSPLUS, etc... */
+
+typedef union
+{
+#if SLANG_HAS_FLOAT
+ double double_val;
+ float float_val;
+#endif
+ long long_val;
+ unsigned long ulong_val;
+ VOID_STAR ptr_val;
+ char *s_val;
+ int int_val;
+ unsigned int uint_val;
+ SLang_MMT_Type *ref;
+ SLang_Name_Type *n_val;
+ struct _SLang_Struct_Type *struct_val;
+ struct _SLang_Array_Type *array_val;
+ short short_val;
+ unsigned short ushort_val;
+ char char_val;
+ unsigned char uchar_val;
+}
+_SL_Object_Union_Type;
+
+typedef struct _SLang_Object_Type
+{
+ unsigned char data_type; /* SLANG_INT_TYPE, ... */
+ _SL_Object_Union_Type v;
+}
+SLang_Object_Type;
+
+struct _SLang_MMT_Type
+{
+ unsigned char data_type; /* int, string, etc... */
+ VOID_STAR user_data; /* address of user structure */
+ unsigned int count; /* number of references */
+};
+
+extern int _SLang_pop_object_of_type (unsigned char, SLang_Object_Type *, int);
+
+typedef struct
+{
+ char *name; /* slstring */
+ SLang_Object_Type obj;
+}
+_SLstruct_Field_Type;
+
+typedef struct _SLang_Struct_Type
+{
+ _SLstruct_Field_Type *fields;
+ unsigned int nfields; /* number used */
+ unsigned int num_refs;
+}
+_SLang_Struct_Type;
+
+extern void _SLstruct_delete_struct (_SLang_Struct_Type *);
+extern int _SLang_push_struct (_SLang_Struct_Type *);
+extern int _SLang_pop_struct (_SLang_Struct_Type **);
+extern int _SLstruct_init (void);
+/* extern int _SLstruct_get_field (char *); */
+extern int _SLstruct_define_struct (void);
+extern int _SLstruct_define_typedef (void);
+
+extern int _SLang_pop_datatype (unsigned char *);
+extern int _SLang_push_datatype (unsigned char);
+
+struct _SLang_Ref_Type
+{
+ int is_global;
+ union
+ {
+ SLang_Name_Type *nt;
+ SLang_Object_Type *local_obj;
+ }
+ v;
+};
+
+extern int _SLang_dereference_ref (SLang_Ref_Type *);
+extern int _SLang_deref_assign (SLang_Ref_Type *);
+extern int _SLang_push_ref (int, VOID_STAR);
+
+extern int _SL_increment_frame_pointer (void);
+extern int _SL_decrement_frame_pointer (void);
+
+extern int SLang_pop(SLang_Object_Type *);
+extern void SLang_free_object (SLang_Object_Type *);
+extern int _SLanytype_typecast (unsigned char, VOID_STAR, unsigned int,
+ unsigned char, VOID_STAR);
+extern void _SLstring_intrinsic (void);
+
+
+/* These functions are used to create slstrings of a fixed length. Be
+ * very careful how they are used. In particular, if len bytes are allocated,
+ * then the string must be len characters long, no more and no less.
+ */
+extern char *_SLallocate_slstring (unsigned int);
+extern char *_SLcreate_via_alloced_slstring (char *, unsigned int);
+extern void _SLunallocate_slstring (char *, unsigned int);
+extern int _SLpush_alloced_slstring (char *, unsigned int);
+
+typedef struct
+{
+ char **buf;
+ unsigned int max_num;
+ unsigned int num;
+ unsigned int delta_num;
+}
+_SLString_List_Type;
+extern int _SLstring_list_append (_SLString_List_Type *, char *);
+extern int _SLstring_list_init (_SLString_List_Type *, unsigned int, unsigned int);
+extern void _SLstring_list_delete (_SLString_List_Type *);
+extern int _SLstring_list_push (_SLString_List_Type *);
+
+/* This function assumes that s is an slstring. */
+extern char *_SLstring_dup_slstring (char *);
+extern int _SLang_dup_and_push_slstring (char *);
+
+
+extern int _SLang_init_import (void);
+
+/* This function checks to see if the referenced object is initialized */
+extern int _SLang_is_ref_initialized (SLang_Ref_Type *);
+extern int _SLcheck_identifier_syntax (char *);
+extern int _SLang_uninitialize_ref (SLang_Ref_Type *);
+
+extern int _SLpush_slang_obj (SLang_Object_Type *);
+
+extern char *_SLexpand_escaped_char(char *, char *);
+extern void _SLexpand_escaped_string (char *, char *, char *);
+
+/* returns a pointer to an SLstring string-- use SLang_free_slstring */
+extern char *_SLstringize_object (SLang_Object_Type *);
+extern int _SLdump_objects (char *, SLang_Object_Type *, unsigned int, int);
+
+extern SLang_Object_Type *_SLRun_Stack;
+extern SLang_Object_Type *_SLStack_Pointer;
+
+struct _SLang_NameSpace_Type
+{
+ struct _SLang_NameSpace_Type *next;
+ char *name; /* this is the load_type name */
+ char *namespace_name; /* this name is assigned by implements */
+ unsigned int table_size;
+ SLang_Name_Type **table;
+};
+extern SLang_NameSpace_Type *_SLns_allocate_namespace (char *, unsigned int);
+extern SLang_NameSpace_Type *_SLns_find_namespace (char *);
+extern int _SLns_set_namespace_name (SLang_NameSpace_Type *, char *);
+extern SLang_Array_Type *_SLnspace_apropos (SLang_NameSpace_Type *, char *, unsigned int);
+extern void _SLang_use_namespace_intrinsic (char *name);
+extern char *_SLang_cur_namespace_intrinsic (void);
+extern SLang_Array_Type *_SLang_apropos (char *, char *, unsigned int);
+extern void _SLang_implements_intrinsic (char *);
+
+extern int _SLang_Trace;
+extern int _SLstack_depth(void);
+extern char *_SLang_Current_Function_Name;
+
+extern int _SLang_trace_fun(char *);
+extern int _SLang_Compile_Line_Num_Info;
+
+extern char *_SLstring_dup_hashed_string (char *, unsigned long);
+extern unsigned long _SLcompute_string_hash (char *);
+extern char *_SLstring_make_hashed_string (char *, unsigned int, unsigned long *);
+extern void _SLfree_hashed_string (char *, unsigned int, unsigned long);
+unsigned long _SLstring_hash (unsigned char *, unsigned char *);
+extern int _SLinit_slcomplex (void);
+
+extern int _SLang_init_slstrops (void);
+extern int _SLstrops_do_sprintf_n (int);
+extern int _SLang_sscanf (void);
+extern double _SLang_atof (char *);
+extern int _SLang_init_bstring (void);
+extern int _SLang_init_sltime (void);
+extern void _SLpack (void);
+extern void _SLunpack (char *, SLang_BString_Type *);
+extern void _SLpack_pad_format (char *);
+extern unsigned int _SLpack_compute_size (char *);
+extern int _SLusleep (unsigned long);
+
+/* frees upon error. NULL __NOT__ ok. */
+extern int _SLang_push_slstring (char *);
+
+extern unsigned char _SLarith_promote_type (unsigned char);
+extern int _SLarith_get_precedence (unsigned char);
+extern int _SLarith_typecast (unsigned char, VOID_STAR, unsigned int,
+ unsigned char, VOID_STAR);
+
+extern int SLang_push(SLang_Object_Type *);
+extern int SLadd_global_variable (char *);
+extern void _SLang_clear_error (void);
+
+extern int _SLdo_pop (void);
+extern unsigned int _SLsys_getkey (void);
+extern int _SLsys_input_pending (int);
+#ifdef IBMPC_SYSTEM
+extern unsigned int _SLpc_convert_scancode (unsigned int, unsigned int, int);
+#define _SLTT_KEY_SHIFT 1
+#define _SLTT_KEY_CTRL 2
+#define _SLTT_KEY_ALT 4
+#endif
+
+typedef struct _SLterminfo_Type SLterminfo_Type;
+extern SLterminfo_Type *_SLtt_tigetent (char *);
+extern char *_SLtt_tigetstr (SLterminfo_Type *, char *);
+extern int _SLtt_tigetnum (SLterminfo_Type *, char *);
+extern int _SLtt_tigetflag (SLterminfo_Type *, char *);
+
+#if SLTT_HAS_NON_BCE_SUPPORT
+extern int _SLtt_get_bce_color_offset (void);
+#endif
+extern void (*_SLtt_color_changed_hook)(void);
+
+extern unsigned char SLang_Input_Buffer [SL_MAX_INPUT_BUFFER_LEN];
+
+extern int _SLregister_types (void);
+extern SLang_Class_Type *_SLclass_get_class (unsigned char);
+extern VOID_STAR _SLclass_get_ptr_to_value (SLang_Class_Type *, SLang_Object_Type *);
+extern void _SLclass_type_mismatch_error (unsigned char, unsigned char);
+extern int _SLclass_init (void);
+extern int _SLclass_copy_class (unsigned char, unsigned char);
+
+extern unsigned char _SLclass_Class_Type [256];
+
+extern int (*_SLclass_get_typecast (unsigned char, unsigned char, int))
+(unsigned char, VOID_STAR, unsigned int,
+ unsigned char, VOID_STAR);
+
+extern int (*_SLclass_get_binary_fun (int, SLang_Class_Type *, SLang_Class_Type *, SLang_Class_Type **, int))
+(int,
+ unsigned char, VOID_STAR, unsigned int,
+ unsigned char, VOID_STAR, unsigned int,
+ VOID_STAR);
+
+extern int (*_SLclass_get_unary_fun (int, SLang_Class_Type *, SLang_Class_Type **, int))
+(int, unsigned char, VOID_STAR, unsigned int, VOID_STAR);
+
+extern int _SLarith_register_types (void);
+extern unsigned char _SLarith_Arith_Types [];
+extern unsigned char _SLarith_Is_Arith_Type [256];
+extern int _SLarith_bin_op (SLang_Object_Type *, SLang_Object_Type *, int);
+
+extern int _SLarray_add_bin_op (unsigned char);
+
+extern int _SLang_call_funptr (SLang_Name_Type *);
+extern void _SLset_double_format (char *);
+extern SLang_Name_Type *_SLlocate_global_name (char *);
+extern SLang_Name_Type *_SLlocate_name (char *);
+
+extern char *_SLdefines[];
+
+#define SL_ERRNO_NOT_IMPLEMENTED 0x7FFF
+extern int _SLerrno_errno;
+extern int _SLerrno_init (void);
+
+extern int _SLstdio_fdopen (char *, int, char *);
+
+extern void _SLstruct_pop_args (int *);
+extern void _SLstruct_push_args (SLang_Array_Type *);
+
+extern int _SLarray_aput (void);
+extern int _SLarray_aget (void);
+extern int _SLarray_inline_implicit_array (void);
+extern int _SLarray_inline_array (void);
+extern int _SLarray_wildcard_array (void);
+
+extern int
+_SLarray_typecast (unsigned char, VOID_STAR, unsigned int,
+ unsigned char, VOID_STAR, int);
+
+extern int _SLarray_aput_transfer_elem (SLang_Array_Type *, int *,
+ VOID_STAR, unsigned int, int);
+extern int _SLarray_aget_transfer_elem (SLang_Array_Type *, int *,
+ VOID_STAR, unsigned int, int);
+extern void _SLarray_free_array_elements (SLang_Class_Type *, VOID_STAR, unsigned int);
+
+extern SLang_Foreach_Context_Type *
+_SLarray_cl_foreach_open (unsigned char, unsigned int);
+extern void _SLarray_cl_foreach_close (unsigned char, SLang_Foreach_Context_Type *);
+extern int _SLarray_cl_foreach (unsigned char, SLang_Foreach_Context_Type *);
+
+extern int _SLarray_matrix_multiply (void);
+extern void (*_SLang_Matrix_Multiply)(void);
+
+extern int _SLarray_init_slarray (void);
+extern SLang_Array_Type *
+SLang_create_array1 (unsigned char, int, VOID_STAR, int *, unsigned int, int);
+
+extern int _SLcompile_push_context (SLang_Load_Type *);
+extern int _SLcompile_pop_context (void);
+extern int _SLang_Auto_Declare_Globals;
+
+typedef struct
+{
+ union
+ {
+ long long_val;
+ char *s_val; /* Used for IDENT_TOKEN, FLOAT, etc... */
+ SLang_BString_Type *b_val;
+ } v;
+ int free_sval_flag;
+ unsigned int num_refs;
+ unsigned long hash;
+#if _SLANG_HAS_DEBUG_CODE
+ int line_number;
+#endif
+ unsigned char type;
+}
+_SLang_Token_Type;
+
+extern void _SLcompile (_SLang_Token_Type *);
+extern void (*_SLcompile_ptr)(_SLang_Token_Type *);
+
+/* *** TOKENS *** */
+
+/* Note that that tokens corresponding to ^J, ^M, and ^Z should not be used.
+ * This is because a file that contains any of these characters will
+ * have an OS dependent interpretation, e.g., ^Z is EOF on MSDOS.
+ */
+
+/* Special tokens */
+#define EOF_TOKEN 0x01
+#define RPN_TOKEN 0x02
+#define NL_TOKEN 0x03
+#define NOP_TOKEN 0x05
+#define FARG_TOKEN 0x06
+#define TMP_TOKEN 0x07
+
+#define RESERVED1_TOKEN 0x0A /* \n */
+#define RESERVED2_TOKEN 0x0D /* \r */
+
+/* Literal tokens */
+#define CHAR_TOKEN 0x10
+#define UCHAR_TOKEN 0x11
+#define SHORT_TOKEN 0x12
+#define USHORT_TOKEN 0x13
+#define INT_TOKEN 0x14
+#define UINT_TOKEN 0x15
+#define LONG_TOKEN 0x16
+#define ULONG_TOKEN 0x17
+#define IS_INTEGER_TOKEN(x) ((x >= CHAR_TOKEN) && (x <= ULONG_TOKEN))
+#define FLOAT_TOKEN 0x18
+#define DOUBLE_TOKEN 0x19
+#define RESERVED3_TOKEN 0x1A /* ^Z */
+#define COMPLEX_TOKEN 0x1B
+#define STRING_TOKEN 0x1C
+#define BSTRING_TOKEN 0x1D
+#define _BSTRING_TOKEN 0x1E /* byte-compiled BSTRING */
+#define ESC_STRING_TOKEN 0x1F
+
+/* Tokens that can be LVALUES */
+#define IDENT_TOKEN 0x20
+#define ARRAY_TOKEN 0x21
+#define DOT_TOKEN 0x22
+#define IS_LVALUE_TOKEN (((t) <= DOT_TOKEN) && ((t) >= IDENT_TOKEN))
+
+/* do not use these values */
+#define RESERVED4_TOKEN 0x23 /* # */
+#define RESERVED5_TOKEN 0x25 /* % */
+
+/* Flags for struct fields */
+#define STATIC_TOKEN 0x26
+#define READONLY_TOKEN 0x27
+#define PRIVATE_TOKEN 0x28
+#define PUBLIC_TOKEN 0x29
+
+/* Punctuation tokens */
+#define OBRACKET_TOKEN 0x2a
+#define CBRACKET_TOKEN 0x2b
+#define OPAREN_TOKEN 0x2c
+#define CPAREN_TOKEN 0x2d
+#define OBRACE_TOKEN 0x2e
+#define CBRACE_TOKEN 0x2f
+
+#define COMMA_TOKEN 0x31
+#define SEMICOLON_TOKEN 0x32
+#define COLON_TOKEN 0x33
+#define NAMESPACE_TOKEN 0x34
+
+/* Operators */
+#define POW_TOKEN 0x38
+
+/* The order here must match the order in the Binop_Level table in slparse.c */
+#define FIRST_BINARY_OP 0x39
+#define ADD_TOKEN 0x39
+#define SUB_TOKEN 0x3a
+#define TIMES_TOKEN 0x3b
+#define DIV_TOKEN 0x3c
+#define LT_TOKEN 0x3d
+#define LE_TOKEN 0x3e
+#define GT_TOKEN 0x3f
+#define GE_TOKEN 0x40
+#define EQ_TOKEN 0x41
+#define NE_TOKEN 0x42
+#define AND_TOKEN 0x43
+#define OR_TOKEN 0x44
+#define MOD_TOKEN 0x45
+#define BAND_TOKEN 0x46
+#define SHL_TOKEN 0x47
+#define SHR_TOKEN 0x48
+#define BXOR_TOKEN 0x49
+#define BOR_TOKEN 0x4a
+#define POUND_TOKEN 0x4b /* matrix multiplication */
+
+#define LAST_BINARY_OP 0x4b
+#define IS_BINARY_OP(t) ((t >= FIRST_BINARY_OP) && (t <= LAST_BINARY_OP))
+
+/* unary tokens -- but not all of them (see grammar) */
+#define DEREF_TOKEN 0x4d
+#define NOT_TOKEN 0x4e
+#define BNOT_TOKEN 0x4f
+
+#define IS_INTERNAL_FUNC(t) ((t >= 0x50) && (t <= 0x56))
+#define POP_TOKEN 0x50
+#define CHS_TOKEN 0x51
+#define SIGN_TOKEN 0x52
+#define ABS_TOKEN 0x53
+#define SQR_TOKEN 0x54
+#define MUL2_TOKEN 0x55
+#define EXCH_TOKEN 0x56
+
+/* Assignment tokens. Note: these must appear with sequential values.
+ * The order here must match the specific lvalue assignments below.
+ * These tokens are used by rpn routines in slang.c. slparse.c maps them
+ * onto the specific lvalue tokens while parsing infix.
+ * Also the assignment _SLANG_BCST_ assumes this order
+ */
+#define ASSIGN_TOKEN 0x57
+#define PLUSEQS_TOKEN 0x58
+#define MINUSEQS_TOKEN 0x59
+#define TIMESEQS_TOKEN 0x5A
+#define DIVEQS_TOKEN 0x5B
+#define BOREQS_TOKEN 0x5C
+#define BANDEQS_TOKEN 0x5D
+#define PLUSPLUS_TOKEN 0x5E
+#define POST_PLUSPLUS_TOKEN 0x5F
+#define MINUSMINUS_TOKEN 0x60
+#define POST_MINUSMINUS_TOKEN 0x61
+
+/* Directives */
+#define FIRST_DIRECTIVE_TOKEN 0x62
+#define IFNOT_TOKEN 0x62
+#define IF_TOKEN 0x63
+#define ELSE_TOKEN 0x64
+#define FOREVER_TOKEN 0x65
+#define WHILE_TOKEN 0x66
+#define FOR_TOKEN 0x67
+#define _FOR_TOKEN 0x68
+#define LOOP_TOKEN 0x69
+#define SWITCH_TOKEN 0x6A
+#define DOWHILE_TOKEN 0x6B
+#define ANDELSE_TOKEN 0x6C
+#define ORELSE_TOKEN 0x6D
+#define ERRBLK_TOKEN 0x6E
+#define EXITBLK_TOKEN 0x6F
+/* These must be sequential */
+#define USRBLK0_TOKEN 0x70
+#define USRBLK1_TOKEN 0x71
+#define USRBLK2_TOKEN 0x72
+#define USRBLK3_TOKEN 0x73
+#define USRBLK4_TOKEN 0x74
+
+#define CONT_TOKEN 0x75
+#define BREAK_TOKEN 0x76
+#define RETURN_TOKEN 0x77
+
+#define CASE_TOKEN 0x78
+#define DEFINE_TOKEN 0x79
+#define DO_TOKEN 0x7a
+#define VARIABLE_TOKEN 0x7b
+#define GVARIABLE_TOKEN 0x7c
+#define _REF_TOKEN 0x7d
+#define PUSH_TOKEN 0x7e
+#define STRUCT_TOKEN 0x7f
+#define TYPEDEF_TOKEN 0x80
+#define NOTELSE_TOKEN 0x81
+#define DEFINE_STATIC_TOKEN 0x82
+#define FOREACH_TOKEN 0x83
+#define USING_TOKEN 0x84
+#define DEFINE_PRIVATE_TOKEN 0x85
+#define DEFINE_PUBLIC_TOKEN 0x86
+
+/* Note: the order here must match the order of the generic assignment tokens.
+ * Also, the first token of each group must be the ?_ASSIGN_TOKEN.
+ * slparse.c exploits this order, as well as slang.h.
+ */
+#define FIRST_ASSIGN_TOKEN 0x90
+#define _STRUCT_ASSIGN_TOKEN 0x90
+#define _STRUCT_PLUSEQS_TOKEN 0x91
+#define _STRUCT_MINUSEQS_TOKEN 0x92
+#define _STRUCT_TIMESEQS_TOKEN 0x93
+#define _STRUCT_DIVEQS_TOKEN 0x94
+#define _STRUCT_BOREQS_TOKEN 0x95
+#define _STRUCT_BANDEQS_TOKEN 0x96
+#define _STRUCT_PLUSPLUS_TOKEN 0x97
+#define _STRUCT_POST_PLUSPLUS_TOKEN 0x98
+#define _STRUCT_MINUSMINUS_TOKEN 0x99
+#define _STRUCT_POST_MINUSMINUS_TOKEN 0x9A
+
+#define _ARRAY_ASSIGN_TOKEN 0xA0
+#define _ARRAY_PLUSEQS_TOKEN 0xA1
+#define _ARRAY_MINUSEQS_TOKEN 0xA2
+#define _ARRAY_TIMESEQS_TOKEN 0xA3
+#define _ARRAY_DIVEQS_TOKEN 0xA4
+#define _ARRAY_BOREQS_TOKEN 0xA5
+#define _ARRAY_BANDEQS_TOKEN 0xA6
+#define _ARRAY_PLUSPLUS_TOKEN 0xA7
+#define _ARRAY_POST_PLUSPLUS_TOKEN 0xA8
+#define _ARRAY_MINUSMINUS_TOKEN 0xA9
+#define _ARRAY_POST_MINUSMINUS_TOKEN 0xAA
+
+#define _SCALAR_ASSIGN_TOKEN 0xB0
+#define _SCALAR_PLUSEQS_TOKEN 0xB1
+#define _SCALAR_MINUSEQS_TOKEN 0xB2
+#define _SCALAR_TIMESEQS_TOKEN 0xB3
+#define _SCALAR_DIVEQS_TOKEN 0xB4
+#define _SCALAR_BOREQS_TOKEN 0xB5
+#define _SCALAR_BANDEQS_TOKEN 0xB6
+#define _SCALAR_PLUSPLUS_TOKEN 0xB7
+#define _SCALAR_POST_PLUSPLUS_TOKEN 0xB8
+#define _SCALAR_MINUSMINUS_TOKEN 0xB9
+#define _SCALAR_POST_MINUSMINUS_TOKEN 0xBA
+
+#define _DEREF_ASSIGN_TOKEN 0xC0
+#define _DEREF_PLUSEQS_TOKEN 0xC1
+#define _DEREF_MINUSEQS_TOKEN 0xC2
+#define _DEREF_TIMESEQS_TOKEN 0xC3
+#define _DEREF_DIVEQS_TOKEN 0xC4
+#define _DEREF_BOREQS_TOKEN 0xC5
+#define _DEREF_BANDEQS_TOKEN 0xC6
+#define _DEREF_PLUSPLUS_TOKEN 0xC7
+#define _DEREF_POST_PLUSPLUS_TOKEN 0xC8
+#define _DEREF_MINUSMINUS_TOKEN 0xC9
+#define _DEREF_POST_MINUSMINUS_TOKEN 0xCA
+
+#define LAST_ASSIGN_TOKEN 0xCA
+#define IS_ASSIGN_TOKEN(t) (((t)>=FIRST_ASSIGN_TOKEN)&&((t)<=LAST_ASSIGN_TOKEN))
+
+#define _INLINE_ARRAY_TOKEN 0xE0
+#define _INLINE_IMPLICIT_ARRAY_TOKEN 0xE1
+#define _NULL_TOKEN 0xE2
+#define _INLINE_WILDCARD_ARRAY_TOKEN 0xE3
+
+#define LINE_NUM_TOKEN 0xFC
+#define ARG_TOKEN 0xFD
+#define EARG_TOKEN 0xFE
+#define NO_OP_LITERAL 0xFF
+
+typedef struct
+{
+ /* sltoken.c */
+ /* SLang_eval_object */
+ SLang_Load_Type *llt;
+ SLPreprocess_Type *this_slpp;
+ /* prep_get_char() */
+ char *input_line;
+ char cchar;
+ /* get_token() */
+ int want_nl_token;
+
+ /* slparse.c */
+ _SLang_Token_Type ctok;
+ int block_depth;
+ int assignment_expression;
+
+ /* slang.c : SLcompile() */
+ _SLang_Token_Type save_token;
+ _SLang_Token_Type next_token;
+ void (*slcompile_ptr)(_SLang_Token_Type *);
+}
+_SLEval_Context;
+
+extern int _SLget_token (_SLang_Token_Type *);
+extern void _SLparse_error (char *, _SLang_Token_Type *, int);
+extern void _SLparse_start (SLang_Load_Type *);
+extern int _SLget_rpn_token (_SLang_Token_Type *);
+extern void _SLcompile_byte_compiled (void);
+
+extern int (*_SLprep_eval_hook) (char *);
+
+#ifdef HAVE_VSNPRINTF
+#define _SLvsnprintf vsnprintf
+#else
+extern int _SLvsnprintf (char *, unsigned int, char *, va_list);
+#endif
+
+#ifdef HAVE_SNPRINTF
+# define _SLsnprintf snprintf
+#else
+extern int _SLsnprintf (char *, unsigned int, char *, ...);
+#endif
+
+#undef _INLINE_
+#if defined(__GNUC__) && _SLANG_USE_INLINE_CODE
+# define _INLINE_ __inline__
+#else
+# define _INLINE_
+#endif
+
+
+#endif /* _PRIVATE_SLANG_H_ */
diff --git a/mdk-stage1/slang/config.h b/mdk-stage1/slang/config.h
new file mode 100644
index 000000000..a5ab3273c
--- /dev/null
+++ b/mdk-stage1/slang/config.h
@@ -0,0 +1,163 @@
+/* src/sysconf.h. Generated automatically by configure. */
+/* -*- c -*- */
+/* Note: this is for unix only. */
+
+#ifndef SL_CONFIG_H
+#define SL_CONFIG_H
+
+/* define if you have stdlib.h */
+#define HAVE_STDLIB_H 1
+
+/* define if you have unistd.h */
+#define HAVE_UNISTD_H 1
+
+/* define if you have termios.h */
+#define HAVE_TERMIOS_H 1
+
+/* define if you have memory.h */
+#define HAVE_MEMORY_H 1
+
+/* define if you have malloc.h */
+#define HAVE_MALLOC_H 1
+
+/* define if you have memset */
+#define HAVE_MEMSET 1
+
+/* define if you have memcpy */
+#define HAVE_MEMCPY 1
+
+//#define HAVE_SETLOCALE 1
+//#define HAVE_LOCALE_H 1
+
+#define HAVE_VFSCANF 1
+
+/* define if you have fcntl.h */
+#define HAVE_FCNTL_H 1
+
+/* Define if you have the vsnprintf, snprintf functions and they return
+ * EOF upon failure.
+ */
+#define HAVE_VSNPRINTF 1
+#define HAVE_SNPRINTF 1
+
+/* define if you have sys/fcntl.h */
+#define HAVE_SYS_FCNTL_H 1
+
+#define HAVE_SYS_TYPES_H 1
+#define HAVE_SYS_WAIT_H 1
+#define HAVE_SYS_TIMES_H 1
+
+/* Set these to the appropriate values */
+#define SIZEOF_SHORT 2
+#define SIZEOF_INT 4
+#define SIZEOF_LONG 4
+#define SIZEOF_FLOAT 4
+#define SIZEOF_DOUBLE 8
+
+/* define if you have these. */
+#define HAVE_ATEXIT 1
+#define HAVE_ON_EXIT 1
+#define HAVE_PUTENV 1
+#define HAVE_GETCWD 1
+#define HAVE_TCGETATTR 1
+#define HAVE_TCSETATTR 1
+#define HAVE_CFGETOSPEED 1
+#define HAVE_LSTAT 1
+#define HAVE_KILL 1
+#define HAVE_CHOWN 1
+#define HAVE_VSNPRINTF 1
+#define HAVE_POPEN 1
+#define HAVE_UMASK 1
+#define HAVE_READLINK 1
+#define HAVE_TIMES 1
+#define HAVE_GMTIME 1
+#define HAVE_MKFIFO 1
+
+#define HAVE_GETPPID 1
+#define HAVE_GETGID 1
+#define HAVE_GETEGID 1
+#define HAVE_GETEUID 1
+/* #undef HAVE_GETUID */
+
+#define HAVE_SETGID 1
+#define HAVE_SETPGID 1
+#define HAVE_SETUID 1
+
+#define HAVE_ACOSH 1
+#define HAVE_ASINH 1
+#define HAVE_ATANH 1
+
+#define HAVE_DIRENT_H 1
+/* #undef HAVE_SYS_NDIR_H */
+/* #undef HAVE_SYS_DIR_H */
+/* #undef HAVE_NDIR_H */
+
+#define HAVE_DLFCN_H 1
+
+#define HAVE_SYS_UTSNAME_H 1
+#define HAVE_UNAME 1
+
+/* These two are needed on DOS-like systems. Unix does not require them.
+ * They are included here for consistency.
+ *
+#define HAVE_IO_H
+#define HAVE_PROCESS_H
+ */
+
+/* #undef USE_TERMCAP */
+
+/* #undef mode_t */
+/* #undef uid_t */
+/* #undef pid_t */
+/* #undef gid_t */
+
+/* Do we have posix signals? */
+#define HAVE_SIGACTION 1
+#define HAVE_SIGPROCMASK 1
+#define HAVE_SIGEMPTYSET 1
+#define HAVE_SIGADDSET 1
+
+#if defined(HAVE_SIGADDSET) && defined(HAVE_SIGEMPTYSET)
+# if defined(HAVE_SIGACTION) && defined(HAVE_SIGPROCMASK)
+# define SLANG_POSIX_SIGNALS
+# endif
+#endif
+
+/* Define if you need to in order for stat and other things to work. */
+/* #undef _POSIX_SOURCE */
+
+#ifdef _AIX
+# ifndef _POSIX_SOURCE
+# define _POSIX_SOURCE 1
+# endif
+# ifndef _ALL_SOURCE
+# define _ALL_SOURCE
+# endif
+/* This may generate warnings but the fact is that without it, xlc will
+ * INCORRECTLY inline many str* functions. */
+/* # undef __STR__ */
+#endif
+
+/* define USE_TERMCAP if you want to use it instead of terminfo. */
+#if defined(sequent) || defined(NeXT)
+# ifndef USE_TERMCAP
+# define USE_TERMCAP
+# endif
+#endif
+
+#if defined(ultrix) && !defined(__GNUC__)
+# ifndef NO_PROTOTYPES
+# define NO_PROTOTYPES
+# endif
+#endif
+
+#ifndef unix
+# define unix 1
+#endif
+
+#ifndef __unix__
+# define __unix__ 1
+#endif
+
+#define _SLANG_SOURCE_ 1
+#endif /* SL_CONFIG_H */
diff --git a/mdk-stage1/slang/jdmacros.h b/mdk-stage1/slang/jdmacros.h
new file mode 100644
index 000000000..70d491b78
--- /dev/null
+++ b/mdk-stage1/slang/jdmacros.h
@@ -0,0 +1,53 @@
+#ifndef _JD_MACROS_H_
+#define _JD_MACROS_H_
+
+#ifndef SLMEMSET
+# ifdef HAVE_MEMSET
+# define SLMEMSET memset
+# else
+# define SLMEMSET SLmemset
+# endif
+#endif
+
+#ifndef SLMEMCHR
+# ifdef HAVE_MEMCHR
+# define SLMEMCHR memchr
+# else
+# define SLMEMCHR SLmemchr
+# endif
+#endif
+
+#ifndef SLMEMCPY
+# ifdef HAVE_MEMCPY
+# define SLMEMCPY memcpy
+# else
+# define SLMEMCPY SLmemcpy
+# endif
+#endif
+
+/* Note: HAVE_MEMCMP requires an unsigned memory comparison!!! */
+#ifndef SLMEMCMP
+# ifdef HAVE_MEMCMP
+# define SLMEMCMP memcmp
+# else
+# define SLMEMCMP SLmemcmp
+# endif
+#endif
+
+#ifndef SLFREE
+# define SLFREE free
+#endif
+
+#ifndef SLMALLOC
+# define SLMALLOC malloc
+#endif
+
+#ifndef SLCALLOC
+# define SLCALLOC calloc
+#endif
+
+#ifndef SLREALLOC
+# define SLREALLOC realloc
+#endif
+
+#endif /* _JD_MACROS_H_ */
diff --git a/mdk-stage1/slang/keywhash.c b/mdk-stage1/slang/keywhash.c
new file mode 100644
index 000000000..17d94d5a3
--- /dev/null
+++ b/mdk-stage1/slang/keywhash.c
@@ -0,0 +1,190 @@
+/* Perfect hash generated by command line:
+ * ./a.out 1
+ */
+#define MIN_HASH_VALUE 2
+#define MAX_HASH_VALUE 118
+#define MIN_KEYWORD_LEN 2
+#define MAX_KEYWORD_LEN 11
+
+static unsigned char Keyword_Hash_Table [256] =
+{
+ 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119,
+ 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119,
+ 119, 1, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119,
+ 9, 7, 1, 8, 2, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119,
+ 119, 119, 0, 0, 119, 0, 119, 119, 119, 7, 119, 0, 0, 119, 119, 0,
+ 119, 119, 0, 0, 0, 0, 119, 119, 0, 119, 119, 119, 119, 119, 119, 2,
+ 119, 41, 1, 1, 9, 0, 55, 8, 0, 0, 119, 0, 27, 0, 0, 0,
+ 7, 2, 0, 21, 0, 0, 0, 3, 2, 0, 119, 119, 119, 119, 119, 119,
+ 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119,
+ 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119,
+ 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119,
+ 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119,
+ 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119,
+ 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119,
+ 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119,
+ 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119
+};
+
+static unsigned char keyword_hash (char *s, unsigned int len)
+{
+ unsigned int sum;
+
+ sum = len;
+ while (len)
+ {
+ len--;
+ sum += (unsigned int) Keyword_Hash_Table [(unsigned char)s[len]];
+ }
+ return sum;
+}
+
+typedef struct
+{
+ char *name;
+ unsigned int type;
+}
+Keyword_Table_Type;
+
+static Keyword_Table_Type Keyword_Table [/* 117 */] =
+{
+ {"or", OR_TOKEN},
+ {"not", NOT_TOKEN},
+ {NULL,0},
+ {"xor", BXOR_TOKEN},
+ {"return", RETURN_TOKEN},
+ {"exch", EXCH_TOKEN},
+ {NULL,0},
+ {"continue", CONT_TOKEN},
+ {NULL,0},
+ {"do", DO_TOKEN},
+ {"mod", MOD_TOKEN},
+ {"ERROR_BLOCK", ERRBLK_TOKEN},
+ {"USER_BLOCK2", USRBLK2_TOKEN},
+ {"USER_BLOCK4", USRBLK4_TOKEN},
+ {"__tmp", TMP_TOKEN},
+ {"pop", POP_TOKEN},
+ {NULL,0},
+ {"EXIT_BLOCK", EXITBLK_TOKEN},
+ {"USER_BLOCK1", USRBLK1_TOKEN},
+ {"USER_BLOCK3", USRBLK3_TOKEN},
+ {"USER_BLOCK0", USRBLK0_TOKEN},
+ {NULL,0},
+ {"shr", SHR_TOKEN},
+ {"chs", CHS_TOKEN},
+ {"sqr", SQR_TOKEN},
+ {NULL,0},
+ {"struct", STRUCT_TOKEN},
+ {NULL,0},
+ {NULL,0},
+ {"switch", SWITCH_TOKEN},
+ {"mul2", MUL2_TOKEN},
+ {"sign", SIGN_TOKEN},
+ {"using", USING_TOKEN},
+ {"while", WHILE_TOKEN},
+ {NULL,0},
+ {NULL,0},
+ {"loop", LOOP_TOKEN},
+ {NULL,0},
+ {NULL,0},
+ {NULL,0},
+ {"public", PUBLIC_TOKEN},
+ {NULL,0},
+ {NULL,0},
+ {NULL,0},
+ {NULL,0},
+ {"break", BREAK_TOKEN},
+ {NULL,0},
+ {"do_while", DOWHILE_TOKEN},
+ {NULL,0},
+ {"shl", SHL_TOKEN},
+ {"else", ELSE_TOKEN},
+ {"and", AND_TOKEN},
+ {"orelse", ORELSE_TOKEN},
+ {"private", PRIVATE_TOKEN},
+ {NULL,0},
+ {"if", IF_TOKEN},
+ {"for", FOR_TOKEN},
+ {"!if", IFNOT_TOKEN},
+ {NULL,0},
+ {"_for", _FOR_TOKEN},
+ {"forever", FOREVER_TOKEN},
+ {NULL,0},
+ {NULL,0},
+ {NULL,0},
+ {"abs", ABS_TOKEN},
+ {"case", CASE_TOKEN},
+ {NULL,0},
+ {"static", STATIC_TOKEN},
+ {"define", DEFINE_TOKEN},
+ {NULL,0},
+ {NULL,0},
+ {NULL,0},
+ {NULL,0},
+ {NULL,0},
+ {NULL,0},
+ {NULL,0},
+ {"typedef", TYPEDEF_TOKEN},
+ {NULL,0},
+ {NULL,0},
+ {NULL,0},
+ {NULL,0},
+ {NULL,0},
+ {NULL,0},
+ {NULL,0},
+ {NULL,0},
+ {NULL,0},
+ {NULL,0},
+ {NULL,0},
+ {NULL,0},
+ {NULL,0},
+ {NULL,0},
+ {NULL,0},
+ {NULL,0},
+ {NULL,0},
+ {NULL,0},
+ {NULL,0},
+ {NULL,0},
+ {NULL,0},
+ {NULL,0},
+ {NULL,0},
+ {NULL,0},
+ {NULL,0},
+ {"foreach", FOREACH_TOKEN},
+ {"andelse", ANDELSE_TOKEN},
+ {NULL,0},
+ {NULL,0},
+ {NULL,0},
+ {NULL,0},
+ {NULL,0},
+ {NULL,0},
+ {NULL,0},
+ {NULL,0},
+ {NULL,0},
+ {NULL,0},
+ {NULL,0},
+ {NULL,0},
+ {"variable", VARIABLE_TOKEN},
+};
+
+static Keyword_Table_Type *is_keyword (char *str, unsigned int len)
+{
+ unsigned int hash;
+ char *name;
+ Keyword_Table_Type *kw;
+
+ if ((len < MIN_KEYWORD_LEN)
+ || (len > MAX_KEYWORD_LEN))
+ return NULL;
+
+ hash = keyword_hash (str, len);
+ if ((hash > MAX_HASH_VALUE) || (hash < MIN_HASH_VALUE))
+ return NULL;
+
+ kw = &Keyword_Table[hash - MIN_HASH_VALUE];
+ if ((NULL != (name = kw->name))
+ && (*str == *name)
+ && (0 == strcmp (str, name)))
+ return kw;
+ return NULL;
+}
diff --git a/mdk-stage1/slang/sl-feat.h b/mdk-stage1/slang/sl-feat.h
new file mode 100644
index 000000000..511d72451
--- /dev/null
+++ b/mdk-stage1/slang/sl-feat.h
@@ -0,0 +1,60 @@
+/* Setting this to 1 enables automatic support for associative arrays.
+ * If this is set to 0, an application must explicitly enable associative
+ * array support via SLang_init_slassoc.
+ */
+#define SLANG_HAS_ASSOC_ARRAYS 1
+
+#define SLANG_HAS_COMPLEX 1
+#define SLANG_HAS_FLOAT 1
+
+/* This is the old space-speed trade off. To reduce memory usage and code
+ * size, set this to zero.
+ */
+#define _SLANG_OPTIMIZE_FOR_SPEED 2
+
+#define _SLANG_USE_INLINE_CODE 1
+
+/* This is experimental. It adds extra information for tracking down
+ * errors.
+ */
+#define _SLANG_HAS_DEBUG_CODE 1
+
+/* Allow optimizations based upon the __tmp operator. */
+#define _SLANG_USE_TMP_OPTIMIZATION 1
+
+/* Setting this to one will map 8 bit vtxxx terminals to 7 bit. Terminals
+ * such as the vt320 can be set up to output the two-character escape sequence
+ * encoded as 'ESC [' as single character. Setting this variable to 1 will
+ * insert code to map such characters to the 7 bit equivalent.
+ * This affects just input characters in the range 128-160 on non PC
+ * systems.
+ */
+#if defined(VMS) || defined(AMIGA)
+# define _SLANG_MAP_VTXXX_8BIT 1
+#else
+# define _SLANG_MAP_VTXXX_8BIT 0
+#endif
+
+/* Add support for color terminals that cannot do background color erases
+ * Such terminals are poorly designed and are slowly disappearing but they
+ * are still quite common. For example, screen is one of them!
+ *
+ * This is experimental. In particular, it is not known to work if
+ * KANJI suupport is enabled.
+ */
+#if !defined(IBMPC_SYSTEM)
+# define SLTT_HAS_NON_BCE_SUPPORT 1
+#else
+# define SLTT_HAS_NON_BCE_SUPPORT 0
+#endif
+
+/* If you want slang to assume that an xterm always has the background color
+ * erase feature, then set this to 1. Otherwise, it will check the terminfo
+ * database. This may or may not be a good idea since most good color xterms
+ * support bce but many terminfo systems do not support it.
+ */
+#define SLTT_XTERM_ALWAYS_BCE 0
+
+/* Set this to 1 to enable Kanji support. See above comment. */
+#define SLANG_HAS_KANJI_SUPPORT 0
+
diff --git a/mdk-stage1/slang/slang.c b/mdk-stage1/slang/slang.c
new file mode 100644
index 000000000..6edc7df37
--- /dev/null
+++ b/mdk-stage1/slang/slang.c
@@ -0,0 +1,5547 @@
+/* -*- mode: C; mode: fold; -*- */
+/* slang.c --- guts of S-Lang interpreter */
+/* Copyright (c) 1992, 1999, 2001 John E. Davis
+ * This file is part of the S-Lang library.
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Perl Artistic License.
+ */
+
+#include "slinclud.h"
+
+#if SLANG_HAS_FLOAT
+# include <math.h>
+#endif
+
+#include "slang.h"
+#include "_slang.h"
+
+#define USE_COMBINED_BYTECODES 0
+
+struct _SLBlock_Type;
+
+typedef struct
+{
+ struct _SLBlock_Type *body;
+ unsigned int num_refs;
+}
+_SLBlock_Header_Type;
+
+typedef struct
+{
+ char *name;
+ SLang_Name_Type *next;
+ char name_type;
+
+ union
+ {
+ _SLBlock_Header_Type *header; /* body of function */
+ char *autoload_filename;
+ }
+ v;
+#if _SLANG_HAS_DEBUG_CODE
+ char *file;
+#endif
+#define SLANG_MAX_LOCAL_VARIABLES 254
+#define AUTOLOAD_NUM_LOCALS (SLANG_MAX_LOCAL_VARIABLES + 1)
+ unsigned char nlocals; /* number of local variables */
+ unsigned char nargs; /* number of arguments */
+}
+_SLang_Function_Type;
+
+typedef struct
+{
+ char *name;
+ SLang_Name_Type *next;
+ char name_type;
+
+ SLang_Object_Type obj;
+}
+SLang_Global_Var_Type;
+
+typedef struct
+{
+ char *name;
+ SLang_Name_Type *next;
+ char name_type;
+
+ int local_var_number;
+}
+SLang_Local_Var_Type;
+
+typedef struct _SLBlock_Type
+{
+ unsigned char bc_main_type;
+ unsigned char bc_sub_type;
+ union
+ {
+ struct _SLBlock_Type *blk;
+ int i_blk;
+
+ SLang_Name_Type *nt_blk;
+ SLang_App_Unary_Type *nt_unary_blk;
+ SLang_Intrin_Var_Type *nt_ivar_blk;
+ SLang_Intrin_Fun_Type *nt_ifun_blk;
+ SLang_Global_Var_Type *nt_gvar_blk;
+ SLang_IConstant_Type *iconst_blk;
+ SLang_DConstant_Type *dconst_blk;
+ _SLang_Function_Type *nt_fun_blk;
+
+ VOID_STAR ptr_blk;
+ char *s_blk;
+ SLang_BString_Type *bs_blk;
+
+#if SLANG_HAS_FLOAT
+ double *double_blk; /*literal double is a pointer */
+#endif
+ float float_blk;
+ long l_blk;
+ struct _SLang_Struct_Type *struct_blk;
+ int (*call_function)(void);
+ }
+ b;
+}
+SLBlock_Type;
+
+/* Debugging and tracing variables */
+
+void (*SLang_Enter_Function)(char *) = NULL;
+void (*SLang_Exit_Function)(char *) = NULL;
+/* If non null, these call C functions before and after a slang function. */
+
+int _SLang_Trace = 0;
+/* If _SLang_Trace = -1, do not trace intrinsics */
+static int Trace_Mode = 0;
+
+static char *Trace_Function; /* function to be traced */
+int SLang_Traceback = 0;
+/* non zero means do traceback. If less than 0, do not show local variables */
+
+/* These variables handle _NARGS processing by the parser */
+int SLang_Num_Function_Args;
+static int *Num_Args_Stack;
+static unsigned int Recursion_Depth;
+static SLang_Object_Type *Frame_Pointer;
+static int Next_Function_Num_Args;
+static unsigned int Frame_Pointer_Depth;
+static unsigned int *Frame_Pointer_Stack;
+
+static int Lang_Break_Condition = 0;
+/* true if any one below is true. This keeps us from testing 3 variables.
+ * I know this can be perfomed with a bitmapped variable, but...
+ */
+static int Lang_Break = 0;
+static int Lang_Return = 0;
+/* static int Lang_Continue = 0; */
+
+SLang_Object_Type *_SLRun_Stack;
+SLang_Object_Type *_SLStack_Pointer;
+static SLang_Object_Type *_SLStack_Pointer_Max;
+
+/* Might want to increase this. */
+static SLang_Object_Type Local_Variable_Stack[SLANG_MAX_LOCAL_STACK];
+static SLang_Object_Type *Local_Variable_Frame = Local_Variable_Stack;
+
+static void free_function_header (_SLBlock_Header_Type *);
+
+void (*SLang_Dump_Routine)(char *);
+
+static void call_dump_routine (char *fmt, ...)
+{
+ char buf[1024];
+ va_list ap;
+
+ va_start (ap, fmt);
+ if (SLang_Dump_Routine != NULL)
+ {
+ (void) _SLvsnprintf (buf, sizeof (buf), fmt, ap);
+ (*SLang_Dump_Routine) (buf);
+ }
+ else
+ {
+ vfprintf (stderr, fmt, ap);
+ fflush (stderr);
+ }
+ va_end (ap);
+}
+
+static void do_traceback (char *, unsigned int, char *);
+static int init_interpreter (void);
+
+/*{{{ push/pop/etc stack manipulation functions */
+
+/* This routine is assumed to work even in the presence of a SLang_Error. */
+_INLINE_
+int SLang_pop (SLang_Object_Type *x)
+{
+ register SLang_Object_Type *y;
+
+ y = _SLStack_Pointer;
+ if (y == _SLRun_Stack)
+ {
+ if (SLang_Error == 0) SLang_Error = SL_STACK_UNDERFLOW;
+ x->data_type = 0;
+ return -1;
+ }
+ y--;
+ *x = *y;
+
+ _SLStack_Pointer = y;
+ return 0;
+}
+
+static int pop_ctrl_integer (int *i)
+{
+ int type;
+ SLang_Class_Type *cl;
+#if _SLANG_OPTIMIZE_FOR_SPEED
+ register SLang_Object_Type *y;
+
+ /* Most of the time, either an integer or a char will be on the stack.
+ * Optimize these cases.
+ */
+ y = _SLStack_Pointer;
+ if (y == _SLRun_Stack)
+ {
+ if (SLang_Error == 0) SLang_Error = SL_STACK_UNDERFLOW;
+ return -1;
+ }
+ y--;
+
+ type = y->data_type;
+ if (type == SLANG_INT_TYPE)
+ {
+ _SLStack_Pointer = y;
+ *i = y->v.int_val;
+ return 0;
+ }
+ if (type == SLANG_CHAR_TYPE)
+ {
+ _SLStack_Pointer = y;
+ *i = y->v.char_val;
+ return 0;
+ }
+#else
+ if (-1 == (type = SLang_peek_at_stack ()))
+ return -1;
+#endif
+
+ cl = _SLclass_get_class ((unsigned char) type);
+ if (cl->cl_to_bool == NULL)
+ {
+ SLang_verror (SL_TYPE_MISMATCH,
+ "%s cannot be used in a boolean context",
+ cl->cl_name);
+ return -1;
+ }
+ return cl->cl_to_bool ((unsigned char) type, i);
+}
+
+_INLINE_
+int SLang_peek_at_stack (void)
+{
+ if (_SLStack_Pointer == _SLRun_Stack)
+ {
+ if (SLang_Error == 0)
+ SLang_Error = SL_STACK_UNDERFLOW;
+ return -1;
+ }
+
+ return (_SLStack_Pointer - 1)->data_type;
+}
+
+int SLang_peek_at_stack1 (void)
+{
+ int type;
+
+ type = SLang_peek_at_stack ();
+ if (type == SLANG_ARRAY_TYPE)
+ type = (_SLStack_Pointer - 1)->v.array_val->data_type;
+
+ return type;
+}
+
+_INLINE_
+void SLang_free_object (SLang_Object_Type *obj)
+{
+ unsigned char data_type;
+ SLang_Class_Type *cl;
+
+ if (obj == NULL) return;
+ data_type = obj->data_type;
+#if _SLANG_OPTIMIZE_FOR_SPEED
+ if (SLANG_CLASS_TYPE_SCALAR == _SLclass_Class_Type [data_type])
+ return;
+ if (data_type == SLANG_STRING_TYPE)
+ {
+ SLang_free_slstring (obj->v.s_val);
+ return;
+ }
+#endif
+ cl = _SLclass_get_class (data_type);
+#if !_SLANG_OPTIMIZE_FOR_SPEED
+ if (cl->cl_class_type != SLANG_CLASS_TYPE_SCALAR)
+#endif
+ (*cl->cl_destroy) (data_type, (VOID_STAR) &obj->v);
+}
+
+_INLINE_
+int SLang_push (SLang_Object_Type *x)
+{
+ register SLang_Object_Type *y;
+ y = _SLStack_Pointer;
+
+ /* if there is a SLang_Error, probably not much harm will be done
+ if it is ignored here */
+ /* if (SLang_Error) return; */
+
+ /* flag it now */
+ if (y >= _SLStack_Pointer_Max)
+ {
+ if (!SLang_Error) SLang_Error = SL_STACK_OVERFLOW;
+ return -1;
+ }
+
+ *y = *x;
+ _SLStack_Pointer = y + 1;
+ return 0;
+}
+
+/* _INLINE_ */
+int SLclass_push_ptr_obj (unsigned char type, VOID_STAR pval)
+{
+ register SLang_Object_Type *y;
+ y = _SLStack_Pointer;
+
+ if (y >= _SLStack_Pointer_Max)
+ {
+ if (!SLang_Error) SLang_Error = SL_STACK_OVERFLOW;
+ return -1;
+ }
+
+ y->data_type = type;
+ y->v.ptr_val = pval;
+
+ _SLStack_Pointer = y + 1;
+ return 0;
+}
+
+_INLINE_
+int SLclass_push_int_obj (unsigned char type, int x)
+{
+ register SLang_Object_Type *y;
+ y = _SLStack_Pointer;
+
+ if (y >= _SLStack_Pointer_Max)
+ {
+ if (!SLang_Error) SLang_Error = SL_STACK_OVERFLOW;
+ return -1;
+ }
+
+ y->data_type = type;
+ y->v.int_val = x;
+
+ _SLStack_Pointer = y + 1;
+ return 0;
+}
+
+_INLINE_
+int _SLang_pop_object_of_type (unsigned char type, SLang_Object_Type *obj,
+ int allow_arrays)
+{
+ register SLang_Object_Type *y;
+
+ y = _SLStack_Pointer;
+ if (y == _SLRun_Stack)
+ return SLang_pop (obj);
+ y--;
+ if (y->data_type != type)
+ {
+#if _SLANG_OPTIMIZE_FOR_SPEED
+ /* This is an implicit typecast. We do not want to typecast
+ * floats to ints implicitly.
+ */
+ if (_SLarith_Is_Arith_Type [type]
+ && _SLarith_Is_Arith_Type [y->data_type]
+ && (_SLarith_Is_Arith_Type [type] >= _SLarith_Is_Arith_Type[y->data_type]))
+ {
+ /* This should not fail */
+ (void) _SLarith_typecast (y->data_type, (VOID_STAR)&y->v, 1,
+ type, (VOID_STAR)&obj->v);
+ obj->data_type = type;
+ _SLStack_Pointer = y;
+ return 0;
+ }
+#endif
+
+ if ((allow_arrays == 0)
+ || (y->data_type != SLANG_ARRAY_TYPE)
+ || (y->v.array_val->data_type != type))
+ if (-1 == SLclass_typecast (type, 1, 0))
+ return -1;
+ }
+ *obj = *y;
+ _SLStack_Pointer = y;
+ return 0;
+}
+
+/* This function reverses the top n items on the stack and returns a
+ * an offset from the start of the stack to the last item.
+ */
+int SLreverse_stack (int n)
+{
+ SLang_Object_Type *otop, *obot, tmp;
+
+ otop = _SLStack_Pointer;
+ if ((n > otop - _SLRun_Stack) || (n < 0))
+ {
+ SLang_Error = SL_STACK_UNDERFLOW;
+ return -1;
+ }
+ obot = otop - n;
+ otop--;
+ while (otop > obot)
+ {
+ tmp = *obot;
+ *obot = *otop;
+ *otop = tmp;
+ otop--;
+ obot++;
+ }
+ return (int) ((_SLStack_Pointer - n) - _SLRun_Stack);
+}
+
+_INLINE_
+int SLroll_stack (int np)
+{
+ int n, i;
+ SLang_Object_Type *otop, *obot, tmp;
+
+ if ((n = abs(np)) <= 1) return 0; /* identity */
+
+ obot = otop = _SLStack_Pointer;
+ i = n;
+ while (i != 0)
+ {
+ if (obot <= _SLRun_Stack)
+ {
+ SLang_Error = SL_STACK_UNDERFLOW;
+ return -1;
+ }
+ obot--;
+ i--;
+ }
+ otop--;
+
+ if (np > 0)
+ {
+ /* Put top on bottom and roll rest up. */
+ tmp = *otop;
+ while (otop > obot)
+ {
+ *otop = *(otop - 1);
+ otop--;
+ }
+ *otop = tmp;
+ }
+ else
+ {
+ /* Put bottom on top and roll rest down. */
+ tmp = *obot;
+ while (obot < otop)
+ {
+ *obot = *(obot + 1);
+ obot++;
+ }
+ *obot = tmp;
+ }
+ return 0;
+}
+
+int _SLstack_depth (void)
+{
+ return (int) (_SLStack_Pointer - _SLRun_Stack);
+}
+
+int SLdup_n (int n)
+{
+ SLang_Object_Type *bot, *top;
+
+ if (n <= 0)
+ return 0;
+
+ top = _SLStack_Pointer;
+ if (top < _SLRun_Stack + n)
+ {
+ if (SLang_Error == 0)
+ SLang_Error = SL_STACK_UNDERFLOW;
+ return -1;
+ }
+ if (top + n > _SLStack_Pointer_Max)
+ {
+ if (SLang_Error == 0)
+ SLang_Error = SL_STACK_OVERFLOW;
+ return -1;
+ }
+ bot = top - n;
+
+ while (bot < top)
+ {
+ SLang_Class_Type *cl;
+ unsigned char data_type = bot->data_type;
+
+#if _SLANG_OPTIMIZE_FOR_SPEED
+ if (SLANG_CLASS_TYPE_SCALAR == _SLclass_Class_Type [data_type])
+ {
+ *_SLStack_Pointer++ = *bot++;
+ continue;
+ }
+#endif
+ cl = _SLclass_get_class (data_type);
+ if (-1 == (*cl->cl_push) (data_type, (VOID_STAR) &bot->v))
+ return -1;
+ bot++;
+ }
+ return 0;
+}
+
+/*}}}*/
+
+/*{{{ inner interpreter and support functions */
+
+_INLINE_
+int _SL_increment_frame_pointer (void)
+{
+ if (Recursion_Depth >= SLANG_MAX_RECURSIVE_DEPTH)
+ {
+ SLang_verror (SL_STACK_OVERFLOW, "Num Args Stack Overflow");
+ return -1;
+ }
+ Num_Args_Stack [Recursion_Depth] = SLang_Num_Function_Args;
+
+ SLang_Num_Function_Args = Next_Function_Num_Args;
+ Next_Function_Num_Args = 0;
+ Recursion_Depth++;
+ return 0;
+}
+
+_INLINE_
+int _SL_decrement_frame_pointer (void)
+{
+ if (Recursion_Depth == 0)
+ {
+ SLang_verror (SL_STACK_UNDERFLOW, "Num Args Stack Underflow");
+ return -1;
+ }
+
+ Recursion_Depth--;
+ if (Recursion_Depth < SLANG_MAX_RECURSIVE_DEPTH)
+ SLang_Num_Function_Args = Num_Args_Stack [Recursion_Depth];
+
+ return 0;
+}
+
+_INLINE_
+int SLang_start_arg_list (void)
+{
+ if (Frame_Pointer_Depth < SLANG_MAX_RECURSIVE_DEPTH)
+ {
+ Frame_Pointer_Stack [Frame_Pointer_Depth] = (unsigned int) (Frame_Pointer - _SLRun_Stack);
+ Frame_Pointer = _SLStack_Pointer;
+ Frame_Pointer_Depth++;
+ Next_Function_Num_Args = 0;
+ return 0;
+ }
+
+ SLang_verror (SL_STACK_OVERFLOW, "Frame Stack Overflow");
+ return -1;
+}
+
+_INLINE_
+int SLang_end_arg_list (void)
+{
+ if (Frame_Pointer_Depth == 0)
+ {
+ SLang_verror (SL_STACK_UNDERFLOW, "Frame Stack Underflow");
+ return -1;
+ }
+ Frame_Pointer_Depth--;
+ if (Frame_Pointer_Depth < SLANG_MAX_RECURSIVE_DEPTH)
+ {
+ Next_Function_Num_Args = (int) (_SLStack_Pointer - Frame_Pointer);
+ Frame_Pointer = _SLRun_Stack + Frame_Pointer_Stack [Frame_Pointer_Depth];
+ }
+ return 0;
+}
+
+_INLINE_
+static int do_bc_call_direct_frame (int (*f)(void))
+{
+ if ((0 == SLang_end_arg_list ())
+ && (0 == _SL_increment_frame_pointer ()))
+ {
+ (void) (*f) ();
+ _SL_decrement_frame_pointer ();
+ }
+ if (SLang_Error)
+ return -1;
+ return 0;
+}
+
+static int do_name_type_error (SLang_Name_Type *nt)
+{
+ char buf[256];
+ if (nt != NULL)
+ {
+ (void) _SLsnprintf (buf, sizeof (buf), "(Error occurred processing %s)", nt->name);
+ do_traceback (buf, 0, NULL);
+ }
+ return -1;
+}
+
+/* local and global variable assignments */
+
+static int do_binary_ab (int op, SLang_Object_Type *obja, SLang_Object_Type *objb)
+{
+ SLang_Class_Type *a_cl, *b_cl, *c_cl;
+ unsigned char b_data_type, a_data_type, c_data_type;
+ int (*binary_fun) (int,
+ unsigned char, VOID_STAR, unsigned int,
+ unsigned char, VOID_STAR, unsigned int,
+ VOID_STAR);
+ VOID_STAR pa;
+ VOID_STAR pb;
+ VOID_STAR pc;
+ int ret;
+
+ b_data_type = objb->data_type;
+ a_data_type = obja->data_type;
+
+#if _SLANG_OPTIMIZE_FOR_SPEED
+ if (_SLarith_Is_Arith_Type[a_data_type]
+ && _SLarith_Is_Arith_Type[b_data_type])
+ {
+ int status;
+ status = _SLarith_bin_op (obja, objb, op);
+ if (status != 1)
+ return status;
+ /* drop and try it the hard way */
+ }
+#endif
+
+ a_cl = _SLclass_get_class (a_data_type);
+ if (a_data_type == b_data_type)
+ b_cl = a_cl;
+ else
+ b_cl = _SLclass_get_class (b_data_type);
+
+ if (NULL == (binary_fun = _SLclass_get_binary_fun (op, a_cl, b_cl, &c_cl, 1)))
+ return -1;
+
+ c_data_type = c_cl->cl_data_type;
+
+#if _SLANG_OPTIMIZE_FOR_SPEED
+ if (SLANG_CLASS_TYPE_SCALAR == _SLclass_Class_Type [a_data_type])
+ pa = (VOID_STAR) &obja->v;
+ else
+#endif
+ pa = _SLclass_get_ptr_to_value (a_cl, obja);
+
+#if _SLANG_OPTIMIZE_FOR_SPEED
+ if (SLANG_CLASS_TYPE_SCALAR == _SLclass_Class_Type [b_data_type])
+ pb = (VOID_STAR) &objb->v;
+ else
+#endif
+ pb = _SLclass_get_ptr_to_value (b_cl, objb);
+
+ pc = c_cl->cl_transfer_buf;
+
+ if (1 != (*binary_fun) (op,
+ a_data_type, pa, 1,
+ b_data_type, pb, 1,
+ pc))
+ {
+ SLang_verror (SL_NOT_IMPLEMENTED,
+ "Binary operation between %s and %s failed",
+ a_cl->cl_name, b_cl->cl_name);
+
+ return -1;
+ }
+
+ /* apush will create a copy, so make sure we free after the push */
+ ret = (*c_cl->cl_apush)(c_data_type, pc);
+#if _SLANG_OPTIMIZE_FOR_SPEED
+ if (SLANG_CLASS_TYPE_SCALAR != _SLclass_Class_Type [c_data_type])
+#endif
+ (*c_cl->cl_adestroy)(c_data_type, pc);
+
+ return ret;
+}
+
+_INLINE_
+static void do_binary (int op)
+{
+ SLang_Object_Type obja, objb;
+
+ if (SLang_pop (&objb)) return;
+ if (0 == SLang_pop (&obja))
+ {
+ (void) do_binary_ab (op, &obja, &objb);
+#if _SLANG_OPTIMIZE_FOR_SPEED
+ if (SLANG_CLASS_TYPE_SCALAR != _SLclass_Class_Type [obja.data_type])
+#endif
+ SLang_free_object (&obja);
+ }
+#if _SLANG_OPTIMIZE_FOR_SPEED
+ if (SLANG_CLASS_TYPE_SCALAR != _SLclass_Class_Type [objb.data_type])
+#endif
+ SLang_free_object (&objb);
+}
+
+static int do_unary_op (int op, SLang_Object_Type *obj, int unary_type)
+{
+ int (*f) (int, unsigned char, VOID_STAR, unsigned int, VOID_STAR);
+ VOID_STAR pa;
+ VOID_STAR pb;
+ SLang_Class_Type *a_cl, *b_cl;
+ unsigned char a_type, b_type;
+ int ret;
+
+ a_type = obj->data_type;
+ a_cl = _SLclass_get_class (a_type);
+
+ if (NULL == (f = _SLclass_get_unary_fun (op, a_cl, &b_cl, unary_type)))
+ return -1;
+
+ b_type = b_cl->cl_data_type;
+
+#if _SLANG_OPTIMIZE_FOR_SPEED
+ if (SLANG_CLASS_TYPE_SCALAR == _SLclass_Class_Type [a_type])
+ pa = (VOID_STAR) &obj->v;
+ else
+#endif
+ pa = _SLclass_get_ptr_to_value (a_cl, obj);
+
+ pb = b_cl->cl_transfer_buf;
+
+ if (1 != (*f) (op, a_type, pa, 1, pb))
+ {
+ SLang_verror (SL_NOT_IMPLEMENTED,
+ "Unary operation for %s failed", a_cl->cl_name);
+ return -1;
+ }
+
+ ret = (*b_cl->cl_apush)(b_type, pb);
+ /* cl_apush creates a copy, so make sure we call cl_adestroy */
+#if _SLANG_OPTIMIZE_FOR_SPEED
+ if (SLANG_CLASS_TYPE_SCALAR != _SLclass_Class_Type [b_type])
+#endif
+ (*b_cl->cl_adestroy)(b_type, pb);
+
+ return ret;
+}
+
+_INLINE_
+static int do_unary (int op, int unary_type)
+{
+ SLang_Object_Type obj;
+ int ret;
+
+ if (-1 == SLang_pop (&obj)) return -1;
+ ret = do_unary_op (op, &obj, unary_type);
+#if _SLANG_OPTIMIZE_FOR_SPEED
+ if (SLANG_CLASS_TYPE_SCALAR != _SLclass_Class_Type [obj.data_type])
+#endif
+ SLang_free_object (&obj);
+ return ret;
+}
+
+static int do_assignment_binary (int op, SLang_Object_Type *obja_ptr)
+{
+ SLang_Object_Type objb;
+ int ret;
+
+ if (SLang_pop (&objb))
+ return -1;
+
+ ret = do_binary_ab (op, obja_ptr, &objb);
+#if _SLANG_OPTIMIZE_FOR_SPEED
+ if (SLANG_CLASS_TYPE_SCALAR != _SLclass_Class_Type [objb.data_type])
+#endif
+ SLang_free_object (&objb);
+ return ret;
+}
+
+/* The order of these is assumed to match the binary operators
+ * defined in slang.h
+ */
+static int
+map_assignment_op_to_binary (unsigned char op_type, int *op, int *is_unary)
+{
+ *is_unary = 0;
+ switch (op_type)
+ {
+ case _SLANG_BCST_PLUSEQS:
+ case _SLANG_BCST_MINUSEQS:
+ case _SLANG_BCST_TIMESEQS:
+ case _SLANG_BCST_DIVEQS:
+ *op = SLANG_PLUS + (op_type - _SLANG_BCST_PLUSEQS);
+ break;
+
+ case _SLANG_BCST_BOREQS:
+ *op = SLANG_BOR;
+ break;
+
+ case _SLANG_BCST_BANDEQS:
+ *op = SLANG_BAND;
+ break;
+
+ case _SLANG_BCST_POST_MINUSMINUS:
+ case _SLANG_BCST_MINUSMINUS:
+ *op = SLANG_MINUS;
+ *is_unary = 1;
+ break;
+
+ case _SLANG_BCST_PLUSPLUS:
+ case _SLANG_BCST_POST_PLUSPLUS:
+ *op = SLANG_PLUS;
+ *is_unary = 1;
+ break;
+
+ default:
+ SLang_verror (SL_NOT_IMPLEMENTED, "Assignment operator not implemented");
+ return -1;
+ }
+ return 0;
+}
+
+static int
+perform_lvalue_operation (unsigned char op_type, SLang_Object_Type *obja_ptr)
+{
+ switch (op_type)
+ {
+ case _SLANG_BCST_ASSIGN:
+ break;
+
+ /* The order of these is assumed to match the binary operators
+ * defined in slang.h
+ */
+ case _SLANG_BCST_PLUSEQS:
+ case _SLANG_BCST_MINUSEQS:
+ case _SLANG_BCST_TIMESEQS:
+ case _SLANG_BCST_DIVEQS:
+ if (-1 == do_assignment_binary (SLANG_PLUS + (op_type - _SLANG_BCST_PLUSEQS), obja_ptr))
+ return -1;
+ break;
+
+ case _SLANG_BCST_BOREQS:
+ if (-1 == do_assignment_binary (SLANG_BOR, obja_ptr))
+ return -1;
+ break;
+
+ case _SLANG_BCST_BANDEQS:
+ if (-1 == do_assignment_binary (SLANG_BAND, obja_ptr))
+ return -1;
+ break;
+
+ case _SLANG_BCST_PLUSPLUS:
+ case _SLANG_BCST_POST_PLUSPLUS:
+#if _SLANG_OPTIMIZE_FOR_SPEED
+ if (obja_ptr->data_type == SLANG_INT_TYPE)
+ return SLclass_push_int_obj (SLANG_INT_TYPE, obja_ptr->v.int_val + 1);
+#endif
+ if (-1 == do_unary_op (SLANG_PLUSPLUS, obja_ptr, _SLANG_BC_UNARY))
+ return -1;
+ break;
+
+ case _SLANG_BCST_MINUSMINUS:
+ case _SLANG_BCST_POST_MINUSMINUS:
+#if _SLANG_OPTIMIZE_FOR_SPEED
+ if (obja_ptr->data_type == SLANG_INT_TYPE)
+ return SLclass_push_int_obj (SLANG_INT_TYPE, obja_ptr->v.int_val - 1);
+#endif
+ if (-1 == do_unary_op (SLANG_MINUSMINUS, obja_ptr, _SLANG_BC_UNARY))
+ return -1;
+ break;
+
+ default:
+ SLang_Error = SL_INTERNAL_ERROR;
+ return -1;
+ }
+ return 0;
+}
+
+_INLINE_
+static int
+set_lvalue_obj (unsigned char op_type, SLang_Object_Type *obja_ptr)
+{
+ if (op_type != _SLANG_BCST_ASSIGN)
+ {
+ if (-1 == perform_lvalue_operation (op_type, obja_ptr))
+ return -1;
+ }
+#if _SLANG_OPTIMIZE_FOR_SPEED
+ if (SLANG_CLASS_TYPE_SCALAR != _SLclass_Class_Type [obja_ptr->data_type])
+#endif
+ SLang_free_object (obja_ptr);
+
+ return SLang_pop(obja_ptr);
+}
+
+static int
+set_struct_lvalue (SLBlock_Type *bc_blk)
+{
+ int type;
+ SLang_Class_Type *cl;
+ char *name;
+ int op;
+
+ if (-1 == (type = SLang_peek_at_stack ()))
+ return -1;
+
+ cl = _SLclass_get_class (type);
+ if ((cl->cl_sput == NULL)
+ || (cl->cl_sget == NULL))
+ {
+ SLang_verror (SL_NOT_IMPLEMENTED,
+ "%s does not support structure access",
+ cl->cl_name);
+ SLdo_pop_n (2); /* object plus what was to be assigned */
+ return -1;
+ }
+ name = bc_blk->b.s_blk;
+ op = bc_blk->bc_sub_type;
+
+ if (op != _SLANG_BCST_ASSIGN)
+ {
+ /* We have something like (A.x += b) or (A.x++). In either case,
+ * we need A.x.
+ */
+ SLang_Object_Type obj_A;
+ SLang_Object_Type obj;
+
+ if (-1 == SLang_pop (&obj_A))
+ return -1;
+
+ if ((-1 == _SLpush_slang_obj (&obj_A))
+ || (-1 == cl->cl_sget ((unsigned char) type, name))
+ || (-1 == SLang_pop (&obj)))
+ {
+ SLang_free_object (&obj_A);
+ return -1;
+ }
+ /* Now the value of A.x is in obj. */
+ if (-1 == perform_lvalue_operation (op, &obj))
+ {
+ SLang_free_object (&obj);
+ SLang_free_object (&obj_A);
+ return -1;
+ }
+ SLang_free_object (&obj);
+ /* The result of the operation is now on the stack.
+ * Perform assignment */
+ if (-1 == SLang_push (&obj_A))
+ {
+ SLang_free_object (&obj_A);
+ return -1;
+ }
+ }
+
+ return (*cl->cl_sput) ((unsigned char) type, name);
+}
+
+static int make_unit_object (SLang_Object_Type *a, SLang_Object_Type *u)
+{
+ unsigned char type;
+
+ type = a->data_type;
+ if (type == SLANG_ARRAY_TYPE)
+ type = a->v.array_val->data_type;
+
+ u->data_type = type;
+ switch (type)
+ {
+ case SLANG_UCHAR_TYPE:
+ case SLANG_CHAR_TYPE:
+ u->v.char_val = 1;
+ break;
+
+ case SLANG_SHORT_TYPE:
+ case SLANG_USHORT_TYPE:
+ u->v.short_val = 1;
+ break;
+
+ case SLANG_LONG_TYPE:
+ case SLANG_ULONG_TYPE:
+ u->v.long_val = 1;
+ break;
+
+#if SLANG_HAS_FLOAT
+ case SLANG_FLOAT_TYPE:
+ u->v.float_val = 1;
+ break;
+
+ case SLANG_COMPLEX_TYPE:
+ u->data_type = SLANG_DOUBLE_TYPE;
+ case SLANG_DOUBLE_TYPE:
+ u->v.double_val = 1;
+ break;
+#endif
+ default:
+ u->data_type = SLANG_INT_TYPE;
+ u->v.int_val = 1;
+ }
+ return 0;
+}
+
+
+/* We want to convert 'A[i] op X' to 'A[i] = A[i] op X'. The code that
+ * has been generated is: X __args i A __aput-op
+ * where __aput-op represents this function. We need to generate:
+ * __args i A __eargs __aget X op __args i A __eargs __aput
+ * Here, __eargs implies a call to do_bc_call_direct_frame with either
+ * the aput or aget function. In addition, __args represents a call to
+ * SLang_start_arg_list. Of course, i represents a set of indices.
+ *
+ * Note: If op is an unary operation (e.g., ++ or --), then X will not
+ * b present an will have to be taken to be 1.
+ *
+ * Implementation note: For efficiency, calls to setup the frame, start
+ * arg list will be omitted and SLang_Num_Function_Args will be set.
+ * This is ugly but the alternative is much less efficient rendering these
+ * assignment operators useless. So, the plan is to roll the stack to get X,
+ * then duplicate the next N values, call __aget followed by op X, finally
+ * calling __aput. Hence, the sequence is:
+ *
+ * start: X i .. j A
+ * dupN: X i .. j A i .. j A
+ * __aget: X i .. j A Y
+ * roll: i .. j A Y X
+ * op: i .. j A Z
+ * roll: Z i .. j A
+ * __aput:
+ */
+static int
+set_array_lvalue (int op)
+{
+ SLang_Object_Type x, y;
+ int num_args, is_unary;
+
+ if (-1 == map_assignment_op_to_binary (op, &op, &is_unary))
+ return -1;
+
+ /* Grab the indices and the array. Do not start a new frame. */
+ if (-1 == SLang_end_arg_list ())
+ return -1;
+ num_args = Next_Function_Num_Args;
+ Next_Function_Num_Args = 0;
+
+ if (-1 == SLdup_n (num_args))
+ return -1;
+
+ SLang_Num_Function_Args = num_args;
+ if (-1 == _SLarray_aget ())
+ return -1;
+
+ if (-1 == SLang_pop (&y))
+ return -1;
+
+ if (is_unary == 0)
+ {
+ if ((-1 == SLroll_stack (-(num_args + 1)))
+ || (-1 == SLang_pop (&x)))
+ {
+ SLang_free_object (&y);
+ return -1;
+ }
+ }
+ else if (-1 == make_unit_object (&y, &x))
+ {
+ SLang_free_object (&y);
+ return -1;
+ }
+
+ if (-1 == do_binary_ab (op, &y, &x))
+ {
+ SLang_free_object (&y);
+ SLang_free_object (&x);
+ return -1;
+ }
+#if _SLANG_OPTIMIZE_FOR_SPEED
+ if (SLANG_CLASS_TYPE_SCALAR != _SLclass_Class_Type [y.data_type])
+#endif
+ SLang_free_object (&y);
+
+#if _SLANG_OPTIMIZE_FOR_SPEED
+ if (SLANG_CLASS_TYPE_SCALAR != _SLclass_Class_Type [x.data_type])
+#endif
+ SLang_free_object (&x);
+
+ if (-1 == SLroll_stack (num_args + 1))
+ return -1;
+
+ SLang_Num_Function_Args = num_args;
+ return _SLarray_aput ();
+}
+
+
+static int
+set_intrin_lvalue (SLBlock_Type *bc_blk)
+{
+ unsigned char op_type;
+ SLang_Object_Type obja;
+ SLang_Class_Type *cl;
+ SLang_Intrin_Var_Type *ivar;
+ VOID_STAR intrinsic_addr;
+ unsigned char intrinsic_type;
+
+ ivar = bc_blk->b.nt_ivar_blk;
+
+ intrinsic_type = ivar->type;
+ intrinsic_addr = ivar->addr;
+
+ op_type = bc_blk->bc_sub_type;
+
+ cl = _SLclass_get_class (intrinsic_type);
+
+ if (op_type != _SLANG_BCST_ASSIGN)
+ {
+ /* We want to get the current value into obja. This is the
+ * easiest way.
+ */
+ if ((-1 == (*cl->cl_push) (intrinsic_type, intrinsic_addr))
+ || (-1 == SLang_pop (&obja)))
+ return -1;
+
+ (void) perform_lvalue_operation (op_type, &obja);
+ SLang_free_object (&obja);
+
+ if (SLang_Error)
+ return -1;
+ }
+
+ return (*cl->cl_pop) (intrinsic_type, intrinsic_addr);
+}
+
+int _SLang_deref_assign (SLang_Ref_Type *ref)
+{
+ SLang_Object_Type *objp;
+ SLang_Name_Type *nt;
+ SLBlock_Type blk;
+
+ if (ref->is_global == 0)
+ {
+ objp = ref->v.local_obj;
+ if (objp > Local_Variable_Frame)
+ {
+ SLang_verror (SL_UNDEFINED_NAME, "Local variable reference is out of scope");
+ return -1;
+ }
+ return set_lvalue_obj (_SLANG_BCST_ASSIGN, objp);
+ }
+
+ nt = ref->v.nt;
+ switch (nt->name_type)
+ {
+ case SLANG_GVARIABLE:
+ case SLANG_PVARIABLE:
+ if (-1 == set_lvalue_obj (_SLANG_BCST_ASSIGN,
+ &((SLang_Global_Var_Type *)nt)->obj))
+ {
+ do_name_type_error (nt);
+ return -1;
+ }
+ break;
+
+ case SLANG_IVARIABLE:
+ blk.b.nt_blk = nt;
+ blk.bc_sub_type = _SLANG_BCST_ASSIGN;
+ if (-1 == set_intrin_lvalue (&blk))
+ {
+ do_name_type_error (nt);
+ return -1;
+ }
+ break;
+
+ case SLANG_LVARIABLE:
+ SLang_Error = SL_INTERNAL_ERROR;
+ /* set_intrin_lvalue (&blk); */
+ return -1;
+
+ case SLANG_RVARIABLE:
+ default:
+ SLang_verror (SL_READONLY_ERROR, "deref assignment to %s not allowed", nt->name);
+ return -1;
+ }
+
+ return 0;
+}
+
+static void set_deref_lvalue (SLBlock_Type *bc_blk)
+{
+ SLang_Object_Type *objp;
+ SLang_Ref_Type *ref;
+
+ switch (bc_blk->bc_sub_type)
+ {
+ case SLANG_LVARIABLE:
+ objp = (Local_Variable_Frame - bc_blk->b.i_blk);
+ break;
+ case SLANG_GVARIABLE:
+ case SLANG_PVARIABLE:
+ objp = &bc_blk->b.nt_gvar_blk->obj;
+ break;
+ default:
+ SLang_Error = SL_INTERNAL_ERROR;
+ return;
+ }
+
+ if (-1 == _SLpush_slang_obj (objp))
+ return;
+
+ if (-1 == SLang_pop_ref (&ref))
+ return;
+ (void) _SLang_deref_assign (ref);
+ SLang_free_ref (ref);
+}
+
+static int push_struct_field (char *name)
+{
+ int type;
+ SLang_Class_Type *cl;
+
+ if (-1 == (type = SLang_peek_at_stack ()))
+ return -1;
+
+ cl = _SLclass_get_class ((unsigned char) type);
+ if (cl->cl_sget == NULL)
+ {
+ SLang_verror (SL_NOT_IMPLEMENTED,
+ "%s does not permit structure access",
+ cl->cl_name);
+ SLdo_pop_n (2);
+ return -1;
+ }
+
+ return (*cl->cl_sget) ((unsigned char) type, name);
+}
+
+static void trace_dump (char *format, char *name, SLang_Object_Type *objs, int n, int dir)
+{
+ unsigned int len;
+ char prefix [52];
+
+ len = Trace_Mode - 1;
+ if (len + 2 >= sizeof (prefix))
+ len = sizeof (prefix) - 2;
+
+ SLMEMSET (prefix, ' ', len);
+ prefix[len] = 0;
+
+ call_dump_routine (prefix);
+ call_dump_routine (format, name, n);
+
+ if (n > 0)
+ {
+ prefix[len] = ' ';
+ len++;
+ prefix[len] = 0;
+
+ _SLdump_objects (prefix, objs, n, dir);
+ }
+}
+
+/* Pop a data item from the stack and return a pointer to it.
+ * Strings are not freed from stack so use another routine to do it.
+ */
+static VOID_STAR pop_pointer (SLang_Object_Type *obj, unsigned char type)
+{
+#ifndef _SLANG_OPTIMIZE_FOR_SPEED
+ SLang_Class_Type *cl;
+#endif
+
+ SLang_Array_Type *at;
+
+ /* Arrays are special. Allow scalars to automatically convert to arrays.
+ */
+ if (type == SLANG_ARRAY_TYPE)
+ {
+ if (-1 == SLang_pop_array (&at, 1))
+ return NULL;
+ obj->data_type = SLANG_ARRAY_TYPE;
+ return obj->v.ptr_val = (VOID_STAR) at;
+ }
+
+ if (type == 0)
+ {
+ /* This happens when an intrinsic is declared without any information
+ * regarding parameter types.
+ */
+ if (-1 == SLang_pop (obj))
+ return NULL;
+ type = obj->data_type;
+ }
+ else if (-1 == _SLang_pop_object_of_type (type, obj, 0))
+ return NULL;
+
+#if _SLANG_OPTIMIZE_FOR_SPEED
+ type = _SLclass_Class_Type [type];
+#else
+ type = _SLclass_get_class (type)->cl_class_type;
+#endif
+
+ if (type == SLANG_CLASS_TYPE_SCALAR)
+ return (VOID_STAR) &obj->v;
+ else if (type == SLANG_CLASS_TYPE_MMT)
+ return SLang_object_from_mmt (obj->v.ref);
+ else
+ return obj->v.ptr_val;
+}
+
+/* This is ugly. Does anyone have a advice for a cleaner way of doing
+ * this??
+ */
+typedef void (*VF0_Type)(void);
+typedef void (*VF1_Type)(VOID_STAR);
+typedef void (*VF2_Type)(VOID_STAR, VOID_STAR);
+typedef void (*VF3_Type)(VOID_STAR, VOID_STAR, VOID_STAR);
+typedef void (*VF4_Type)(VOID_STAR, VOID_STAR, VOID_STAR, VOID_STAR);
+typedef void (*VF5_Type)(VOID_STAR, VOID_STAR, VOID_STAR, VOID_STAR, VOID_STAR);
+typedef void (*VF6_Type)(VOID_STAR, VOID_STAR, VOID_STAR, VOID_STAR, VOID_STAR, VOID_STAR);
+typedef void (*VF7_Type)(VOID_STAR, VOID_STAR, VOID_STAR, VOID_STAR, VOID_STAR, VOID_STAR, VOID_STAR);
+typedef long (*LF0_Type)(void);
+typedef long (*LF1_Type)(VOID_STAR);
+typedef long (*LF2_Type)(VOID_STAR, VOID_STAR);
+typedef long (*LF3_Type)(VOID_STAR, VOID_STAR, VOID_STAR);
+typedef long (*LF4_Type)(VOID_STAR, VOID_STAR, VOID_STAR, VOID_STAR);
+typedef long (*LF5_Type)(VOID_STAR, VOID_STAR, VOID_STAR, VOID_STAR, VOID_STAR);
+typedef long (*LF6_Type)(VOID_STAR, VOID_STAR, VOID_STAR, VOID_STAR, VOID_STAR, VOID_STAR);
+typedef long (*LF7_Type)(VOID_STAR, VOID_STAR, VOID_STAR, VOID_STAR, VOID_STAR, VOID_STAR, VOID_STAR);
+#if SLANG_HAS_FLOAT
+typedef double (*FF0_Type)(void);
+typedef double (*FF1_Type)(VOID_STAR);
+typedef double (*FF2_Type)(VOID_STAR, VOID_STAR);
+typedef double (*FF3_Type)(VOID_STAR, VOID_STAR, VOID_STAR);
+typedef double (*FF4_Type)(VOID_STAR, VOID_STAR, VOID_STAR, VOID_STAR);
+typedef double (*FF5_Type)(VOID_STAR, VOID_STAR, VOID_STAR, VOID_STAR, VOID_STAR);
+typedef double (*FF6_Type)(VOID_STAR, VOID_STAR, VOID_STAR, VOID_STAR, VOID_STAR, VOID_STAR);
+typedef double (*FF7_Type)(VOID_STAR, VOID_STAR, VOID_STAR, VOID_STAR, VOID_STAR, VOID_STAR, VOID_STAR);
+#endif
+
+static int execute_intrinsic_fun (SLang_Intrin_Fun_Type *objf)
+{
+#if SLANG_HAS_FLOAT
+ double xf;
+#endif
+ VOID_STAR p[SLANG_MAX_INTRIN_ARGS];
+ SLang_Object_Type objs[SLANG_MAX_INTRIN_ARGS];
+ long ret;
+ unsigned char type;
+ unsigned int argc;
+ unsigned int i;
+ FVOID_STAR fptr;
+ unsigned char *arg_types;
+ int stk_depth;
+
+ fptr = objf->i_fun;
+ argc = objf->num_args;
+ type = objf->return_type;
+ arg_types = objf->arg_types;
+
+ if (argc > SLANG_MAX_INTRIN_ARGS)
+ {
+ SLang_verror(SL_APPLICATION_ERROR,
+ "Intrinsic function %s requires too many parameters", objf->name);
+ return -1;
+ }
+
+ if (-1 == _SL_increment_frame_pointer ())
+ return -1;
+
+ stk_depth = -1;
+ if (Trace_Mode && (_SLang_Trace > 0))
+ {
+ int nargs;
+
+ stk_depth = _SLstack_depth ();
+
+ nargs = SLang_Num_Function_Args;
+ if (nargs == 0)
+ nargs = (int)argc;
+
+ stk_depth -= nargs;
+
+ if (stk_depth >= 0)
+ trace_dump (">>%s (%d args)\n",
+ objf->name,
+ _SLStack_Pointer - nargs,
+ nargs,
+ 1);
+ }
+
+ i = argc;
+ while (i != 0)
+ {
+ i--;
+ if (NULL == (p[i] = pop_pointer (objs + i, arg_types[i])))
+ {
+ i++;
+ goto free_and_return;
+ }
+ }
+
+ ret = 0;
+#if SLANG_HAS_FLOAT
+ xf = 0.0;
+#endif
+
+ switch (argc)
+ {
+ case 0:
+ if (type == SLANG_VOID_TYPE) ((VF0_Type) fptr) ();
+#if SLANG_HAS_FLOAT
+ else if (type == SLANG_DOUBLE_TYPE) xf = ((FF0_Type) fptr)();
+#endif
+ else ret = ((LF0_Type) fptr)();
+ break;
+
+ case 1:
+ if (type == SLANG_VOID_TYPE) ((VF1_Type) fptr)(p[0]);
+#if SLANG_HAS_FLOAT
+ else if (type == SLANG_DOUBLE_TYPE) xf = ((FF1_Type) fptr)(p[0]);
+#endif
+ else ret = ((LF1_Type) fptr)(p[0]);
+ break;
+
+ case 2:
+ if (type == SLANG_VOID_TYPE) ((VF2_Type) fptr)(p[0], p[1]);
+#if SLANG_HAS_FLOAT
+ else if (type == SLANG_DOUBLE_TYPE) xf = ((FF2_Type) fptr)(p[0], p[1]);
+#endif
+ else ret = ((LF2_Type) fptr)(p[0], p[1]);
+ break;
+
+ case 3:
+ if (type == SLANG_VOID_TYPE) ((VF3_Type) fptr)(p[0], p[1], p[2]);
+#if SLANG_HAS_FLOAT
+ else if (type == SLANG_DOUBLE_TYPE) xf = ((FF3_Type) fptr)(p[0], p[1], p[2]);
+#endif
+ else ret = ((LF3_Type) fptr)(p[0], p[1], p[2]);
+ break;
+
+ case 4:
+ if (type == SLANG_VOID_TYPE) ((VF4_Type) fptr)(p[0], p[1], p[2], p[3]);
+#if SLANG_HAS_FLOAT
+ else if (type == SLANG_DOUBLE_TYPE) xf = ((FF4_Type) fptr)(p[0], p[1], p[2], p[3]);
+#endif
+ else ret = ((LF4_Type) fptr)(p[0], p[1], p[2], p[3]);
+ break;
+
+ case 5:
+ if (type == SLANG_VOID_TYPE) ((VF5_Type) fptr)(p[0], p[1], p[2], p[3], p[4]);
+#if SLANG_HAS_FLOAT
+ else if (type == SLANG_DOUBLE_TYPE) xf = ((FF5_Type) fptr)(p[0], p[1], p[2], p[3], p[4]);
+#endif
+ else ret = ((LF5_Type) fptr)(p[0], p[1], p[2], p[3], p[4]);
+ break;
+
+ case 6:
+ if (type == SLANG_VOID_TYPE) ((VF6_Type) fptr)(p[0], p[1], p[2], p[3], p[4], p[5]);
+#if SLANG_HAS_FLOAT
+ else if (type == SLANG_DOUBLE_TYPE) xf = ((FF6_Type) fptr)(p[0], p[1], p[2], p[3], p[4], p[5]);
+#endif
+ else ret = ((LF6_Type) fptr)(p[0], p[1], p[2], p[3], p[4], p[5]);
+ break;
+
+ case 7:
+ if (type == SLANG_VOID_TYPE) ((VF7_Type) fptr)(p[0], p[1], p[2], p[3], p[4], p[5], p[6]);
+#if SLANG_HAS_FLOAT
+ else if (type == SLANG_DOUBLE_TYPE) xf = ((FF7_Type) fptr)(p[0], p[1], p[2], p[3], p[4], p[5], p[6]);
+#endif
+ else ret = ((LF7_Type) fptr)(p[0], p[1], p[2], p[3], p[4], p[5], p[6]);
+ break;
+ }
+
+ switch (type)
+ {
+ case SLANG_VOID_TYPE:
+ break;
+
+#if SLANG_HAS_FLOAT
+ case SLANG_DOUBLE_TYPE:
+ (void) SLang_push_double (xf);
+ break;
+#endif
+ case SLANG_UINT_TYPE:
+ case SLANG_INT_TYPE: (void) SLclass_push_int_obj (type, (int) ret);
+ break;
+
+ case SLANG_CHAR_TYPE:
+ case SLANG_UCHAR_TYPE: (void) SLclass_push_char_obj (type, (char) ret);
+ break;
+
+ case SLANG_SHORT_TYPE:
+ case SLANG_USHORT_TYPE: (void) SLclass_push_short_obj (type, (short) ret);
+ break;
+
+ case SLANG_LONG_TYPE:
+ case SLANG_ULONG_TYPE: (void) SLclass_push_long_obj (type, ret);
+ break;
+
+ case SLANG_STRING_TYPE:
+ if (NULL == (char *)ret)
+ {
+ if (SLang_Error == 0) SLang_Error = SL_INTRINSIC_ERROR;
+ }
+ else (void) SLang_push_string ((char *)ret);
+ break;
+
+ default:
+ SLang_verror (SL_NOT_IMPLEMENTED,
+ "Support for intrinsic functions returning %s is not provided",
+ SLclass_get_datatype_name (type));
+ }
+
+ if (stk_depth >= 0)
+ {
+ stk_depth = _SLstack_depth () - stk_depth;
+
+ trace_dump ("<<%s (returning %d values)\n",
+ objf->name,
+ _SLStack_Pointer - stk_depth,
+ stk_depth,
+ 1);
+ }
+
+ free_and_return:
+ while (i < argc)
+ {
+ SLang_free_object (objs + i);
+ i++;
+ }
+
+ return _SL_decrement_frame_pointer ();
+}
+
+static int inner_interp(register SLBlock_Type *);
+
+/* Switch_Obj_Ptr points to the NEXT available free switch object */
+static SLang_Object_Type Switch_Objects[SLANG_MAX_NESTED_SWITCH];
+static SLang_Object_Type *Switch_Obj_Ptr = Switch_Objects;
+static SLang_Object_Type *Switch_Obj_Max = Switch_Objects + SLANG_MAX_NESTED_SWITCH;
+
+static void
+lang_do_loops (unsigned char stype, SLBlock_Type *block, unsigned int num_blocks)
+{
+ int i, ctrl;
+ int first, last;
+ SLBlock_Type *blks[4];
+ char *loop_name;
+ SLang_Foreach_Context_Type *foreach_context;
+ SLang_Class_Type *cl;
+ int type;
+ unsigned int j;
+
+ j = 0;
+ for (i = 0; i < (int) num_blocks; i++)
+ {
+ if (block[i].bc_main_type != _SLANG_BC_BLOCK)
+ {
+ if (block[i].bc_main_type == _SLANG_BC_LINE_NUM)
+ continue;
+
+ SLang_verror (SL_SYNTAX_ERROR, "Bytecode is not a looping block");
+ return;
+ }
+ blks[j] = block[i].b.blk;
+ j++;
+ }
+
+ num_blocks = j;
+ block = blks[0];
+
+ switch (stype)
+ {
+ case _SLANG_BCST_FOREACH:
+ loop_name = "foreach";
+ if (num_blocks != 1)
+ goto wrong_num_blocks_error;
+
+ /* We should find Next_Function_Num_Args + 1 items on the stack.
+ * The first Next_Function_Num_Args items represent the arguments to
+ * to USING. The last item (deepest in stack) is the object to loop
+ * over. So, roll the stack up and grab it.
+ */
+ if ((-1 == SLroll_stack (-(Next_Function_Num_Args + 1)))
+ || (-1 == (type = SLang_peek_at_stack ())))
+ goto return_error;
+
+ cl = _SLclass_get_class ((unsigned char) type);
+ if ((cl->cl_foreach == NULL)
+ || (cl->cl_foreach_open == NULL)
+ || (cl->cl_foreach_close == NULL))
+ {
+ SLang_verror (SL_NOT_IMPLEMENTED, "%s does not permit foreach", cl->cl_name);
+ SLdo_pop_n (Next_Function_Num_Args + 1);
+ goto return_error;
+ }
+
+ if (NULL == (foreach_context = (*cl->cl_foreach_open) ((unsigned char)type, Next_Function_Num_Args)))
+ goto return_error;
+
+ while (1)
+ {
+ int status;
+
+ if (SLang_Error)
+ {
+ (*cl->cl_foreach_close) ((unsigned char) type, foreach_context);
+ goto return_error;
+ }
+
+ status = (*cl->cl_foreach) ((unsigned char) type, foreach_context);
+ if (status <= 0)
+ {
+ if (status == 0)
+ break;
+
+ (*cl->cl_foreach_close) ((unsigned char) type, foreach_context);
+ goto return_error;
+ }
+
+ inner_interp (block);
+ if (Lang_Break) break;
+ Lang_Break_Condition = /* Lang_Continue = */ 0;
+ }
+ (*cl->cl_foreach_close) ((unsigned char) type, foreach_context);
+ break;
+
+ case _SLANG_BCST_WHILE:
+ loop_name = "while";
+
+ if (num_blocks != 2)
+ goto wrong_num_blocks_error;
+
+ type = blks[1]->bc_main_type;
+ while (1)
+ {
+ if (SLang_Error)
+ goto return_error;
+
+ inner_interp (block);
+ if (Lang_Break) break;
+
+ if (-1 == pop_ctrl_integer (&ctrl))
+ goto return_error;
+
+ if (ctrl == 0) break;
+
+ if (type)
+ {
+ inner_interp (blks[1]);
+ if (Lang_Break) break;
+ Lang_Break_Condition = /* Lang_Continue = */ 0;
+ }
+ }
+ break;
+
+ case _SLANG_BCST_DOWHILE:
+ loop_name = "do...while";
+
+ if (num_blocks != 2)
+ goto wrong_num_blocks_error;
+
+ while (1)
+ {
+ if (SLang_Error)
+ goto return_error;
+
+ Lang_Break_Condition = /* Lang_Continue = */ 0;
+ inner_interp (block);
+ if (Lang_Break) break;
+ Lang_Break_Condition = /* Lang_Continue = */ 0;
+ inner_interp (blks[1]);
+ if (-1 == pop_ctrl_integer (&ctrl))
+ goto return_error;
+
+ if (ctrl == 0) break;
+ }
+ break;
+
+ case _SLANG_BCST_CFOR:
+ loop_name = "for";
+
+ /* we need 4 blocks: first 3 control, the last is code */
+ if (num_blocks != 4) goto wrong_num_blocks_error;
+
+ inner_interp (block);
+ while (1)
+ {
+ if (SLang_Error)
+ goto return_error;
+
+ inner_interp(blks[1]); /* test */
+ if (-1 == pop_ctrl_integer (&ctrl))
+ goto return_error;
+
+ if (ctrl == 0) break;
+ inner_interp(blks[3]); /* code */
+ if (Lang_Break) break;
+ inner_interp(blks[2]); /* bump */
+ Lang_Break_Condition = /* Lang_Continue = */ 0;
+ }
+ break;
+
+ case _SLANG_BCST_FOR:
+ loop_name = "_for";
+
+ if (num_blocks != 1)
+ goto wrong_num_blocks_error;
+
+ /* 3 elements: first, last, step */
+ if ((-1 == SLang_pop_integer (&ctrl))
+ || (-1 == SLang_pop_integer (&last))
+ || (-1 == SLang_pop_integer (&first)))
+ goto return_error;
+
+ i = first;
+ while (1)
+ {
+ /* It is ugly to have this test here but I do not know of a
+ * simple way to do this without using two while loops.
+ */
+ if (ctrl >= 0)
+ {
+ if (i > last) break;
+ }
+ else if (i < last) break;
+
+ if (SLang_Error) goto return_error;
+
+ SLclass_push_int_obj (SLANG_INT_TYPE, i);
+ inner_interp (block);
+ if (Lang_Break) break;
+ Lang_Break_Condition = /* Lang_Continue = */ 0;
+
+ i += ctrl;
+ }
+ break;
+
+ case _SLANG_BCST_LOOP:
+ loop_name = "loop";
+ if (num_blocks != 1)
+ goto wrong_num_blocks_error;
+
+ if (-1 == SLang_pop_integer (&ctrl))
+ goto return_error;
+ while (ctrl > 0)
+ {
+ ctrl--;
+
+ if (SLang_Error)
+ goto return_error;
+
+ inner_interp (block);
+ if (Lang_Break) break;
+ Lang_Break_Condition = /* Lang_Continue = */ 0;
+ }
+ break;
+
+ case _SLANG_BCST_FOREVER:
+ loop_name = "forever";
+
+ if (num_blocks != 1)
+ goto wrong_num_blocks_error;
+
+ while (1)
+ {
+ if (SLang_Error)
+ goto return_error;
+
+ inner_interp (block);
+ if (Lang_Break) break;
+ Lang_Break_Condition = /* Lang_Continue = */ 0;
+ }
+ break;
+
+ default: SLang_verror(SL_INTERNAL_ERROR, "Unknown loop type");
+ return;
+ }
+ Lang_Break = /* Lang_Continue = */ 0;
+ Lang_Break_Condition = Lang_Return;
+ return;
+
+ wrong_num_blocks_error:
+ SLang_verror (SL_SYNTAX_ERROR, "Wrong number of blocks for '%s' construct", loop_name);
+
+ /* drop */
+ return_error:
+ do_traceback (loop_name, 0, NULL);
+}
+
+static void lang_do_and_orelse (unsigned char stype, SLBlock_Type *addr, SLBlock_Type *addr_max)
+{
+ int test = 0;
+ int is_or;
+
+ is_or = (stype == _SLANG_BCST_ORELSE);
+
+ while (addr <= addr_max)
+ {
+ if (addr->bc_main_type == _SLANG_BC_LINE_NUM)
+ {
+ addr++;
+ continue;
+ }
+
+ inner_interp (addr->b.blk);
+ if (SLang_Error
+ || Lang_Break_Condition
+ || (-1 == pop_ctrl_integer (&test)))
+ return;
+
+ if (is_or == (test != 0))
+ break;
+
+ /* if (((stype == _SLANG_BCST_ANDELSE) && (test == 0))
+ * || ((stype == _SLANG_BCST_ORELSE) && test))
+ * break;
+ */
+
+ addr++;
+ }
+ SLclass_push_int_obj (SLANG_INT_TYPE, test);
+}
+
+static void do_else_if (SLBlock_Type *zero_block, SLBlock_Type *non_zero_block)
+{
+ int test;
+
+ if (-1 == pop_ctrl_integer (&test))
+ return;
+
+ if (test == 0)
+ non_zero_block = zero_block;
+
+ if (non_zero_block != NULL)
+ inner_interp (non_zero_block->b.blk);
+}
+
+int _SLang_trace_fun (char *f)
+{
+ if (NULL == (f = SLang_create_slstring (f)))
+ return -1;
+
+ SLang_free_slstring (Trace_Function);
+ Trace_Function = f;
+ _SLang_Trace = 1;
+ return 0;
+}
+
+int _SLdump_objects (char *prefix, SLang_Object_Type *x, unsigned int n, int dir)
+{
+ char *s;
+ SLang_Class_Type *cl;
+
+ while (n)
+ {
+ cl = _SLclass_get_class (x->data_type);
+
+ if (NULL == (s = _SLstringize_object (x)))
+ s = "??";
+
+ call_dump_routine ("%s[%s]:%s\n", prefix, cl->cl_name, s);
+
+ SLang_free_slstring (s);
+
+ x += dir;
+ n--;
+ }
+ return 0;
+}
+
+static SLBlock_Type *Exit_Block_Ptr;
+static SLBlock_Type *Global_User_Block[5];
+static SLBlock_Type **User_Block_Ptr = Global_User_Block;
+char *_SLang_Current_Function_Name = NULL;
+
+static int execute_slang_fun (_SLang_Function_Type *fun)
+{
+ register unsigned int i;
+ register SLang_Object_Type *frame, *lvf;
+ register unsigned int n_locals;
+ _SLBlock_Header_Type *header;
+ /* SLBlock_Type *val; */
+ SLBlock_Type *exit_block_save;
+ SLBlock_Type **user_block_save;
+ SLBlock_Type *user_blocks[5];
+ char *save_fname;
+
+ exit_block_save = Exit_Block_Ptr;
+ user_block_save = User_Block_Ptr;
+ User_Block_Ptr = user_blocks;
+ *(user_blocks) = NULL;
+ *(user_blocks + 1) = NULL;
+ *(user_blocks + 2) = NULL;
+ *(user_blocks + 3) = NULL;
+ *(user_blocks + 4) = NULL;
+
+ Exit_Block_Ptr = NULL;
+
+ save_fname = _SLang_Current_Function_Name;
+ _SLang_Current_Function_Name = fun->name;
+
+ _SL_increment_frame_pointer ();
+
+ /* need loaded? */
+ if (fun->nlocals == AUTOLOAD_NUM_LOCALS)
+ {
+ header = NULL;
+ if (-1 == SLang_load_file(fun->v.autoload_filename))
+ goto the_return;
+
+ if (fun->nlocals == AUTOLOAD_NUM_LOCALS)
+ {
+ SLang_verror (SL_UNDEFINED_NAME, "%s: Function did not autoload",
+ _SLang_Current_Function_Name);
+ goto the_return;
+ }
+ }
+
+ n_locals = fun->nlocals;
+
+ /* let the error propagate through since it will do no harm
+ and allow us to restore stack. */
+
+ /* set new stack frame */
+ lvf = frame = Local_Variable_Frame;
+ i = n_locals;
+ if ((lvf + i) > Local_Variable_Stack + SLANG_MAX_LOCAL_STACK)
+ {
+ SLang_verror(SL_STACK_OVERFLOW, "%s: Local Variable Stack Overflow",
+ _SLang_Current_Function_Name);
+ goto the_return;
+ }
+
+ /* Make sure we do not allow this header to get destroyed by something
+ * like: define crash () { eval ("define crash ();") }
+ */
+ header = fun->v.header;
+ header->num_refs++;
+
+ while (i--)
+ {
+ lvf++;
+ lvf->data_type = SLANG_UNDEFINED_TYPE;
+ }
+ Local_Variable_Frame = lvf;
+
+ /* read values of function arguments */
+ i = fun->nargs;
+ while (i > 0)
+ {
+ i--;
+ (void) SLang_pop (Local_Variable_Frame - i);
+ }
+
+ if (SLang_Enter_Function != NULL) (*SLang_Enter_Function)(_SLang_Current_Function_Name);
+
+ if (_SLang_Trace)
+ {
+ int stack_depth;
+
+ stack_depth = _SLstack_depth ();
+
+ if ((Trace_Function != NULL)
+ && (0 == strcmp (Trace_Function, _SLang_Current_Function_Name))
+ && (Trace_Mode == 0))
+ Trace_Mode = 1;
+
+ if (Trace_Mode)
+ {
+ /* The local variable frame grows backwards */
+ trace_dump (">>%s (%d args)\n",
+ _SLang_Current_Function_Name,
+ Local_Variable_Frame,
+ (int) fun->nargs,
+ -1);
+ Trace_Mode++;
+ }
+
+ inner_interp (header->body);
+ Lang_Break_Condition = Lang_Return = Lang_Break = 0;
+ if (Exit_Block_Ptr != NULL) inner_interp(Exit_Block_Ptr);
+
+ if (Trace_Mode)
+ {
+ Trace_Mode--;
+ stack_depth = _SLstack_depth () - stack_depth;
+
+ trace_dump ("<<%s (returning %d values)\n",
+ _SLang_Current_Function_Name,
+ _SLStack_Pointer - stack_depth,
+ stack_depth,
+ 1);
+
+ if (Trace_Mode == 1)
+ Trace_Mode = 0;
+ }
+ }
+ else
+ {
+ inner_interp (header->body);
+ Lang_Break_Condition = Lang_Return = Lang_Break = 0;
+ if (Exit_Block_Ptr != NULL) inner_interp(Exit_Block_Ptr);
+ }
+
+ if (SLang_Exit_Function != NULL) (*SLang_Exit_Function)(_SLang_Current_Function_Name);
+
+ if (SLang_Error)
+ do_traceback(fun->name, n_locals,
+#if _SLANG_HAS_DEBUG_CODE
+ fun->file
+#else
+ NULL
+#endif
+ );
+
+ /* free local variables.... */
+ lvf = Local_Variable_Frame;
+ while (lvf > frame)
+ {
+#if _SLANG_OPTIMIZE_FOR_SPEED
+ if (SLANG_CLASS_TYPE_SCALAR != _SLclass_Class_Type [lvf->data_type])
+#endif
+ SLang_free_object (lvf);
+ lvf--;
+ }
+ Local_Variable_Frame = lvf;
+
+ if (header->num_refs == 1)
+ free_function_header (header);
+ else
+ header->num_refs--;
+
+ the_return:
+
+ Lang_Break_Condition = Lang_Return = Lang_Break = 0;
+ Exit_Block_Ptr = exit_block_save;
+ User_Block_Ptr = user_block_save;
+ _SLang_Current_Function_Name = save_fname;
+ _SL_decrement_frame_pointer ();
+
+ if (SLang_Error)
+ return -1;
+
+ return 0;
+}
+
+static void do_traceback (char *name, unsigned int locals, char *file)
+{
+ char *s;
+ unsigned int i;
+ SLang_Object_Type *objp;
+ unsigned short stype;
+
+ /* FIXME: Priority=low
+ * I need to make this configurable!!! That is, let the
+ * application decide whether or not a usage error should result in a
+ * traceback.
+ */
+ if (SLang_Error == SL_USAGE_ERROR)
+ return;
+
+ if (SLang_Traceback == 0)
+ return;
+
+ call_dump_routine ("S-Lang Traceback: %s\n", name);
+ if (SLang_Traceback < 0)
+ return;
+
+ if (file != NULL)
+ call_dump_routine ("File: %s\n", file);
+
+ if (locals == 0)
+ return;
+
+ call_dump_routine (" Local Variables:\n");
+
+ for (i = 0; i < locals; i++)
+ {
+ SLang_Class_Type *cl;
+ char *class_name;
+
+ objp = Local_Variable_Frame - i;
+ stype = objp->data_type;
+
+ s = _SLstringize_object (objp);
+ cl = _SLclass_get_class (stype);
+ class_name = cl->cl_name;
+
+ call_dump_routine ("\t$%d: Type: %s,\tValue:\t", i, class_name);
+
+ if (s == NULL) call_dump_routine("??\n");
+ else
+ {
+ char *q = "";
+#ifndef HAVE_VSNPRINTF
+ char buf[256];
+ if (strlen (s) >= sizeof (buf))
+ {
+ strncpy (buf, s, sizeof(buf));
+ s = buf;
+ s[sizeof(buf) - 1] = 0;
+ }
+#endif
+ if (SLANG_STRING_TYPE == stype) q = "\"";
+ call_dump_routine ("%s%s%s\n", q, s, q);
+ }
+ }
+}
+
+static void do_app_unary (SLang_App_Unary_Type *nt)
+{
+ if (-1 == do_unary (nt->unary_op, nt->name_type))
+ do_traceback (nt->name, 0, NULL);
+}
+
+static int inner_interp_nametype (SLang_Name_Type *nt)
+{
+ SLBlock_Type bc_blks[2];
+
+ bc_blks[0].b.nt_blk = nt;
+ bc_blks[0].bc_main_type = nt->name_type;
+ bc_blks[1].bc_main_type = 0;
+ return inner_interp(bc_blks);
+}
+
+int _SLang_dereference_ref (SLang_Ref_Type *ref)
+{
+ if (ref == NULL)
+ {
+ SLang_Error = SL_INTERNAL_ERROR;
+ return -1;
+ }
+
+ if (ref->is_global == 0)
+ {
+ SLang_Object_Type *obj = ref->v.local_obj;
+ if (obj > Local_Variable_Frame)
+ {
+ SLang_verror (SL_UNDEFINED_NAME, "Local variable deref is out of scope");
+ return -1;
+ }
+ return _SLpush_slang_obj (ref->v.local_obj);
+ }
+
+ (void) inner_interp_nametype (ref->v.nt);
+ return 0;
+}
+
+int _SLang_is_ref_initialized (SLang_Ref_Type *ref)
+{
+ unsigned char type;
+
+ if (ref == NULL)
+ {
+ SLang_Error = SL_INTERNAL_ERROR;
+ return -1;
+ }
+
+ if (ref->is_global == 0)
+ {
+ SLang_Object_Type *obj = ref->v.local_obj;
+ if (obj > Local_Variable_Frame)
+ {
+ SLang_verror (SL_UNDEFINED_NAME, "Local variable deref is out of scope");
+ return -1;
+ }
+ type = ref->v.local_obj->data_type;
+ }
+ else
+ {
+ SLang_Name_Type *nt = ref->v.nt;
+ if ((nt->name_type != SLANG_GVARIABLE)
+ && (nt->name_type != SLANG_PVARIABLE))
+ return 1;
+ type = ((SLang_Global_Var_Type *)nt)->obj.data_type;
+ }
+ return type != SLANG_UNDEFINED_TYPE;
+}
+
+int _SLang_uninitialize_ref (SLang_Ref_Type *ref)
+{
+ SLang_Object_Type *obj;
+
+ if (ref == NULL)
+ {
+ SLang_Error = SL_INTERNAL_ERROR;
+ return -1;
+ }
+
+ if (ref->is_global == 0)
+ {
+ obj = ref->v.local_obj;
+ if (obj > Local_Variable_Frame)
+ {
+ SLang_verror (SL_UNDEFINED_NAME, "Local variable deref is out of scope");
+ return -1;
+ }
+ obj = ref->v.local_obj;
+ }
+ else
+ {
+ SLang_Name_Type *nt = ref->v.nt;
+ if ((nt->name_type != SLANG_GVARIABLE)
+ && (nt->name_type != SLANG_PVARIABLE))
+ return -1;
+ obj = &((SLang_Global_Var_Type *)nt)->obj;
+ }
+ SLang_free_object (obj);
+ obj->data_type = SLANG_UNDEFINED_TYPE;
+ obj->v.ptr_val = NULL;
+ return 0;
+}
+
+void (*SLang_Interrupt)(void);
+static int Last_Error;
+void (*SLang_User_Clear_Error)(void);
+void _SLang_clear_error (void)
+{
+ if (Last_Error <= 0)
+ {
+ Last_Error = 0;
+ return;
+ }
+ Last_Error--;
+ if (SLang_User_Clear_Error != NULL) (*SLang_User_Clear_Error)();
+}
+
+int _SLpush_slang_obj (SLang_Object_Type *obj)
+{
+ unsigned char subtype;
+ SLang_Class_Type *cl;
+
+ if (obj == NULL) return SLang_push_null ();
+
+ subtype = obj->data_type;
+
+#if _SLANG_OPTIMIZE_FOR_SPEED
+ if (SLANG_CLASS_TYPE_SCALAR == _SLclass_Class_Type[subtype])
+ return SLang_push (obj);
+#endif
+
+ cl = _SLclass_get_class (subtype);
+ return (*cl->cl_push) (subtype, (VOID_STAR) &obj->v);
+}
+
+_INLINE_
+static int push_local_variable (int i)
+{
+ SLang_Class_Type *cl;
+ SLang_Object_Type *obj;
+ unsigned char subtype;
+
+ obj = Local_Variable_Frame - i;
+ subtype = obj->data_type;
+
+#if _SLANG_OPTIMIZE_FOR_SPEED
+ if (SLANG_CLASS_TYPE_SCALAR == _SLclass_Class_Type[subtype])
+ return SLang_push (obj);
+ if (subtype == SLANG_STRING_TYPE)
+ return _SLang_dup_and_push_slstring (obj->v.s_val);
+#endif
+
+ cl = _SLclass_get_class (subtype);
+ return (*cl->cl_push) (subtype, (VOID_STAR) &obj->v);
+}
+
+static int push_intrinsic_variable (SLang_Intrin_Var_Type *ivar)
+{
+ SLang_Class_Type *cl;
+ unsigned char stype;
+
+ stype = ivar->type;
+ cl = _SLclass_get_class (stype);
+
+ if (-1 == (*cl->cl_push_intrinsic) (stype, ivar->addr))
+ {
+ do_name_type_error ((SLang_Name_Type *) ivar);
+ return -1;
+ }
+ return 0;
+}
+
+static int dereference_object (void)
+{
+ SLang_Object_Type obj;
+ SLang_Class_Type *cl;
+ unsigned char type;
+ int ret;
+
+ if (-1 == SLang_pop (&obj))
+ return -1;
+
+ type = obj.data_type;
+
+ cl = _SLclass_get_class (type);
+ ret = (*cl->cl_dereference)(type, (VOID_STAR) &obj.v);
+
+ SLang_free_object (&obj);
+ return ret;
+}
+
+static int case_function (void)
+{
+ unsigned char type;
+ SLang_Object_Type obj;
+ SLang_Object_Type *swobjptr;
+
+ swobjptr = Switch_Obj_Ptr - 1;
+
+ if ((swobjptr < Switch_Objects)
+ || (0 == (type = swobjptr->data_type)))
+ {
+ SLang_verror (SL_SYNTAX_ERROR, "Misplaced 'case' keyword");
+ return -1;
+ }
+
+ if (-1 == SLang_pop (&obj))
+ return -1;
+
+ if (obj.data_type != type)
+ {
+ SLang_Class_Type *a_cl, *b_cl;
+
+ a_cl = _SLclass_get_class (obj.data_type);
+ b_cl = _SLclass_get_class (type);
+
+ if (NULL == _SLclass_get_binary_fun (SLANG_EQ, a_cl, b_cl, &a_cl, 0))
+ {
+ (void) SLclass_push_int_obj (SLANG_INT_TYPE, 0);
+ SLang_free_object (&obj);
+ return 0;
+ }
+ }
+
+ (void) do_binary_ab (SLANG_EQ, swobjptr, &obj);
+ SLang_free_object (&obj);
+ return 0;
+}
+
+static void tmp_variable_function (SLBlock_Type *addr)
+{
+ SLang_Object_Type *obj;
+
+ switch (addr->bc_sub_type)
+ {
+ case SLANG_GVARIABLE:
+ case SLANG_PVARIABLE:
+ obj = &addr->b.nt_gvar_blk->obj;
+ break;
+
+ case SLANG_LVARIABLE:
+ obj = Local_Variable_Frame - addr->b.i_blk;
+ break;
+
+ default:
+ SLang_Error = SL_INTERNAL_ERROR;
+ return;
+ }
+
+ /* There is no need to go through higher level routines since we are
+ * not creating or destroying extra copies.
+ */
+ if (-1 == SLang_push (obj))
+ return;
+
+ obj->data_type = SLANG_UNDEFINED_TYPE;
+ obj->v.ptr_val = NULL;
+}
+
+
+static int
+do_inner_interp_error (SLBlock_Type *err_block,
+ SLBlock_Type *addr_start,
+ SLBlock_Type *addr)
+{
+ int save_err, slerr;
+
+ /* Someday I can use the these variable to provide extra information
+ * about what went wrong.
+ */
+ (void) addr_start;
+ (void) addr;
+
+ if (err_block == NULL)
+ goto return_error;
+
+ if (SLang_Error < 0) /* errors less than 0 are severe */
+ goto return_error;
+
+ save_err = Last_Error++;
+ slerr = SLang_Error;
+ SLang_Error = 0;
+ inner_interp (err_block->b.blk);
+
+ if (Last_Error <= save_err)
+ {
+ /* Caught error and cleared it */
+ Last_Error = save_err;
+ if ((Lang_Break_Condition == 0)
+ /* An error may have cleared the error and then caused the
+ * function to return. We will allow that but let's not allow
+ * 'break' nor 'continue' statements until later.
+ */
+ || Lang_Return)
+ return 0;
+
+ /* drop--- either a break or continue was called */
+ }
+
+ Last_Error = save_err;
+ SLang_Error = slerr;
+
+ return_error:
+#if _SLANG_HAS_DEBUG_CODE
+ while (addr >= addr_start)
+ {
+ if (addr->bc_main_type == _SLANG_BC_LINE_NUM)
+ {
+ char buf[256];
+ sprintf (buf, "(Error occurred on line %lu)", addr->b.l_blk);
+ do_traceback (buf, 0, NULL);
+ break;
+ }
+ /* Special hack for 16 bit systems to prevent pointer wrapping. */
+#if defined(__16_BIT_SYSTEM__)
+ if (addr == addr_start)
+ break;
+#endif
+ addr--;
+ }
+#endif
+ return -1;
+}
+
+
+#define GATHER_STATISTICS 0
+#if GATHER_STATISTICS
+static unsigned int Bytecodes[0xFFFF];
+
+static void print_stats (void)
+{
+ unsigned int i;
+ unsigned long total;
+ FILE *fp = fopen ("stats.txt", "w");
+ if (fp == NULL)
+ return;
+
+ total = 0;
+ for (i = 0; i < 0xFFFF; i++)
+ total += Bytecodes[i];
+
+ if (total == 0)
+ total = 1;
+
+ for (i = 0; i < 0xFFFF; i++)
+ {
+ if (Bytecodes[i])
+ fprintf (fp, "0x%04X %9u %e\n", i, Bytecodes[i], Bytecodes[i]/(double) total);
+ }
+ fclose (fp);
+}
+
+static void add_to_statistics (SLBlock_Type *b)
+{
+ unsigned short x, y;
+
+ x = b->bc_main_type;
+ if (x == 0)
+ {
+ Bytecodes[0] += 1;
+ return;
+ }
+ b++;
+ y = b->bc_main_type;
+
+ Bytecodes[(x << 8) | y] += 1;
+}
+
+#endif
+
+/* inner interpreter */
+/* The return value from this function is only meaningful when it is used
+ * to process blocks for the switch statement. If it returns 0, the calling
+ * routine should pass the next block to it. Otherwise it will
+ * return non-zero, with or without error.
+ */
+static int inner_interp (SLBlock_Type *addr_start)
+{
+ SLBlock_Type *block, *err_block, *addr;
+#if GATHER_STATISTICS
+ static int inited = 0;
+
+ if (inited == 0)
+ {
+ (void) SLang_add_cleanup_function (print_stats);
+ inited = 1;
+ }
+#endif
+
+ /* for systems that have no real interrupt facility (e.g. go32 on dos) */
+ if (SLang_Interrupt != NULL) (*SLang_Interrupt)();
+
+ block = err_block = NULL;
+ addr = addr_start;
+
+#if GATHER_STATISTICS
+ add_to_statistics (addr);
+#endif
+ while (1)
+ {
+ switch (addr->bc_main_type)
+ {
+ case 0:
+ return 1;
+ case _SLANG_BC_LVARIABLE:
+ push_local_variable (addr->b.i_blk);
+ break;
+ case _SLANG_BC_GVARIABLE:
+ if (-1 == _SLpush_slang_obj (&addr->b.nt_gvar_blk->obj))
+ do_name_type_error (addr->b.nt_blk);
+ break;
+
+ case _SLANG_BC_IVARIABLE:
+ case _SLANG_BC_RVARIABLE:
+ push_intrinsic_variable (addr->b.nt_ivar_blk);
+ break;
+
+ case _SLANG_BC_INTRINSIC:
+ execute_intrinsic_fun (addr->b.nt_ifun_blk);
+ if (SLang_Error)
+ do_traceback(addr->b.nt_ifun_blk->name, 0, NULL);
+ break;
+
+ case _SLANG_BC_FUNCTION:
+ execute_slang_fun (addr->b.nt_fun_blk);
+ if (Lang_Break_Condition) goto handle_break_condition;
+ break;
+
+ case _SLANG_BC_MATH_UNARY:
+ case _SLANG_BC_APP_UNARY:
+ /* Make sure we treat these like function calls since the
+ * parser took sin(x) to be a function call.
+ */
+ if (0 == _SL_increment_frame_pointer ())
+ {
+ do_app_unary (addr->b.nt_unary_blk);
+ (void) _SL_decrement_frame_pointer ();
+ }
+ break;
+
+ case _SLANG_BC_ICONST:
+ SLclass_push_int_obj (SLANG_INT_TYPE, addr->b.iconst_blk->i);
+ break;
+
+#if SLANG_HAS_FLOAT
+ case _SLANG_BC_DCONST:
+ SLang_push_double (addr->b.dconst_blk->d);
+ break;
+#endif
+
+ case _SLANG_BC_PVARIABLE:
+ if (-1 == _SLpush_slang_obj (&addr->b.nt_gvar_blk->obj))
+ do_name_type_error (addr->b.nt_blk);
+ break;
+
+ case _SLANG_BC_PFUNCTION:
+ execute_slang_fun (addr->b.nt_fun_blk);
+ if (Lang_Break_Condition) goto handle_break_condition;
+ break;
+
+ case _SLANG_BC_BINARY:
+ do_binary (addr->b.i_blk);
+ break;
+
+ case _SLANG_BC_LITERAL:
+#if !_SLANG_OPTIMIZE_FOR_SPEED
+ case _SLANG_BC_LITERAL_INT:
+ case _SLANG_BC_LITERAL_STR:
+#endif
+ {
+ SLang_Class_Type *cl = _SLclass_get_class (addr->bc_sub_type);
+ (*cl->cl_push_literal) (addr->bc_sub_type, (VOID_STAR) &addr->b.ptr_blk);
+ }
+ break;
+#if _SLANG_OPTIMIZE_FOR_SPEED
+ case _SLANG_BC_LITERAL_INT:
+ SLclass_push_int_obj (addr->bc_sub_type, (int) addr->b.l_blk);
+ break;
+
+ case _SLANG_BC_LITERAL_STR:
+ _SLang_dup_and_push_slstring (addr->b.s_blk);
+ break;
+#endif
+ case _SLANG_BC_BLOCK:
+ switch (addr->bc_sub_type)
+ {
+ case _SLANG_BCST_ERROR_BLOCK:
+ err_block = addr;
+ break;
+
+ case _SLANG_BCST_EXIT_BLOCK:
+ Exit_Block_Ptr = addr->b.blk;
+ break;
+
+ case _SLANG_BCST_USER_BLOCK0:
+ case _SLANG_BCST_USER_BLOCK1:
+ case _SLANG_BCST_USER_BLOCK2:
+ case _SLANG_BCST_USER_BLOCK3:
+ case _SLANG_BCST_USER_BLOCK4:
+ User_Block_Ptr[addr->bc_sub_type - _SLANG_BCST_USER_BLOCK0] = addr->b.blk;
+ break;
+
+ case _SLANG_BCST_LOOP:
+ case _SLANG_BCST_WHILE:
+ case _SLANG_BCST_FOR:
+ case _SLANG_BCST_FOREVER:
+ case _SLANG_BCST_CFOR:
+ case _SLANG_BCST_DOWHILE:
+ case _SLANG_BCST_FOREACH:
+ if (block == NULL) block = addr;
+ lang_do_loops(addr->bc_sub_type, block, 1 + (unsigned int) (addr - block));
+ block = NULL;
+ break;
+
+ case _SLANG_BCST_IFNOT:
+#if _SLANG_OPTIMIZE_FOR_SPEED
+ {
+ int i;
+
+ if ((0 == pop_ctrl_integer (&i)) && (i == 0))
+ inner_interp (addr->b.blk);
+ }
+#else
+ do_else_if (addr, NULL);
+#endif
+ break;
+
+ case _SLANG_BCST_IF:
+#if _SLANG_OPTIMIZE_FOR_SPEED
+ {
+ int i;
+
+ if ((0 == pop_ctrl_integer (&i)) && i)
+ inner_interp (addr->b.blk);
+ }
+#else
+ do_else_if (NULL, addr);
+#endif
+ break;
+
+ case _SLANG_BCST_NOTELSE:
+ do_else_if (block, addr);
+ block = NULL;
+ break;
+
+ case _SLANG_BCST_ELSE:
+ do_else_if (addr, block);
+ block = NULL;
+ break;
+
+ case _SLANG_BCST_SWITCH:
+ if (Switch_Obj_Ptr == Switch_Obj_Max)
+ {
+ SLang_doerror("switch nesting too deep");
+ break;
+ }
+ (void) SLang_pop (Switch_Obj_Ptr);
+ Switch_Obj_Ptr++;
+
+ if (block == NULL) block = addr;
+ while ((SLang_Error == 0)
+ && (block <= addr)
+ && (Lang_Break_Condition == 0)
+ && (0 == inner_interp (block->b.blk)))
+ block++;
+ Switch_Obj_Ptr--;
+ SLang_free_object (Switch_Obj_Ptr);
+ Switch_Obj_Ptr->data_type = 0;
+ block = NULL;
+ break;
+
+ case _SLANG_BCST_ANDELSE:
+ case _SLANG_BCST_ORELSE:
+ if (block == NULL) block = addr;
+ lang_do_and_orelse (addr->bc_sub_type, block, addr);
+ block = NULL;
+ break;
+
+ default:
+ if (block == NULL) block = addr;
+ break;
+ }
+ if (Lang_Break_Condition) goto handle_break_condition;
+ break;
+
+ case _SLANG_BC_RETURN:
+ Lang_Break_Condition = Lang_Return = Lang_Break = 1; return 1;
+ case _SLANG_BC_BREAK:
+ Lang_Break_Condition = Lang_Break = 1; return 1;
+ case _SLANG_BC_CONTINUE:
+ Lang_Break_Condition = /* Lang_Continue = */ 1; return 1;
+
+ case _SLANG_BC_EXCH:
+ (void) SLreverse_stack (2);
+ break;
+
+ case _SLANG_BC_LABEL:
+ {
+ int test;
+ if ((0 == SLang_pop_integer (&test))
+ && (test == 0))
+ return 0;
+ }
+ break;
+
+ case _SLANG_BC_LOBJPTR:
+ (void)_SLang_push_ref (0, (VOID_STAR)(Local_Variable_Frame - addr->b.i_blk));
+ break;
+
+ case _SLANG_BC_GOBJPTR:
+ (void)_SLang_push_ref (1, (VOID_STAR)addr->b.nt_blk);
+ break;
+
+ case _SLANG_BC_X_ERROR:
+ if (err_block != NULL)
+ {
+ inner_interp(err_block->b.blk);
+ if (SLang_Error) err_block = NULL;
+ }
+ else SLang_verror(SL_SYNTAX_ERROR, "No ERROR_BLOCK");
+ if (Lang_Break_Condition) goto handle_break_condition;
+ break;
+
+ case _SLANG_BC_X_USER0:
+ case _SLANG_BC_X_USER1:
+ case _SLANG_BC_X_USER2:
+ case _SLANG_BC_X_USER3:
+ case _SLANG_BC_X_USER4:
+ if (User_Block_Ptr[addr->bc_main_type - _SLANG_BC_X_USER0] != NULL)
+ {
+ inner_interp(User_Block_Ptr[addr->bc_main_type - _SLANG_BC_X_USER0]);
+ }
+ else SLang_verror(SL_SYNTAX_ERROR, "No block for X_USERBLOCK");
+ if (Lang_Break_Condition) goto handle_break_condition;
+ break;
+
+ case _SLANG_BC_CALL_DIRECT:
+ (*addr->b.call_function) ();
+ break;
+
+ case _SLANG_BC_CALL_DIRECT_FRAME:
+ do_bc_call_direct_frame (addr->b.call_function);
+ break;
+
+ case _SLANG_BC_UNARY:
+ do_unary (addr->b.i_blk, _SLANG_BC_UNARY);
+ break;
+
+ case _SLANG_BC_UNARY_FUNC:
+ /* Make sure we treat these like function calls since the
+ * parser took abs(x) to be a function call.
+ */
+ if (0 == _SL_increment_frame_pointer ())
+ {
+ do_unary (addr->b.i_blk, _SLANG_BC_UNARY);
+ (void) _SL_decrement_frame_pointer ();
+ }
+ break;
+
+ case _SLANG_BC_DEREF_ASSIGN:
+ set_deref_lvalue (addr);
+ break;
+ case _SLANG_BC_SET_LOCAL_LVALUE:
+ set_lvalue_obj (addr->bc_sub_type, Local_Variable_Frame - addr->b.i_blk);
+ break;
+ case _SLANG_BC_SET_GLOBAL_LVALUE:
+ if (-1 == set_lvalue_obj (addr->bc_sub_type, &addr->b.nt_gvar_blk->obj))
+ do_name_type_error (addr->b.nt_blk);
+ break;
+ case _SLANG_BC_SET_INTRIN_LVALUE:
+ set_intrin_lvalue (addr);
+ break;
+ case _SLANG_BC_SET_STRUCT_LVALUE:
+ set_struct_lvalue (addr);
+ break;
+
+ case _SLANG_BC_FIELD:
+ (void) push_struct_field (addr->b.s_blk);
+ break;
+
+ case _SLANG_BC_SET_ARRAY_LVALUE:
+ set_array_lvalue (addr->bc_sub_type);
+ break;
+
+#if _SLANG_HAS_DEBUG_CODE
+ case _SLANG_BC_LINE_NUM:
+ break;
+#endif
+
+ case _SLANG_BC_TMP:
+ tmp_variable_function (addr);
+ break;
+
+#if _SLANG_OPTIMIZE_FOR_SPEED
+ case _SLANG_BC_LVARIABLE_AGET:
+ if (0 == push_local_variable (addr->b.i_blk))
+ do_bc_call_direct_frame (_SLarray_aget);
+ break;
+
+ case _SLANG_BC_LVARIABLE_APUT:
+ if (0 == push_local_variable (addr->b.i_blk))
+ do_bc_call_direct_frame (_SLarray_aput);
+ break;
+ case _SLANG_BC_INTEGER_PLUS:
+ if (0 == SLclass_push_int_obj (addr->bc_sub_type, (int) addr->b.l_blk))
+ do_binary (SLANG_PLUS);
+ break;
+
+ case _SLANG_BC_INTEGER_MINUS:
+ if (0 == SLclass_push_int_obj (addr->bc_sub_type, (int) addr->b.l_blk))
+ do_binary (SLANG_MINUS);
+ break;
+#endif
+#if 0
+ case _SLANG_BC_ARG_LVARIABLE:
+ (void) SLang_start_arg_list ();
+ push_local_variable (addr->b.i_blk);
+ break;
+#endif
+ case _SLANG_BC_EARG_LVARIABLE:
+ push_local_variable (addr->b.i_blk);
+ (void) SLang_end_arg_list ();
+ break;
+
+#if USE_COMBINED_BYTECODES
+ case _SLANG_BC_CALL_DIRECT_INTRINSIC:
+ (*addr->b.call_function) ();
+ addr++;
+ execute_intrinsic_fun (addr->b.nt_ifun_blk);
+ if (SLang_Error)
+ do_traceback(addr->b.nt_ifun_blk->name, 0, NULL);
+ break;
+
+ case _SLANG_BC_INTRINSIC_CALL_DIRECT:
+ execute_intrinsic_fun (addr->b.nt_ifun_blk);
+ if (SLang_Error)
+ {
+ do_traceback(addr->b.nt_ifun_blk->name, 0, NULL);
+ break;
+ }
+ addr++;
+ (*addr->b.call_function) ();
+ break;
+
+ case _SLANG_BC_CALL_DIRECT_LSTR:
+ (*addr->b.call_function) ();
+ addr++;
+ _SLang_dup_and_push_slstring (addr->b.s_blk);
+ break;
+
+ case _SLANG_BC_CALL_DIRECT_SLFUN:
+ (*addr->b.call_function) ();
+ addr++;
+ execute_slang_fun (addr->b.nt_fun_blk);
+ if (Lang_Break_Condition) goto handle_break_condition;
+ break;
+
+ case _SLANG_BC_CALL_DIRECT_INTRSTOP:
+ (*addr->b.call_function) ();
+ addr++;
+ /* drop */
+ case _SLANG_BC_INTRINSIC_STOP:
+ execute_intrinsic_fun (addr->b.nt_ifun_blk);
+ if (SLang_Error == 0)
+ return 1;
+ do_traceback(addr->b.nt_ifun_blk->name, 0, NULL);
+ break;
+
+ case _SLANG_BC_CALL_DIRECT_EARG_LVAR:
+ (*addr->b.call_function) ();
+ addr++;
+ push_local_variable (addr->b.i_blk);
+ (void) SLang_end_arg_list ();
+ break;
+
+ case _SLANG_BC_CALL_DIRECT_LINT:
+ (*addr->b.call_function) ();
+ addr++;
+ SLclass_push_int_obj (addr->bc_sub_type, (int) addr->b.l_blk);
+ break;
+
+ case _SLANG_BC_CALL_DIRECT_LVAR:
+ (*addr->b.call_function) ();
+ addr++;
+ push_local_variable (addr->b.i_blk);
+ break;
+#endif /* USE_COMBINED_BYTECODES */
+
+ default:
+ SLang_verror (SL_INTERNAL_ERROR, "Byte-Code 0x%X is not valid", addr->bc_main_type);
+ }
+
+ /* Someday I plan to add a 'signal' intrinsic function. Then when a
+ * signal is caught, a variable will be set to one and that value of
+ * that variable will need to be monitored here, e.g.,
+ * if (Handle_Signal) handle_signal ();
+ * It would be nice to check only one variable instead of Handle_Signal
+ * and SLang_Error. Perhaps I should phase out SLang_Error = xxx
+ * and used something like: SLang_set_error (code); Then, I could
+ * use:
+ * if (Handle_Condition)
+ * {
+ * Handle_Condition = 0;
+ * if (SLang_Error) ....
+ * else if (Handle_Signal) handle_signal ();
+ * else....
+ * }
+ */
+ if (SLang_Error)
+ {
+ if (-1 == do_inner_interp_error (err_block, addr_start, addr))
+ return 1;
+ if (SLang_Error)
+ return 1;
+
+ /* Otherwise, error cleared. Continue onto next bytecode.
+ * Someday I need to add something to indicate where the
+ * next statement begins since continuing on the next
+ * bytecode is not really what is desired.
+ */
+ if (Lang_Break_Condition) goto handle_break_condition;
+ }
+ addr++;
+ }
+
+ handle_break_condition:
+ /* Get here if Lang_Break_Condition != 0, which implies that either
+ * Lang_Return, Lang_Break, or Lang_Continue is non zero
+ */
+ if (Lang_Return)
+ Lang_Break = 1;
+
+ return 1;
+}
+
+/*}}}*/
+
+/* The functions below this point are used to implement the parsed token
+ * to byte-compiled code.
+ */
+/* static SLang_Name_Type **Static_Hash_Table; */
+
+static SLang_Name_Type **Locals_Hash_Table;
+static int Local_Variable_Number;
+static unsigned int Function_Args_Number;
+int _SLang_Auto_Declare_Globals = 0;
+int (*SLang_Auto_Declare_Var_Hook) (char *);
+
+static SLang_NameSpace_Type *This_Static_NameSpace;
+static SLang_NameSpace_Type *Global_NameSpace;
+
+#if _SLANG_HAS_DEBUG_CODE
+static char *This_Compile_Filename;
+#endif
+static SLBlock_Type SLShort_Blocks[6];
+/* These are initialized in add_table below. I cannot init a Union!! */
+
+static int Lang_Defining_Function;
+static void (*Default_Variable_Mode) (_SLang_Token_Type *);
+static void (*Default_Define_Function) (char *, unsigned long);
+
+static int push_compile_context (char *);
+static int pop_compile_context (void);
+
+typedef struct
+{
+ int block_type;
+ SLBlock_Type *block; /* beginning of block definition */
+ SLBlock_Type *block_ptr; /* current location */
+ SLBlock_Type *block_max; /* end of definition */
+ SLang_NameSpace_Type *static_namespace;
+}
+Block_Context_Type;
+
+static Block_Context_Type Block_Context_Stack [SLANG_MAX_BLOCK_STACK_LEN];
+static unsigned int Block_Context_Stack_Len;
+
+static SLBlock_Type *Compile_ByteCode_Ptr;
+static SLBlock_Type *This_Compile_Block;
+static SLBlock_Type *This_Compile_Block_Max;
+static int This_Compile_Block_Type;
+#define COMPILE_BLOCK_TYPE_FUNCTION 1
+#define COMPILE_BLOCK_TYPE_BLOCK 2
+#define COMPILE_BLOCK_TYPE_TOP_LEVEL 3
+
+/* If it returns 0, DO NOT FREE p */
+static int lang_free_branch (SLBlock_Type *p)
+{
+ /* Note: we look at 0,2,4, since these blocks are 0 terminated */
+ if ((p == SLShort_Blocks)
+ || (p == SLShort_Blocks + 2)
+ || (p == SLShort_Blocks + 4)
+ )
+ return 0;
+
+ while (1)
+ {
+ SLang_Class_Type *cl;
+
+ switch (p->bc_main_type)
+ {
+ case _SLANG_BC_BLOCK:
+ if (lang_free_branch(p->b.blk))
+ SLfree((char *)p->b.blk);
+ break;
+
+ case _SLANG_BC_LITERAL:
+ case _SLANG_BC_LITERAL_STR:
+ /* No user types should be here. */
+ cl = _SLclass_get_class (p->bc_sub_type);
+ (*cl->cl_byte_code_destroy) (p->bc_sub_type, (VOID_STAR) &p->b.ptr_blk);
+ break;
+
+ case _SLANG_BC_FIELD:
+ case _SLANG_BC_SET_STRUCT_LVALUE:
+ SLang_free_slstring (p->b.s_blk);
+ break;
+
+ default:
+ break;
+
+ case 0:
+ return 1;
+ }
+ p++;
+ }
+}
+
+static void free_function_header (_SLBlock_Header_Type *h)
+{
+ if (h->num_refs > 1)
+ {
+ h->num_refs--;
+ return;
+ }
+
+ if (h->body != NULL)
+ {
+ if (lang_free_branch (h->body))
+ SLfree ((char *) h->body);
+ }
+
+ SLfree ((char *) h);
+}
+
+static int push_block_context (int type)
+{
+ Block_Context_Type *c;
+ unsigned int num;
+ SLBlock_Type *b;
+
+ if (Block_Context_Stack_Len == SLANG_MAX_BLOCK_STACK_LEN)
+ {
+ SLang_verror (SL_STACK_OVERFLOW, "Block stack overflow");
+ return -1;
+ }
+
+ num = 5; /* 40 bytes */
+ if (NULL == (b = (SLBlock_Type *) SLcalloc (num, sizeof (SLBlock_Type))))
+ return -1;
+
+ c = Block_Context_Stack + Block_Context_Stack_Len;
+ c->block = This_Compile_Block;
+ c->block_ptr = Compile_ByteCode_Ptr;
+ c->block_max = This_Compile_Block_Max;
+ c->block_type = This_Compile_Block_Type;
+ c->static_namespace = This_Static_NameSpace;
+
+ Compile_ByteCode_Ptr = This_Compile_Block = b;
+ This_Compile_Block_Max = b + num;
+ This_Compile_Block_Type = type;
+
+ Block_Context_Stack_Len += 1;
+ return 0;
+}
+
+static int pop_block_context (void)
+{
+ Block_Context_Type *c;
+
+ if (Block_Context_Stack_Len == 0)
+ return -1;
+
+ Block_Context_Stack_Len -= 1;
+ c = Block_Context_Stack + Block_Context_Stack_Len;
+
+ This_Compile_Block = c->block;
+ This_Compile_Block_Max = c->block_max;
+ This_Compile_Block_Type = c->block_type;
+ Compile_ByteCode_Ptr = c->block_ptr;
+ This_Static_NameSpace = c->static_namespace;
+
+ return 0;
+}
+
+int _SLcompile_push_context (SLang_Load_Type *load_object)
+{
+ if (-1 == push_compile_context (load_object->name))
+ return -1;
+
+ if (NULL == (This_Static_NameSpace = _SLns_allocate_namespace (load_object->name, SLSTATIC_HASH_TABLE_SIZE)))
+ {
+ pop_compile_context ();
+ return -1;
+ }
+
+ if (-1 == push_block_context (COMPILE_BLOCK_TYPE_TOP_LEVEL))
+ {
+ pop_compile_context ();
+ return -1;
+ }
+
+ return 0;
+}
+
+int _SLcompile_pop_context (void)
+{
+ if (This_Compile_Block_Type == COMPILE_BLOCK_TYPE_TOP_LEVEL)
+ {
+ Compile_ByteCode_Ptr->bc_main_type = 0;
+ if (lang_free_branch (This_Compile_Block))
+ SLfree ((char *) This_Compile_Block);
+ }
+
+ (void) pop_block_context ();
+ (void) pop_compile_context ();
+
+ if (This_Compile_Block == NULL)
+ return 0;
+
+#if 0
+ if (This_Compile_Block_Type != COMPILE_BLOCK_TYPE_TOP_LEVEL)
+ {
+ SLang_verror (SL_INTERNAL_ERROR, "Not at top-level");
+ return -1;
+ }
+#endif
+
+ return 0;
+}
+
+/*{{{ Hash and Name Table Functions */
+
+static SLang_Name_Type *locate_name_in_table (char *name, unsigned long hash,
+ SLang_Name_Type **table, unsigned int table_size)
+{
+ SLang_Name_Type *t;
+ char ch;
+
+ t = table [(unsigned int) (hash % table_size)];
+ ch = *name++;
+
+ while (t != NULL)
+ {
+ if ((ch == t->name[0])
+ && (0 == strcmp (t->name + 1, name)))
+ break;
+
+ t = t->next;
+ }
+
+ return t;
+}
+
+static SLang_Name_Type *locate_namespace_encoded_name (char *name, int err_on_bad_ns)
+{
+ char *ns, *ns1;
+ SLang_NameSpace_Type *table;
+ SLang_Name_Type *nt;
+
+ ns = name;
+ name = strchr (name, '-');
+ if ((name == NULL) || (name [1] != '>'))
+ name = ns;
+
+ ns1 = SLang_create_nslstring (ns, (unsigned int) (name - ns));
+ if (ns1 == NULL)
+ return NULL;
+ if (ns != name)
+ name += 2;
+ ns = ns1;
+
+ if (*ns == 0)
+ {
+ /* Use Global Namespace */
+ SLang_free_slstring (ns);
+ return locate_name_in_table (name, _SLcompute_string_hash (name),
+ Global_NameSpace->table, Global_NameSpace->table_size);
+ }
+
+ if (NULL == (table = _SLns_find_namespace (ns)))
+ {
+ if (err_on_bad_ns)
+ SLang_verror (SL_SYNTAX_ERROR, "Unable to find namespace called %s", ns);
+ SLang_free_slstring (ns);
+ return NULL;
+ }
+ SLang_free_slstring (ns);
+
+ /* FIXME: the hash table size should be stored in the hash table itself */
+ nt = locate_name_in_table (name, _SLcompute_string_hash (name),
+ table->table, table->table_size);
+ if (nt == NULL)
+ return NULL;
+
+ switch (nt->name_type)
+ {
+ /* These are private and cannot be accessed through the namespace. */
+ case SLANG_PVARIABLE:
+ case SLANG_PFUNCTION:
+ return NULL;
+ }
+ return nt;
+}
+
+static SLang_Name_Type *locate_hashed_name (char *name, unsigned long hash)
+{
+ SLang_Name_Type *t;
+
+ if (Lang_Defining_Function)
+ {
+ t = locate_name_in_table (name, hash, Locals_Hash_Table, SLLOCALS_HASH_TABLE_SIZE);
+ if (t != NULL)
+ return t;
+ }
+
+ if ((This_Static_NameSpace != NULL)
+ && (NULL != (t = locate_name_in_table (name, hash, This_Static_NameSpace->table, This_Static_NameSpace->table_size))))
+ return t;
+
+ t = locate_name_in_table (name, hash, Global_NameSpace->table, Global_NameSpace->table_size);
+ if (NULL != t)
+ return t;
+
+ return locate_namespace_encoded_name (name, 1);
+}
+
+SLang_Name_Type *_SLlocate_name (char *name)
+{
+ return locate_hashed_name (name, _SLcompute_string_hash (name));
+}
+
+static SLang_Name_Type *
+add_name_to_hash_table (char *name, unsigned long hash,
+ unsigned int sizeof_obj, unsigned char name_type,
+ SLang_Name_Type **table, unsigned int table_size,
+ int check_existing)
+{
+ SLang_Name_Type *t;
+
+ if (check_existing)
+ {
+ t = locate_name_in_table (name, hash, table, table_size);
+ if (t != NULL)
+ return t;
+ }
+
+ if (-1 == _SLcheck_identifier_syntax (name))
+ return NULL;
+
+ t = (SLang_Name_Type *) SLmalloc (sizeof_obj);
+ if (t == NULL)
+ return t;
+
+ memset ((char *) t, 0, sizeof_obj);
+ if (NULL == (t->name = _SLstring_dup_hashed_string (name, hash)))
+ {
+ SLfree ((char *) t);
+ return NULL;
+ }
+ t->name_type = name_type;
+
+ hash = hash % table_size;
+ t->next = table [(unsigned int)hash];
+ table [(unsigned int) hash] = t;
+
+ return t;
+}
+
+static SLang_Name_Type *
+add_global_name (char *name, unsigned long hash,
+ unsigned char name_type, unsigned int sizeof_obj,
+ SLang_NameSpace_Type *ns)
+{
+ SLang_Name_Type *nt;
+ SLang_Name_Type **table;
+ unsigned int table_size;
+
+ table = ns->table;
+ table_size = ns->table_size;
+
+ nt = locate_name_in_table (name, hash, table, table_size);
+ if (nt != NULL)
+ {
+ if (nt->name_type == name_type)
+ return nt;
+
+ SLang_verror (SL_DUPLICATE_DEFINITION, "%s cannot be re-defined", name);
+ return NULL;
+ }
+
+ return add_name_to_hash_table (name, hash, sizeof_obj, name_type,
+ table, table_size, 0);
+}
+
+static int add_intrinsic_function (SLang_NameSpace_Type *ns,
+ char *name, FVOID_STAR addr, unsigned char ret_type,
+ unsigned int nargs, va_list ap)
+{
+ SLang_Intrin_Fun_Type *f;
+ unsigned int i;
+
+ if (-1 == init_interpreter ())
+ return -1;
+
+ if (ns == NULL) ns = Global_NameSpace;
+
+ if (nargs > SLANG_MAX_INTRIN_ARGS)
+ {
+ SLang_verror (SL_APPLICATION_ERROR, "Function %s requires too many arguments", name);
+ return -1;
+ }
+
+ if (ret_type == SLANG_FLOAT_TYPE)
+ {
+ SLang_verror (SL_NOT_IMPLEMENTED, "Function %s is not permitted to return float", name);
+ return -1;
+ }
+
+ f = (SLang_Intrin_Fun_Type *) add_global_name (name, _SLcompute_string_hash (name),
+ SLANG_INTRINSIC, sizeof (SLang_Intrin_Fun_Type),
+ ns);
+
+ if (f == NULL)
+ return -1;
+
+ f->i_fun = addr;
+ f->num_args = nargs;
+ f->return_type = ret_type;
+
+ for (i = 0; i < nargs; i++)
+ f->arg_types [i] = va_arg (ap, unsigned int);
+
+ return 0;
+}
+
+int SLadd_intrinsic_function (char *name, FVOID_STAR addr, unsigned char ret_type,
+ unsigned int nargs, ...)
+{
+ va_list ap;
+ int status;
+
+ va_start (ap, nargs);
+ status = add_intrinsic_function (NULL, name, addr, ret_type, nargs, ap);
+ va_end (ap);
+
+ return status;
+}
+
+int SLns_add_intrinsic_function (SLang_NameSpace_Type *ns,
+ char *name, FVOID_STAR addr, unsigned char ret_type,
+ unsigned int nargs, ...)
+{
+ va_list ap;
+ int status;
+
+ va_start (ap, nargs);
+ status = add_intrinsic_function (ns, name, addr, ret_type, nargs, ap);
+ va_end (ap);
+
+ return status;
+}
+
+int SLns_add_intrinsic_variable (SLang_NameSpace_Type *ns,
+ char *name, VOID_STAR addr, unsigned char data_type, int ro)
+{
+ SLang_Intrin_Var_Type *v;
+
+ if (-1 == init_interpreter ())
+ return -1;
+
+ if (ns == NULL) ns = Global_NameSpace;
+
+ v = (SLang_Intrin_Var_Type *)add_global_name (name,
+ _SLcompute_string_hash (name),
+ (ro ? SLANG_RVARIABLE : SLANG_IVARIABLE),
+ sizeof (SLang_Intrin_Var_Type),
+ ns);
+ if (v == NULL)
+ return -1;
+
+ v->addr = addr;
+ v->type = data_type;
+ return 0;
+}
+
+int SLadd_intrinsic_variable (char *name, VOID_STAR addr, unsigned char data_type, int ro)
+{
+ return SLns_add_intrinsic_variable (NULL, name, addr, data_type, ro);
+}
+
+static int
+add_slang_function (char *name, unsigned char type, unsigned long hash,
+ unsigned int num_args, unsigned int num_locals,
+#if _SLANG_HAS_DEBUG_CODE
+ char *file,
+#endif
+ _SLBlock_Header_Type *h,
+ SLang_NameSpace_Type *ns)
+{
+ _SLang_Function_Type *f;
+
+#if _SLANG_HAS_DEBUG_CODE
+ if ((file != NULL)
+ && (NULL == (file = SLang_create_slstring (file))))
+ return -1;
+#endif
+
+ f = (_SLang_Function_Type *)add_global_name (name, hash,
+ type,
+ sizeof (_SLang_Function_Type),
+ ns);
+ if (f == NULL)
+ {
+#if _SLANG_HAS_DEBUG_CODE
+ SLang_free_slstring (file); /* NULL ok */
+#endif
+ return -1;
+ }
+
+ if (f->v.header != NULL)
+ {
+ if (f->nlocals == AUTOLOAD_NUM_LOCALS)
+ SLang_free_slstring ((char *)f->v.autoload_filename); /* autoloaded filename */
+ else
+ free_function_header (f->v.header);
+ }
+
+#if _SLANG_HAS_DEBUG_CODE
+ if (f->file != NULL) SLang_free_slstring (f->file);
+ f->file = file;
+#endif
+ f->v.header = h;
+ f->nlocals = num_locals;
+ f->nargs = num_args;
+
+ return 0;
+}
+
+int SLang_autoload (char *name, char *file)
+{
+ _SLang_Function_Type *f;
+ unsigned long hash;
+
+ hash = _SLcompute_string_hash (name);
+ f = (_SLang_Function_Type *)locate_name_in_table (name, hash, Global_NameSpace->table, Global_NameSpace->table_size);
+
+ if ((f != NULL)
+ && (f->name_type == SLANG_FUNCTION)
+ && (f->v.header != NULL)
+ && (f->nlocals != AUTOLOAD_NUM_LOCALS))
+ {
+ /* already loaded */
+ return 0;
+ }
+
+ file = SLang_create_slstring (file);
+ if (-1 == add_slang_function (name, SLANG_FUNCTION, hash, 0, AUTOLOAD_NUM_LOCALS,
+#if _SLANG_HAS_DEBUG_CODE
+ file,
+#endif
+ (_SLBlock_Header_Type *) file,
+ Global_NameSpace))
+ {
+ SLang_free_slstring (file);
+ return -1;
+ }
+
+ return 0;
+}
+
+SLang_Name_Type *_SLlocate_global_name (char *name)
+{
+ unsigned long hash;
+
+ hash = _SLcompute_string_hash (name);
+ return locate_name_in_table (name, hash, Global_NameSpace->table,
+ Global_NameSpace->table_size);
+}
+
+/*}}}*/
+
+static void free_local_variable_table (void)
+{
+ unsigned int i;
+ SLang_Name_Type *t, *t1;
+
+ for (i = 0; i < SLLOCALS_HASH_TABLE_SIZE; i++)
+ {
+ t = Locals_Hash_Table [i];
+ while (t != NULL)
+ {
+ SLang_free_slstring (t->name);
+ t1 = t->next;
+ SLfree ((char *) t);
+ t = t1;
+ }
+ Locals_Hash_Table [i] = NULL;
+ }
+ Local_Variable_Number = 0;
+}
+
+/* call inner interpreter or return for more */
+static void lang_try_now(void)
+{
+ Compile_ByteCode_Ptr++;
+ if (This_Compile_Block_Type != COMPILE_BLOCK_TYPE_TOP_LEVEL)
+ return;
+
+ Compile_ByteCode_Ptr->bc_main_type = 0; /* so next command stops after this */
+
+ /* now do it */
+ inner_interp (This_Compile_Block);
+ (void) lang_free_branch (This_Compile_Block);
+ Compile_ByteCode_Ptr = This_Compile_Block;
+}
+
+SLang_Name_Type *SLang_get_fun_from_ref (SLang_Ref_Type *ref)
+{
+ if (ref->is_global)
+ {
+ SLang_Name_Type *nt = ref->v.nt;
+
+ switch (nt->name_type)
+ {
+ case SLANG_PFUNCTION:
+ case SLANG_FUNCTION:
+ case SLANG_INTRINSIC:
+ case SLANG_MATH_UNARY:
+ case SLANG_APP_UNARY:
+ return nt;
+ }
+ SLang_verror (SL_TYPE_MISMATCH,
+ "Reference to a function expected. Found &%s",
+ nt->name);
+ }
+
+ SLang_verror (SL_TYPE_MISMATCH,
+ "Reference to a function expected");
+ return NULL;
+}
+
+int SLexecute_function (SLang_Name_Type *nt)
+{
+ unsigned char type;
+ char *name;
+
+ if (SLang_Error)
+ return -1;
+
+ type = nt->name_type;
+ name = nt->name;
+
+ switch (type)
+ {
+ case SLANG_PFUNCTION:
+ case SLANG_FUNCTION:
+ execute_slang_fun ((_SLang_Function_Type *) nt);
+ break;
+
+ case SLANG_INTRINSIC:
+ execute_intrinsic_fun ((SLang_Intrin_Fun_Type *) nt);
+ break;
+
+ case SLANG_MATH_UNARY:
+ case SLANG_APP_UNARY:
+ inner_interp_nametype (nt);
+ break;
+
+ default:
+ SLang_verror (SL_TYPE_MISMATCH, "%s is not a function", name);
+ return -1;
+ }
+
+ if (SLang_Error)
+ {
+ SLang_verror (SLang_Error, "Error while executing %s", name);
+ return -1;
+ }
+
+ return 1;
+}
+
+int SLang_execute_function (char *name)
+{
+ SLang_Name_Type *entry;
+
+ if (NULL == (entry = SLang_get_function (name)))
+ return 0;
+
+ return SLexecute_function (entry);
+}
+
+/* return S-Lang function or NULL */
+SLang_Name_Type *SLang_get_function (char *name)
+{
+ SLang_Name_Type *entry;
+
+ if (NULL == (entry = locate_namespace_encoded_name (name, 0)))
+ return NULL;
+
+ if ((entry->name_type == SLANG_FUNCTION)
+ || (entry->name_type == SLANG_INTRINSIC))
+ return entry;
+
+ return NULL;
+}
+
+static void lang_begin_function (void)
+{
+ if (This_Compile_Block_Type != COMPILE_BLOCK_TYPE_TOP_LEVEL)
+ {
+ SLang_verror (SL_SYNTAX_ERROR, "Function nesting is illegal");
+ return;
+ }
+ Lang_Defining_Function = 1;
+ (void) push_block_context (COMPILE_BLOCK_TYPE_FUNCTION);
+}
+
+#if USE_COMBINED_BYTECODES
+static void optimize_block (SLBlock_Type *b)
+{
+ while (1)
+ {
+ switch (b->bc_main_type)
+ {
+ case 0:
+ return;
+
+ default:
+ b++;
+ break;
+
+ case _SLANG_BC_CALL_DIRECT:
+ b++;
+ switch (b->bc_main_type)
+ {
+ case 0:
+ return;
+ case _SLANG_BC_INTRINSIC:
+ if ((b+1)->bc_main_type == 0)
+ {
+ (b-1)->bc_main_type = _SLANG_BC_CALL_DIRECT_INTRSTOP;
+ return;
+ }
+ (b-1)->bc_main_type = _SLANG_BC_CALL_DIRECT_INTRINSIC;
+ b++;
+ break;
+ case _SLANG_BC_LITERAL_STR:
+ (b-1)->bc_main_type = _SLANG_BC_CALL_DIRECT_LSTR;
+ b++;
+ break;
+ case _SLANG_BC_FUNCTION:
+ case _SLANG_BC_PFUNCTION:
+ (b-1)->bc_main_type = _SLANG_BC_CALL_DIRECT_SLFUN;
+ b++;
+ break;
+ case _SLANG_BC_EARG_LVARIABLE:
+ (b-1)->bc_main_type = _SLANG_BC_CALL_DIRECT_EARG_LVAR;
+ b++;
+ break;
+ case _SLANG_BC_LITERAL_INT:
+ (b-1)->bc_main_type = _SLANG_BC_CALL_DIRECT_LINT;
+ b++;
+ break;
+ case _SLANG_BC_LVARIABLE:
+ (b-1)->bc_main_type = _SLANG_BC_CALL_DIRECT_LVAR;
+ b++;
+ break;
+ }
+ break;
+
+ case _SLANG_BC_INTRINSIC:
+ b++;
+ switch (b->bc_main_type)
+ {
+ case _SLANG_BC_CALL_DIRECT:
+ (b-1)->bc_main_type = _SLANG_BC_INTRINSIC_CALL_DIRECT;
+ b++;
+ break;
+#if 0
+ case _SLANG_BC_BLOCK:
+ (b-1)->bc_main_type = _SLANG_BC_INTRINSIC_BLOCK;
+ b++;
+ break;
+#endif
+
+ case 0:
+ (b-1)->bc_main_type = _SLANG_BC_INTRINSIC_STOP;
+ return;
+ }
+ break;
+ }
+ }
+}
+
+#endif
+
+
+/* name will be NULL if the object is to simply terminate the function
+ * definition. See SLang_restart.
+ */
+static int lang_define_function (char *name, unsigned char type, unsigned long hash,
+ SLang_NameSpace_Type *ns)
+{
+ if (This_Compile_Block_Type != COMPILE_BLOCK_TYPE_FUNCTION)
+ {
+ SLang_verror (SL_SYNTAX_ERROR, "Premature end of function");
+ return -1;
+ }
+
+ /* terminate function */
+ Compile_ByteCode_Ptr->bc_main_type = 0;
+
+ if (name != NULL)
+ {
+ _SLBlock_Header_Type *h;
+
+ h = (_SLBlock_Header_Type *)SLmalloc (sizeof (_SLBlock_Header_Type));
+ if (h != NULL)
+ {
+ h->num_refs = 1;
+ h->body = This_Compile_Block;
+
+#if USE_COMBINED_BYTECODES
+ optimize_block (h->body);
+#endif
+
+ if (-1 == add_slang_function (name, type, hash,
+ Function_Args_Number,
+ Local_Variable_Number,
+#if _SLANG_HAS_DEBUG_CODE
+ This_Compile_Filename,
+#endif
+ h, ns))
+ SLfree ((char *) h);
+ }
+ /* Drop through for clean-up */
+ }
+
+ free_local_variable_table ();
+
+ Function_Args_Number = 0;
+ Lang_Defining_Function = 0;
+
+ if (SLang_Error) return -1;
+ /* SLang_restart will finish this if there is a slang error. */
+
+ pop_block_context ();
+
+ /* A function is only defined at top-level */
+ if (This_Compile_Block_Type != COMPILE_BLOCK_TYPE_TOP_LEVEL)
+ {
+ SLang_verror (SL_INTERNAL_ERROR, "Not at top-level");
+ return -1;
+ }
+ Compile_ByteCode_Ptr = This_Compile_Block;
+ return 0;
+}
+
+static void define_static_function (char *name, unsigned long hash)
+{
+ (void) lang_define_function (name, SLANG_FUNCTION, hash, This_Static_NameSpace);
+}
+
+static void define_private_function (char *name, unsigned long hash)
+{
+ (void) lang_define_function (name, SLANG_PFUNCTION, hash, This_Static_NameSpace);
+}
+
+static void define_public_function (char *name, unsigned long hash)
+{
+ (void) lang_define_function (name, SLANG_FUNCTION, hash, Global_NameSpace);
+}
+
+static void lang_end_block (void)
+{
+ SLBlock_Type *node, *branch;
+ unsigned char mtype;
+
+ if (This_Compile_Block_Type != COMPILE_BLOCK_TYPE_BLOCK)
+ {
+ SLang_verror (SL_SYNTAX_ERROR, "Not defining a block");
+ return;
+ }
+
+ /* terminate the block */
+ Compile_ByteCode_Ptr->bc_main_type = 0;
+ branch = This_Compile_Block;
+
+ /* Try to save some space by using the cached blocks. */
+ if (Compile_ByteCode_Ptr == branch + 1)
+ {
+ mtype = branch->bc_main_type;
+ if (((mtype == _SLANG_BC_BREAK)
+ || (mtype == _SLANG_BC_CONTINUE)
+ || (mtype == _SLANG_BC_RETURN))
+ && (SLang_Error == 0))
+ {
+ SLfree ((char *)branch);
+ branch = SLShort_Blocks + 2 * (int) (mtype - _SLANG_BC_RETURN);
+ }
+ }
+
+#if USE_COMBINED_BYTECODES
+ optimize_block (branch);
+#endif
+
+ pop_block_context ();
+ node = Compile_ByteCode_Ptr++;
+
+ node->bc_main_type = _SLANG_BC_BLOCK;
+ node->bc_sub_type = 0;
+ node->b.blk = branch;
+}
+
+static int lang_begin_block (void)
+{
+ return push_block_context (COMPILE_BLOCK_TYPE_BLOCK);
+}
+
+static int lang_check_space (void)
+{
+ unsigned int n;
+ SLBlock_Type *p;
+
+ if (NULL == (p = This_Compile_Block))
+ {
+ SLang_verror (SL_INTERNAL_ERROR, "Top-level block not present");
+ return -1;
+ }
+
+ /* Allow 1 extra for terminator */
+ if (Compile_ByteCode_Ptr + 1 < This_Compile_Block_Max)
+ return 0;
+
+ n = (unsigned int) (This_Compile_Block_Max - p);
+
+ /* enlarge the space by 2 objects */
+ n += 2;
+
+ if (NULL == (p = (SLBlock_Type *) SLrealloc((char *)p, n * sizeof(SLBlock_Type))))
+ return -1;
+
+ This_Compile_Block_Max = p + n;
+ n = (unsigned int) (Compile_ByteCode_Ptr - This_Compile_Block);
+ This_Compile_Block = p;
+ Compile_ByteCode_Ptr = p + n;
+
+ return 0;
+}
+
+/* returns positive number if name is a function or negative number if it
+ is a variable. If it is intrinsic, it returns magnitude of 1, else 2 */
+int SLang_is_defined(char *name)
+{
+ SLang_Name_Type *t;
+
+ if (-1 == init_interpreter ())
+ return -1;
+
+ t = locate_namespace_encoded_name (name, 0);
+ if (t == NULL)
+ return 0;
+
+ switch (t->name_type)
+ {
+ case SLANG_FUNCTION:
+ /* case SLANG_PFUNCTION: */
+ return 2;
+ case SLANG_GVARIABLE:
+ /* case SLANG_PVARIABLE: */
+ return -2;
+
+ case SLANG_ICONSTANT:
+ case SLANG_DCONSTANT:
+ case SLANG_RVARIABLE:
+ case SLANG_IVARIABLE:
+ return -1;
+
+ case SLANG_INTRINSIC:
+ default:
+ return 1;
+ }
+}
+
+static int add_global_variable (char *name, char name_type, unsigned long hash,
+ SLang_NameSpace_Type *ns)
+{
+ SLang_Name_Type *g;
+
+ /* Note the importance of checking if it is already defined or not. For example,
+ * suppose X is defined as an intrinsic variable. Then S-Lang code like:
+ * !if (is_defined("X")) { variable X; }
+ * will not result in a global variable X. On the other hand, this would
+ * not be an issue if 'variable' statements always were not processed
+ * immediately. That is, as it is now, 'if (0) {variable ZZZZ;}' will result
+ * in the variable ZZZZ being defined because of the immediate processing.
+ * The current solution is to do: if (0) { eval("variable ZZZZ;"); }
+ */
+ /* hash = _SLcompute_string_hash (name); */
+ g = locate_name_in_table (name, hash, ns->table, ns->table_size);
+
+ if (g != NULL)
+ {
+ if (g->name_type == name_type)
+ return 0;
+ }
+
+ if (NULL == add_global_name (name, hash, name_type,
+ sizeof (SLang_Global_Var_Type), ns))
+ return -1;
+
+ return 0;
+}
+
+int SLadd_global_variable (char *name)
+{
+ if (-1 == init_interpreter ())
+ return -1;
+
+ return add_global_variable (name, SLANG_GVARIABLE,
+ _SLcompute_string_hash (name),
+ Global_NameSpace);
+}
+
+static int add_local_variable (char *name, unsigned long hash)
+{
+ SLang_Local_Var_Type *t;
+
+ /* local variable */
+ if (Local_Variable_Number >= SLANG_MAX_LOCAL_VARIABLES)
+ {
+ SLang_verror (SL_SYNTAX_ERROR, "Too many local variables");
+ return -1;
+ }
+
+ if (NULL != locate_name_in_table (name, hash, Locals_Hash_Table, SLLOCALS_HASH_TABLE_SIZE))
+ {
+ SLang_verror (SL_SYNTAX_ERROR, "Local variable %s has already been defined", name);
+ return -1;
+ }
+
+ t = (SLang_Local_Var_Type *)
+ add_name_to_hash_table (name, hash,
+ sizeof (SLang_Local_Var_Type), SLANG_LVARIABLE,
+ Locals_Hash_Table, SLLOCALS_HASH_TABLE_SIZE, 0);
+ if (t == NULL)
+ return -1;
+
+ t->local_var_number = Local_Variable_Number;
+ Local_Variable_Number++;
+ return 0;
+}
+
+static void (*Compile_Mode_Function) (_SLang_Token_Type *);
+static void compile_basic_token_mode (_SLang_Token_Type *);
+
+/* if an error occurs, discard current object, block, function, etc... */
+void SLang_restart (int localv)
+{
+ int save = SLang_Error;
+
+ SLang_Error = SL_UNKNOWN_ERROR;
+
+ _SLcompile_ptr = _SLcompile;
+ Compile_Mode_Function = compile_basic_token_mode;
+
+ Lang_Break = /* Lang_Continue = */ Lang_Return = 0;
+ Trace_Mode = 0;
+
+ while (This_Compile_Block_Type == COMPILE_BLOCK_TYPE_BLOCK)
+ lang_end_block();
+
+ if (This_Compile_Block_Type == COMPILE_BLOCK_TYPE_FUNCTION)
+ {
+ /* Terminate function definition and free variables */
+ lang_define_function (NULL, SLANG_FUNCTION, 0, Global_NameSpace);
+ if (lang_free_branch (This_Compile_Block))
+ SLfree((char *)This_Compile_Block);
+ }
+ Lang_Defining_Function = 0;
+
+ SLang_Error = save;
+
+ if (SLang_Error == SL_STACK_OVERFLOW)
+ {
+ /* This loop guarantees that the stack is properly cleaned. */
+ while (_SLStack_Pointer != _SLRun_Stack)
+ {
+ SLdo_pop ();
+ }
+ }
+
+ while ((This_Compile_Block_Type != COMPILE_BLOCK_TYPE_TOP_LEVEL)
+ && (0 == pop_block_context ()))
+ ;
+
+ if (localv)
+ {
+ Next_Function_Num_Args = SLang_Num_Function_Args = 0;
+ Local_Variable_Frame = Local_Variable_Stack;
+ Recursion_Depth = 0;
+ Frame_Pointer = _SLStack_Pointer;
+ Frame_Pointer_Depth = 0;
+ Switch_Obj_Ptr = Switch_Objects;
+ while (Switch_Obj_Ptr < Switch_Obj_Max)
+ {
+ SLang_free_object (Switch_Obj_Ptr);
+ Switch_Obj_Ptr++;
+ }
+ Switch_Obj_Ptr = Switch_Objects;
+ }
+}
+
+static void compile_directive (unsigned char sub_type)
+{
+ /* This function is called only from compile_directive_mode which is
+ * only possible when a block is available.
+ */
+
+ /* use BLOCK */
+ Compile_ByteCode_Ptr--;
+ Compile_ByteCode_Ptr->bc_sub_type = sub_type;
+
+ lang_try_now ();
+}
+
+static void compile_unary (int op, unsigned char mt)
+{
+ Compile_ByteCode_Ptr->bc_main_type = mt;
+ Compile_ByteCode_Ptr->b.i_blk = op;
+ Compile_ByteCode_Ptr->bc_sub_type = 0;
+
+ lang_try_now ();
+}
+
+
+static void compile_binary (int op)
+{
+ Compile_ByteCode_Ptr->bc_main_type = _SLANG_BC_BINARY;
+ Compile_ByteCode_Ptr->b.i_blk = op;
+ Compile_ByteCode_Ptr->bc_sub_type = 0;
+
+ lang_try_now ();
+}
+
+#if _SLANG_OPTIMIZE_FOR_SPEED
+static int try_compressed_bytecode (unsigned char last_bc, unsigned char bc)
+{
+ if (Compile_ByteCode_Ptr != This_Compile_Block)
+ {
+ SLBlock_Type *b;
+ b = Compile_ByteCode_Ptr - 1;
+ if (b->bc_main_type == last_bc)
+ {
+ Compile_ByteCode_Ptr = b;
+ b->bc_main_type = bc;
+ lang_try_now ();
+ return 0;
+ }
+ }
+ return -1;
+}
+#endif
+
+static void compile_fast_binary (int op, unsigned char bc)
+{
+#if _SLANG_OPTIMIZE_FOR_SPEED
+ if (0 == try_compressed_bytecode (_SLANG_BC_LITERAL_INT, bc))
+ return;
+#else
+ (void) bc;
+#endif
+ compile_binary (op);
+}
+
+/* This is a hack */
+typedef struct _Special_NameTable_Type
+{
+ char *name;
+ int (*fun) (struct _Special_NameTable_Type *, _SLang_Token_Type *);
+ VOID_STAR blk_data;
+ unsigned char main_type;
+}
+Special_NameTable_Type;
+
+static int handle_special (Special_NameTable_Type *nt, _SLang_Token_Type *tok)
+{
+ (void) tok;
+ Compile_ByteCode_Ptr->bc_main_type = nt->main_type;
+ Compile_ByteCode_Ptr->b.ptr_blk = nt->blk_data;
+ return 0;
+}
+
+static int handle_special_file (Special_NameTable_Type *nt, _SLang_Token_Type *tok)
+{
+ char *name;
+
+ (void) nt; (void) tok;
+
+ if (This_Static_NameSpace == NULL) name = "***Unknown***";
+ else
+ name = This_Static_NameSpace->name;
+
+ name = SLang_create_slstring (name);
+ if (name == NULL)
+ return -1;
+
+ Compile_ByteCode_Ptr->b.s_blk = name;
+ Compile_ByteCode_Ptr->bc_main_type = _SLANG_BC_LITERAL_STR;
+ Compile_ByteCode_Ptr->bc_sub_type = SLANG_STRING_TYPE;
+ return 0;
+}
+
+static int handle_special_line (Special_NameTable_Type *nt, _SLang_Token_Type *tok)
+{
+ (void) nt;
+
+#if _SLANG_HAS_DEBUG_CODE
+ Compile_ByteCode_Ptr->b.l_blk = (long) tok->line_number;
+#endif
+ Compile_ByteCode_Ptr->bc_main_type = _SLANG_BC_LITERAL;
+ Compile_ByteCode_Ptr->bc_sub_type = SLANG_UINT_TYPE;
+
+ return 0;
+}
+
+static Special_NameTable_Type Special_Name_Table [] =
+{
+ {"EXECUTE_ERROR_BLOCK", handle_special, NULL, _SLANG_BC_X_ERROR},
+ {"X_USER_BLOCK0", handle_special, NULL, _SLANG_BC_X_USER0},
+ {"X_USER_BLOCK1", handle_special, NULL, _SLANG_BC_X_USER1},
+ {"X_USER_BLOCK2", handle_special, NULL, _SLANG_BC_X_USER2},
+ {"X_USER_BLOCK3", handle_special, NULL, _SLANG_BC_X_USER3},
+ {"X_USER_BLOCK4", handle_special, NULL, _SLANG_BC_X_USER4},
+ {"__FILE__", handle_special_file, NULL, 0},
+ {"__LINE__", handle_special_line, NULL, 0},
+#if 0
+ {"__NAMESPACE__", handle_special_namespace, NULL, 0},
+#endif
+ {NULL, NULL, NULL, 0}
+};
+
+static void compile_hashed_identifier (char *name, unsigned long hash, _SLang_Token_Type *tok)
+{
+ SLang_Name_Type *entry;
+ unsigned char name_type;
+
+ entry = locate_hashed_name (name, hash);
+
+ if (entry == NULL)
+ {
+ Special_NameTable_Type *nt = Special_Name_Table;
+
+ while (nt->name != NULL)
+ {
+ if (strcmp (name, nt->name))
+ {
+ nt++;
+ continue;
+ }
+
+ if (0 == (*nt->fun)(nt, tok))
+ lang_try_now ();
+ return;
+ }
+
+ SLang_verror (SL_UNDEFINED_NAME, "%s is undefined", name);
+ return;
+ }
+
+ name_type = entry->name_type;
+ Compile_ByteCode_Ptr->bc_main_type = name_type;
+
+ if (name_type == SLANG_LVARIABLE)
+ Compile_ByteCode_Ptr->b.i_blk = ((SLang_Local_Var_Type *) entry)->local_var_number;
+ else
+ Compile_ByteCode_Ptr->b.nt_blk = entry;
+
+ lang_try_now ();
+}
+
+static void compile_tmp_variable (char *name, unsigned long hash)
+{
+ SLang_Name_Type *entry;
+ unsigned char name_type;
+
+ if (NULL == (entry = locate_hashed_name (name, hash)))
+ {
+ SLang_verror (SL_UNDEFINED_NAME, "%s is undefined", name);
+ return;
+ }
+
+ name_type = entry->name_type;
+ switch (name_type)
+ {
+ case SLANG_LVARIABLE:
+ Compile_ByteCode_Ptr->b.i_blk = ((SLang_Local_Var_Type *) entry)->local_var_number;
+ break;
+
+ case SLANG_GVARIABLE:
+ case SLANG_PVARIABLE:
+ Compile_ByteCode_Ptr->b.nt_blk = entry;
+ break;
+
+ default:
+ SLang_verror (SL_SYNTAX_ERROR, "__tmp(%s) does not specifiy a variable", name);
+ return;
+ }
+
+ Compile_ByteCode_Ptr->bc_main_type = _SLANG_BC_TMP;
+ Compile_ByteCode_Ptr->bc_sub_type = name_type;
+
+ lang_try_now ();
+}
+
+static void compile_simple (unsigned char main_type)
+{
+ Compile_ByteCode_Ptr->bc_main_type = main_type;
+ Compile_ByteCode_Ptr->bc_sub_type = 0;
+ Compile_ByteCode_Ptr->b.blk = NULL;
+ lang_try_now ();
+}
+
+static void compile_identifier (char *name, _SLang_Token_Type *tok)
+{
+ compile_hashed_identifier (name, _SLcompute_string_hash (name), tok);
+}
+
+static void compile_call_direct (int (*f) (void), unsigned char byte_code)
+{
+ Compile_ByteCode_Ptr->b.call_function = f;
+ Compile_ByteCode_Ptr->bc_main_type = byte_code;
+ Compile_ByteCode_Ptr->bc_sub_type = 0;
+ lang_try_now ();
+}
+
+static void compile_lvar_call_direct (int (*f)(void), unsigned char bc,
+ unsigned char frame_op)
+{
+#if _SLANG_OPTIMIZE_FOR_SPEED
+ if (0 == try_compressed_bytecode (_SLANG_BC_LVARIABLE, bc))
+ return;
+#else
+ (void) bc;
+#endif
+
+ compile_call_direct (f, frame_op);
+}
+
+static void compile_integer (long i, unsigned char bc_main_type, unsigned char bc_sub_type)
+{
+ Compile_ByteCode_Ptr->b.l_blk = i;
+ Compile_ByteCode_Ptr->bc_main_type = bc_main_type;
+ Compile_ByteCode_Ptr->bc_sub_type = bc_sub_type;
+
+ lang_try_now ();
+}
+
+#if SLANG_HAS_FLOAT
+static void compile_double (char *str, unsigned char type)
+{
+ double d;
+ unsigned int factor = 1;
+ double *ptr;
+
+#if 1
+ d = _SLang_atof (str);
+#else
+ if (1 != sscanf (str, "%lf", &d))
+ {
+ SLang_verror (SL_SYNTAX_ERROR, "Unable to convert %s to double", str);
+ return;
+ }
+#endif
+
+#if SLANG_HAS_COMPLEX
+ if (type == SLANG_COMPLEX_TYPE) factor = 2;
+#endif
+ if (NULL == (ptr = (double *) SLmalloc(factor * sizeof(double))))
+ return;
+
+ Compile_ByteCode_Ptr->b.double_blk = ptr;
+#if SLANG_HAS_COMPLEX
+ if (type == SLANG_COMPLEX_TYPE)
+ *ptr++ = 0;
+#endif
+ *ptr = d;
+
+ Compile_ByteCode_Ptr->bc_main_type = _SLANG_BC_LITERAL;
+ Compile_ByteCode_Ptr->bc_sub_type = type;
+ lang_try_now ();
+}
+
+static void compile_float (char *s)
+{
+ float x;
+
+#if 1
+ x = (float) _SLang_atof (s);
+#else
+ if (1 != sscanf (s, "%f", &x))
+ {
+ SLang_verror (SL_SYNTAX_ERROR, "Unable to convert %s to float", s);
+ return;
+ }
+#endif
+ Compile_ByteCode_Ptr->b.float_blk = x;
+ Compile_ByteCode_Ptr->bc_main_type = _SLANG_BC_LITERAL;
+ Compile_ByteCode_Ptr->bc_sub_type = SLANG_FLOAT_TYPE;
+ lang_try_now ();
+}
+
+#endif
+
+static void compile_string (char *s, unsigned long hash)
+{
+ if (NULL == (Compile_ByteCode_Ptr->b.s_blk = _SLstring_dup_hashed_string (s, hash)))
+ return;
+
+ Compile_ByteCode_Ptr->bc_main_type = _SLANG_BC_LITERAL_STR;
+ Compile_ByteCode_Ptr->bc_sub_type = SLANG_STRING_TYPE;
+
+ lang_try_now ();
+}
+
+static void compile_bstring (SLang_BString_Type *s)
+{
+ if (NULL == (Compile_ByteCode_Ptr->b.bs_blk = SLbstring_dup (s)))
+ return;
+
+ Compile_ByteCode_Ptr->bc_main_type = _SLANG_BC_LITERAL;
+ Compile_ByteCode_Ptr->bc_sub_type = SLANG_BSTRING_TYPE;
+
+ lang_try_now ();
+}
+
+/* assign_type is one of _SLANG_BCST_ASSIGN, ... values */
+static void compile_assign (unsigned char assign_type,
+ char *name, unsigned long hash)
+{
+ SLang_Name_Type *v;
+ unsigned char main_type;
+ SLang_Class_Type *cl;
+
+ v = locate_hashed_name (name, hash);
+ if (v == NULL)
+ {
+ if ((_SLang_Auto_Declare_Globals == 0)
+ || (NULL != strchr (name, '-')) /* namespace->name form */
+ || Lang_Defining_Function
+ || (assign_type != _SLANG_BCST_ASSIGN)
+ || (This_Static_NameSpace == NULL))
+ {
+ SLang_verror (SL_UNDEFINED_NAME, "%s is undefined", name);
+ return;
+ }
+ /* Note that function local variables are not at top level */
+
+ /* Variables that are automatically declared are given static
+ * scope.
+ */
+ if ((NULL != SLang_Auto_Declare_Var_Hook)
+ && (-1 == (*SLang_Auto_Declare_Var_Hook) (name)))
+ return;
+
+ if ((-1 == add_global_variable (name, SLANG_GVARIABLE, hash, This_Static_NameSpace))
+ || (NULL == (v = locate_hashed_name (name, hash))))
+ return;
+ }
+
+ switch (v->name_type)
+ {
+ case SLANG_LVARIABLE:
+ main_type = _SLANG_BC_SET_LOCAL_LVALUE;
+ Compile_ByteCode_Ptr->b.i_blk = ((SLang_Local_Var_Type *) v)->local_var_number;
+ break;
+
+ case SLANG_GVARIABLE:
+ case SLANG_PVARIABLE:
+ main_type = _SLANG_BC_SET_GLOBAL_LVALUE;
+ Compile_ByteCode_Ptr->b.nt_blk = v;
+ break;
+
+ case SLANG_IVARIABLE:
+ cl = _SLclass_get_class (((SLang_Intrin_Var_Type *)v)->type);
+ if (cl->cl_class_type != SLANG_CLASS_TYPE_SCALAR)
+ {
+ SLang_verror (SL_SYNTAX_ERROR, "Assignment to %s is not allowed", name);
+ return;
+ }
+ main_type = _SLANG_BC_SET_INTRIN_LVALUE;
+ Compile_ByteCode_Ptr->b.nt_blk = v;
+ break;
+
+ case SLANG_RVARIABLE:
+ SLang_verror (SL_READONLY_ERROR, "%s is read-only", name);
+ return;
+
+ default:
+ SLang_verror (SL_DUPLICATE_DEFINITION, "%s may not be used as an lvalue", name);
+ return;
+ }
+
+ Compile_ByteCode_Ptr->bc_sub_type = assign_type;
+ Compile_ByteCode_Ptr->bc_main_type = main_type;
+
+ lang_try_now ();
+}
+
+static void compile_deref_assign (char *name, unsigned long hash)
+{
+ SLang_Name_Type *v;
+
+ v = locate_hashed_name (name, hash);
+
+ if (v == NULL)
+ {
+ SLang_verror (SL_UNDEFINED_NAME, "%s is undefined", name);
+ return;
+ }
+
+ switch (v->name_type)
+ {
+ case SLANG_LVARIABLE:
+ Compile_ByteCode_Ptr->b.i_blk = ((SLang_Local_Var_Type *) v)->local_var_number;
+ break;
+
+ case SLANG_GVARIABLE:
+ case SLANG_PVARIABLE:
+ Compile_ByteCode_Ptr->b.nt_blk = v;
+ break;
+
+ default:
+ /* FIXME: Priority=low
+ * This could be made to work. It is not a priority because
+ * I cannot imagine application intrinsics which are references.
+ */
+ SLang_verror (SL_NOT_IMPLEMENTED, "Deref assignment to %s is not allowed", name);
+ return;
+ }
+
+ Compile_ByteCode_Ptr->bc_sub_type = v->name_type;
+ Compile_ByteCode_Ptr->bc_main_type = _SLANG_BC_DEREF_ASSIGN;
+
+ lang_try_now ();
+}
+
+static void
+compile_struct_assign (_SLang_Token_Type *t)
+{
+ Compile_ByteCode_Ptr->bc_sub_type = _SLANG_BCST_ASSIGN + (t->type - _STRUCT_ASSIGN_TOKEN);
+ Compile_ByteCode_Ptr->bc_main_type = _SLANG_BC_SET_STRUCT_LVALUE;
+ Compile_ByteCode_Ptr->b.s_blk = _SLstring_dup_hashed_string (t->v.s_val, t->hash);
+ lang_try_now ();
+}
+
+static void
+compile_array_assign (_SLang_Token_Type *t)
+{
+ Compile_ByteCode_Ptr->bc_sub_type = _SLANG_BCST_ASSIGN + (t->type - _ARRAY_ASSIGN_TOKEN);
+ Compile_ByteCode_Ptr->bc_main_type = _SLANG_BC_SET_ARRAY_LVALUE;
+ Compile_ByteCode_Ptr->b.s_blk = NULL;
+ lang_try_now ();
+}
+
+static void compile_dot(_SLang_Token_Type *t)
+{
+ Compile_ByteCode_Ptr->bc_main_type = _SLANG_BC_FIELD;
+ Compile_ByteCode_Ptr->b.s_blk = _SLstring_dup_hashed_string(t->v.s_val, t->hash);
+ lang_try_now ();
+}
+
+static void compile_ref (char *name, unsigned long hash)
+{
+ SLang_Name_Type *entry;
+ unsigned char main_type;
+
+ if (NULL == (entry = locate_hashed_name (name, hash)))
+ {
+ SLang_verror (SL_UNDEFINED_NAME, "%s is undefined", name);
+ return;
+ }
+
+ main_type = entry->name_type;
+
+ if (main_type == SLANG_LVARIABLE)
+ {
+ main_type = _SLANG_BC_LOBJPTR;
+ Compile_ByteCode_Ptr->b.i_blk = ((SLang_Local_Var_Type *)entry)->local_var_number;
+ }
+ else
+ {
+ main_type = _SLANG_BC_GOBJPTR;
+ Compile_ByteCode_Ptr->b.nt_blk = entry;
+ }
+
+ Compile_ByteCode_Ptr->bc_main_type = main_type;
+ lang_try_now ();
+}
+
+static void compile_break (unsigned char break_type,
+ int requires_block, int requires_fun,
+ char *str)
+{
+ if ((requires_fun
+ && (Lang_Defining_Function == 0))
+ || (requires_block
+ && (This_Compile_Block_Type != COMPILE_BLOCK_TYPE_BLOCK)))
+ {
+ SLang_verror (SL_SYNTAX_ERROR, "misplaced %s", str);
+ return;
+ }
+
+ Compile_ByteCode_Ptr->bc_main_type = break_type;
+ Compile_ByteCode_Ptr->bc_sub_type = 0;
+
+ lang_try_now ();
+}
+
+static void compile_public_variable_mode (_SLang_Token_Type *t)
+{
+ if (t->type == IDENT_TOKEN)
+ {
+ /* If the variable is already defined in the static hash table,
+ * generate an error.
+ */
+ if ((This_Static_NameSpace != NULL)
+ && (NULL != locate_name_in_table (t->v.s_val, t->hash, This_Static_NameSpace->table, This_Static_NameSpace->table_size)))
+ {
+ SLang_verror (SL_DUPLICATE_DEFINITION,
+ "%s already has static or private linkage in this unit",
+ t->v.s_val);
+ return;
+ }
+ add_global_variable (t->v.s_val, SLANG_GVARIABLE, t->hash, Global_NameSpace);
+ }
+ else if (t->type == CBRACKET_TOKEN)
+ Compile_Mode_Function = compile_basic_token_mode;
+ else
+ SLang_verror (SL_SYNTAX_ERROR, "Misplaced token in variable list");
+}
+
+static void compile_local_variable_mode (_SLang_Token_Type *t)
+{
+ if (t->type == IDENT_TOKEN)
+ add_local_variable (t->v.s_val, t->hash);
+ else if (t->type == CBRACKET_TOKEN)
+ Compile_Mode_Function = compile_basic_token_mode;
+ else
+ SLang_verror (SL_SYNTAX_ERROR, "Misplaced token in variable list");
+}
+
+static void compile_static_variable_mode (_SLang_Token_Type *t)
+{
+ if (t->type == IDENT_TOKEN)
+ add_global_variable (t->v.s_val, SLANG_GVARIABLE, t->hash, This_Static_NameSpace);
+ else if (t->type == CBRACKET_TOKEN)
+ Compile_Mode_Function = compile_basic_token_mode;
+ else
+ SLang_verror (SL_SYNTAX_ERROR, "Misplaced token in variable list");
+}
+
+static void compile_private_variable_mode (_SLang_Token_Type *t)
+{
+ if (t->type == IDENT_TOKEN)
+ add_global_variable (t->v.s_val, SLANG_PVARIABLE, t->hash, This_Static_NameSpace);
+ else if (t->type == CBRACKET_TOKEN)
+ Compile_Mode_Function = compile_basic_token_mode;
+ else
+ SLang_verror (SL_SYNTAX_ERROR, "Misplaced token in variable list");
+}
+
+static void compile_function_mode (_SLang_Token_Type *t)
+{
+ if (-1 == lang_check_space ())
+ return;
+
+ if (t->type != IDENT_TOKEN)
+ SLang_verror (SL_SYNTAX_ERROR, "Expecting function name");
+ else
+ lang_define_function (t->v.s_val, SLANG_FUNCTION, t->hash, Global_NameSpace);
+
+ Compile_Mode_Function = compile_basic_token_mode;
+}
+
+/* An error block is not permitted to contain continue or break statements.
+ * This restriction may be removed later but for now reject them.
+ */
+static int check_error_block (void)
+{
+ SLBlock_Type *p;
+ unsigned char t;
+
+ /* Back up to the block and then scan it. */
+ p = (Compile_ByteCode_Ptr - 1)->b.blk;
+
+ while (0 != (t = p->bc_main_type))
+ {
+ if ((t == _SLANG_BC_BREAK)
+ || (t == _SLANG_BC_CONTINUE))
+ {
+ SLang_verror (SL_SYNTAX_ERROR,
+ "An ERROR_BLOCK is not permitted to contain continue or break statements");
+ return -1;
+ }
+ p++;
+ }
+ return 0;
+}
+
+/* The only allowed tokens are the directives and another block start.
+ * The mode is only active if a block is available. The inner_interp routine
+ * expects such safety checks.
+ */
+static void compile_directive_mode (_SLang_Token_Type *t)
+{
+ int bc_sub_type;
+
+ if (-1 == lang_check_space ())
+ return;
+
+ bc_sub_type = -1;
+
+ switch (t->type)
+ {
+ case FOREVER_TOKEN:
+ bc_sub_type = _SLANG_BCST_FOREVER;
+ break;
+
+ case IFNOT_TOKEN:
+ bc_sub_type = _SLANG_BCST_IFNOT;
+ break;
+
+ case IF_TOKEN:
+ bc_sub_type = _SLANG_BCST_IF;
+ break;
+
+ case ANDELSE_TOKEN:
+ bc_sub_type = _SLANG_BCST_ANDELSE;
+ break;
+
+ case SWITCH_TOKEN:
+ bc_sub_type = _SLANG_BCST_SWITCH;
+ break;
+
+ case EXITBLK_TOKEN:
+ if (Lang_Defining_Function == 0)
+ {
+ SLang_verror (SL_SYNTAX_ERROR, "misplaced EXIT_BLOCK");
+ break;
+ }
+ bc_sub_type = _SLANG_BCST_EXIT_BLOCK;
+ break;
+
+ case ERRBLK_TOKEN:
+ if (This_Compile_Block_Type == COMPILE_BLOCK_TYPE_TOP_LEVEL)
+ {
+ SLang_verror (SL_SYNTAX_ERROR, "misplaced ERROR_BLOCK");
+ break;
+ }
+ if (0 == check_error_block ())
+ bc_sub_type = _SLANG_BCST_ERROR_BLOCK;
+ break;
+
+ case USRBLK0_TOKEN:
+ case USRBLK1_TOKEN:
+ case USRBLK2_TOKEN:
+ case USRBLK3_TOKEN:
+ case USRBLK4_TOKEN:
+ if (This_Compile_Block_Type == COMPILE_BLOCK_TYPE_TOP_LEVEL)
+ {
+ SLang_verror (SL_SYNTAX_ERROR, "misplaced USER_BLOCK");
+ break;
+ }
+ bc_sub_type = _SLANG_BCST_USER_BLOCK0 + (t->type - USRBLK0_TOKEN);
+ break;
+
+ case NOTELSE_TOKEN:
+ bc_sub_type = _SLANG_BCST_NOTELSE;
+ break;
+
+ case ELSE_TOKEN:
+ bc_sub_type = _SLANG_BCST_ELSE;
+ break;
+
+ case LOOP_TOKEN:
+ bc_sub_type = _SLANG_BCST_LOOP;
+ break;
+
+ case DOWHILE_TOKEN:
+ bc_sub_type = _SLANG_BCST_DOWHILE;
+ break;
+
+ case WHILE_TOKEN:
+ bc_sub_type = _SLANG_BCST_WHILE;
+ break;
+
+ case ORELSE_TOKEN:
+ bc_sub_type = _SLANG_BCST_ORELSE;
+ break;
+
+ case _FOR_TOKEN:
+ bc_sub_type = _SLANG_BCST_FOR;
+ break;
+
+ case FOR_TOKEN:
+ bc_sub_type = _SLANG_BCST_CFOR;
+ break;
+
+ case FOREACH_TOKEN:
+ bc_sub_type = _SLANG_BCST_FOREACH;
+ break;
+
+ case OBRACE_TOKEN:
+ lang_begin_block ();
+ break;
+
+ default:
+ SLang_verror (SL_SYNTAX_ERROR, "Expecting directive token. Found 0x%X", t->type);
+ break;
+ }
+
+ /* Reset this pointer first because compile_directive may cause a
+ * file to be loaded.
+ */
+ Compile_Mode_Function = compile_basic_token_mode;
+
+ if (bc_sub_type != -1)
+ compile_directive (bc_sub_type);
+}
+
+static unsigned int Assign_Mode_Type;
+static void compile_assign_mode (_SLang_Token_Type *t)
+{
+ if (t->type != IDENT_TOKEN)
+ {
+ SLang_verror (SL_SYNTAX_ERROR, "Expecting identifier for assignment");
+ return;
+ }
+
+ compile_assign (Assign_Mode_Type, t->v.s_val, t->hash);
+ Compile_Mode_Function = compile_basic_token_mode;
+}
+
+static void compile_basic_token_mode (_SLang_Token_Type *t)
+{
+ if (-1 == lang_check_space ())
+ return;
+
+ switch (t->type)
+ {
+ case PUSH_TOKEN:
+ case NOP_TOKEN:
+ case EOF_TOKEN:
+ case READONLY_TOKEN:
+ case DO_TOKEN:
+ case VARIABLE_TOKEN:
+ case SEMICOLON_TOKEN:
+ default:
+ SLang_verror (SL_SYNTAX_ERROR, "Unknown or unsupported token type 0x%X", t->type);
+ break;
+
+ case DEREF_TOKEN:
+ compile_call_direct (dereference_object, _SLANG_BC_CALL_DIRECT);
+ break;
+
+ case STRUCT_TOKEN:
+ compile_call_direct (_SLstruct_define_struct, _SLANG_BC_CALL_DIRECT);
+ break;
+
+ case TYPEDEF_TOKEN:
+ compile_call_direct (_SLstruct_define_typedef, _SLANG_BC_CALL_DIRECT);
+ break;
+
+ case TMP_TOKEN:
+ compile_tmp_variable (t->v.s_val, t->hash);
+ break;
+
+ case DOT_TOKEN: /* X . field */
+ compile_dot (t);
+ break;
+
+ case COMMA_TOKEN:
+ break; /* do nothing */
+
+ case IDENT_TOKEN:
+ compile_hashed_identifier (t->v.s_val, t->hash, t);
+ break;
+
+ case _REF_TOKEN:
+ compile_ref (t->v.s_val, t->hash);
+ break;
+
+ case ARG_TOKEN:
+ compile_call_direct (SLang_start_arg_list, _SLANG_BC_CALL_DIRECT);
+ break;
+
+ case EARG_TOKEN:
+ compile_lvar_call_direct (SLang_end_arg_list, _SLANG_BC_EARG_LVARIABLE, _SLANG_BC_CALL_DIRECT);
+ break;
+
+ case COLON_TOKEN:
+ if (This_Compile_Block_Type == COMPILE_BLOCK_TYPE_BLOCK)
+ compile_simple (_SLANG_BC_LABEL);
+ else SLang_Error = SL_SYNTAX_ERROR;
+ break;
+
+ case POP_TOKEN:
+ compile_call_direct (SLdo_pop, _SLANG_BC_CALL_DIRECT);
+ break;
+
+ case CASE_TOKEN:
+ if (This_Compile_Block_Type != COMPILE_BLOCK_TYPE_BLOCK)
+ SLang_verror (SL_SYNTAX_ERROR, "Misplaced 'case'");
+ else
+ compile_call_direct (case_function, _SLANG_BC_CALL_DIRECT);
+ break;
+
+ case CHAR_TOKEN:
+ compile_integer (t->v.long_val, _SLANG_BC_LITERAL, SLANG_CHAR_TYPE);
+ break;
+ case SHORT_TOKEN:
+ compile_integer (t->v.long_val, _SLANG_BC_LITERAL, SLANG_SHORT_TYPE);
+ break;
+ case INT_TOKEN:
+ compile_integer (t->v.long_val, _SLANG_BC_LITERAL_INT, SLANG_INT_TYPE);
+ break;
+ case UCHAR_TOKEN:
+ compile_integer (t->v.long_val, _SLANG_BC_LITERAL, SLANG_UCHAR_TYPE);
+ break;
+ case USHORT_TOKEN:
+ compile_integer (t->v.long_val, _SLANG_BC_LITERAL, SLANG_USHORT_TYPE);
+ break;
+ case UINT_TOKEN:
+ compile_integer (t->v.long_val, _SLANG_BC_LITERAL_INT, SLANG_UINT_TYPE);
+ break;
+ case LONG_TOKEN:
+ compile_integer (t->v.long_val, _SLANG_BC_LITERAL, SLANG_LONG_TYPE);
+ break;
+ case ULONG_TOKEN:
+ compile_integer (t->v.long_val, _SLANG_BC_LITERAL, SLANG_ULONG_TYPE);
+ break;
+
+#if SLANG_HAS_FLOAT
+ case FLOAT_TOKEN:
+ compile_float (t->v.s_val);
+ break;
+
+ case DOUBLE_TOKEN:
+ compile_double (t->v.s_val, SLANG_DOUBLE_TYPE);
+ break;
+#endif
+#if SLANG_HAS_COMPLEX
+ case COMPLEX_TOKEN:
+ compile_double (t->v.s_val, SLANG_COMPLEX_TYPE);
+ break;
+#endif
+
+ case STRING_TOKEN:
+ compile_string (t->v.s_val, t->hash);
+ break;
+
+ case _BSTRING_TOKEN:
+ compile_bstring (SLbstring_create ((unsigned char *)t->v.s_val, (unsigned int) t->hash));
+ break;
+
+ case BSTRING_TOKEN:
+ compile_bstring (t->v.b_val);
+ break;
+
+ case _NULL_TOKEN:
+ compile_identifier ("NULL", t);
+ break;
+
+ case _INLINE_WILDCARD_ARRAY_TOKEN:
+ compile_call_direct (_SLarray_wildcard_array, _SLANG_BC_CALL_DIRECT);
+ break;
+
+ case _INLINE_ARRAY_TOKEN:
+ compile_call_direct (_SLarray_inline_array, _SLANG_BC_CALL_DIRECT_FRAME);
+ break;
+
+ case _INLINE_IMPLICIT_ARRAY_TOKEN:
+ compile_call_direct (_SLarray_inline_implicit_array, _SLANG_BC_CALL_DIRECT_FRAME);
+ break;
+
+ case ARRAY_TOKEN:
+ compile_lvar_call_direct (_SLarray_aget, _SLANG_BC_LVARIABLE_AGET, _SLANG_BC_CALL_DIRECT_FRAME);
+ break;
+
+ /* Note: I need to add the other _ARRAY assign tokens. */
+ case _ARRAY_PLUSEQS_TOKEN:
+ case _ARRAY_MINUSEQS_TOKEN:
+ case _ARRAY_TIMESEQS_TOKEN:
+ case _ARRAY_DIVEQS_TOKEN:
+ case _ARRAY_BOREQS_TOKEN:
+ case _ARRAY_BANDEQS_TOKEN:
+ case _ARRAY_POST_MINUSMINUS_TOKEN:
+ case _ARRAY_MINUSMINUS_TOKEN:
+ case _ARRAY_POST_PLUSPLUS_TOKEN:
+ case _ARRAY_PLUSPLUS_TOKEN:
+ compile_array_assign (t);
+ break;
+
+ case _ARRAY_ASSIGN_TOKEN:
+ compile_lvar_call_direct (_SLarray_aput, _SLANG_BC_LVARIABLE_APUT, _SLANG_BC_CALL_DIRECT_FRAME);
+ break;
+
+ case _STRUCT_ASSIGN_TOKEN:
+ case _STRUCT_PLUSEQS_TOKEN:
+ case _STRUCT_MINUSEQS_TOKEN:
+ case _STRUCT_TIMESEQS_TOKEN:
+ case _STRUCT_DIVEQS_TOKEN:
+ case _STRUCT_BOREQS_TOKEN:
+ case _STRUCT_BANDEQS_TOKEN:
+ case _STRUCT_POST_MINUSMINUS_TOKEN:
+ case _STRUCT_MINUSMINUS_TOKEN:
+ case _STRUCT_POST_PLUSPLUS_TOKEN:
+ case _STRUCT_PLUSPLUS_TOKEN:
+ compile_struct_assign (t);
+ break;
+
+ case _SCALAR_ASSIGN_TOKEN:
+ case _SCALAR_PLUSEQS_TOKEN:
+ case _SCALAR_MINUSEQS_TOKEN:
+ case _SCALAR_TIMESEQS_TOKEN:
+ case _SCALAR_DIVEQS_TOKEN:
+ case _SCALAR_BOREQS_TOKEN:
+ case _SCALAR_BANDEQS_TOKEN:
+ case _SCALAR_POST_MINUSMINUS_TOKEN:
+ case _SCALAR_MINUSMINUS_TOKEN:
+ case _SCALAR_POST_PLUSPLUS_TOKEN:
+ case _SCALAR_PLUSPLUS_TOKEN:
+ compile_assign (_SLANG_BCST_ASSIGN + (t->type - _SCALAR_ASSIGN_TOKEN),
+ t->v.s_val, t->hash);
+ break;
+
+ case _DEREF_ASSIGN_TOKEN:
+ compile_deref_assign (t->v.s_val, t->hash);
+ break;
+
+ /* For processing RPN tokens */
+ case ASSIGN_TOKEN:
+ case PLUSEQS_TOKEN:
+ case MINUSEQS_TOKEN:
+ case TIMESEQS_TOKEN:
+ case DIVEQS_TOKEN:
+ case BOREQS_TOKEN:
+ case BANDEQS_TOKEN:
+ case POST_MINUSMINUS_TOKEN:
+ case MINUSMINUS_TOKEN:
+ case POST_PLUSPLUS_TOKEN:
+ case PLUSPLUS_TOKEN:
+ Compile_Mode_Function = compile_assign_mode;
+ Assign_Mode_Type = _SLANG_BCST_ASSIGN + (t->type - ASSIGN_TOKEN);
+ break;
+
+ case LT_TOKEN:
+ compile_binary (SLANG_LT);
+ break;
+
+ case LE_TOKEN:
+ compile_binary (SLANG_LE);
+ break;
+
+ case GT_TOKEN:
+ compile_binary (SLANG_GT);
+ break;
+
+ case GE_TOKEN:
+ compile_binary (SLANG_GE);
+ break;
+
+ case EQ_TOKEN:
+ compile_binary (SLANG_EQ);
+ break;
+
+ case NE_TOKEN:
+ compile_binary (SLANG_NE);
+ break;
+
+ case AND_TOKEN:
+ compile_binary (SLANG_AND);
+ break;
+
+ case ADD_TOKEN:
+ compile_fast_binary (SLANG_PLUS, _SLANG_BC_INTEGER_PLUS);
+ break;
+
+ case SUB_TOKEN:
+ compile_fast_binary (SLANG_MINUS, _SLANG_BC_INTEGER_MINUS);
+ break;
+
+ case TIMES_TOKEN:
+ compile_binary (SLANG_TIMES);
+ break;
+
+ case DIV_TOKEN:
+ compile_binary (SLANG_DIVIDE);
+ break;
+
+ case POW_TOKEN:
+ compile_binary (SLANG_POW);
+ break;
+
+ case BXOR_TOKEN:
+ compile_binary (SLANG_BXOR);
+ break;
+
+ case BAND_TOKEN:
+ compile_binary (SLANG_BAND);
+ break;
+
+ case BOR_TOKEN:
+ compile_binary (SLANG_BOR);
+ break;
+
+ case SHR_TOKEN:
+ compile_binary (SLANG_SHR);
+ break;
+
+ case SHL_TOKEN:
+ compile_binary (SLANG_SHL);
+ break;
+
+ case MOD_TOKEN:
+ compile_binary (SLANG_MOD);
+ break;
+
+ case OR_TOKEN:
+ compile_binary (SLANG_OR);
+ break;
+
+ case NOT_TOKEN:
+ compile_unary (SLANG_NOT, _SLANG_BC_UNARY);
+ break;
+
+ case BNOT_TOKEN:
+ compile_unary (SLANG_BNOT, _SLANG_BC_UNARY);
+ break;
+
+ case MUL2_TOKEN:
+ compile_unary (SLANG_MUL2, _SLANG_BC_UNARY_FUNC);
+ break;
+
+ case CHS_TOKEN:
+ compile_unary (SLANG_CHS, _SLANG_BC_UNARY_FUNC);
+ break;
+
+ case ABS_TOKEN:
+ compile_unary (SLANG_ABS, _SLANG_BC_UNARY_FUNC);
+ break;
+
+ case SQR_TOKEN:
+ compile_unary (SLANG_SQR, _SLANG_BC_UNARY_FUNC);
+ break;
+
+ case SIGN_TOKEN:
+ compile_unary (SLANG_SIGN, _SLANG_BC_UNARY_FUNC);
+ break;
+
+ case BREAK_TOKEN:
+ compile_break (_SLANG_BC_BREAK, 1, 0, "break");
+ break;
+
+ case RETURN_TOKEN:
+ compile_break (_SLANG_BC_RETURN, 0, 1, "return");
+ break;
+
+ case CONT_TOKEN:
+ compile_break (_SLANG_BC_CONTINUE, 1, 0, "continue");
+ break;
+
+ case EXCH_TOKEN:
+ compile_break (_SLANG_BC_EXCH, 0, 0, ""); /* FIXME: Priority=low */
+ break;
+
+ case STATIC_TOKEN:
+ if (Lang_Defining_Function == 0)
+ Compile_Mode_Function = compile_static_variable_mode;
+ else
+ SLang_verror (SL_NOT_IMPLEMENTED, "static variables not permitted in functions");
+ break;
+
+ case PRIVATE_TOKEN:
+ if (Lang_Defining_Function == 0)
+ Compile_Mode_Function = compile_private_variable_mode;
+ else
+ SLang_verror (SL_NOT_IMPLEMENTED, "private variables not permitted in functions");
+ break;
+
+ case PUBLIC_TOKEN:
+ if (Lang_Defining_Function == 0)
+ Compile_Mode_Function = compile_public_variable_mode;
+ else
+ SLang_verror (SL_NOT_IMPLEMENTED, "public variables not permitted in functions");
+ break;
+
+ case OBRACKET_TOKEN:
+ if (Lang_Defining_Function == 0)
+ Compile_Mode_Function = Default_Variable_Mode;
+ else
+ Compile_Mode_Function = compile_local_variable_mode;
+ break;
+
+ case OPAREN_TOKEN:
+ lang_begin_function ();
+ break;
+
+ case DEFINE_STATIC_TOKEN:
+ if (Lang_Defining_Function)
+ define_static_function (t->v.s_val, t->hash);
+ else SLang_Error = SL_SYNTAX_ERROR;
+ break;
+
+ case DEFINE_PRIVATE_TOKEN:
+ if (Lang_Defining_Function)
+ define_private_function (t->v.s_val, t->hash);
+ else SLang_Error = SL_SYNTAX_ERROR;
+ break;
+
+ case DEFINE_PUBLIC_TOKEN:
+ if (Lang_Defining_Function)
+ define_public_function (t->v.s_val, t->hash);
+ else SLang_Error = SL_SYNTAX_ERROR;
+ break;
+
+ case DEFINE_TOKEN:
+ if (Lang_Defining_Function)
+ (*Default_Define_Function) (t->v.s_val, t->hash);
+ else
+ SLang_Error = SL_SYNTAX_ERROR;
+ break;
+
+ case CPAREN_TOKEN:
+ if (Lang_Defining_Function)
+ Compile_Mode_Function = compile_function_mode;
+ else SLang_Error = SL_SYNTAX_ERROR;
+ break;
+
+ case CBRACE_TOKEN:
+ lang_end_block ();
+ Compile_Mode_Function = compile_directive_mode;
+ break;
+
+ case OBRACE_TOKEN:
+ lang_begin_block ();
+ break;
+
+ case FARG_TOKEN:
+ Function_Args_Number = Local_Variable_Number;
+ break;
+
+#if _SLANG_HAS_DEBUG_CODE
+ case LINE_NUM_TOKEN:
+ Compile_ByteCode_Ptr->bc_main_type = _SLANG_BC_LINE_NUM;
+ Compile_ByteCode_Ptr->b.l_blk = t->v.long_val;
+ lang_try_now ();
+ break;
+#endif
+ case POUND_TOKEN:
+ compile_call_direct (_SLarray_matrix_multiply, _SLANG_BC_CALL_DIRECT);
+ break;
+ }
+}
+
+void _SLcompile (_SLang_Token_Type *t)
+{
+ if (SLang_Error == 0)
+ {
+ if (Compile_Mode_Function != compile_basic_token_mode)
+ {
+ if (Compile_Mode_Function == NULL)
+ Compile_Mode_Function = compile_basic_token_mode;
+#if _SLANG_HAS_DEBUG_CODE
+ if (t->type == LINE_NUM_TOKEN)
+ {
+ compile_basic_token_mode (t);
+ return;
+ }
+#endif
+ }
+
+ (*Compile_Mode_Function) (t);
+ }
+
+ if (SLang_Error)
+ {
+ Compile_Mode_Function = compile_basic_token_mode;
+ SLang_restart (0);
+ }
+}
+
+void (*_SLcompile_ptr)(_SLang_Token_Type *) = _SLcompile;
+
+typedef struct _Compile_Context_Type
+{
+ struct _Compile_Context_Type *next;
+ SLang_NameSpace_Type *static_namespace;
+ void (*compile_variable_mode) (_SLang_Token_Type *);
+ void (*define_function) (char *, unsigned long);
+ int lang_defining_function;
+ int local_variable_number;
+ unsigned int function_args_number;
+ SLang_Name_Type **locals_hash_table;
+ void (*compile_mode_function)(_SLang_Token_Type *);
+#if _SLANG_HAS_DEBUG_CODE
+ char *compile_filename;
+#endif
+}
+Compile_Context_Type;
+
+static Compile_Context_Type *Compile_Context_Stack;
+
+/* The only way the push/pop_context functions can get called is via
+ * an eval type function. That can only happen when executed from a
+ * top level block. This means that Compile_ByteCode_Ptr can always be
+ * rest back to the beginning of a block.
+ */
+
+static int pop_compile_context (void)
+{
+ Compile_Context_Type *cc;
+
+ if (NULL == (cc = Compile_Context_Stack))
+ return -1;
+
+ This_Static_NameSpace = cc->static_namespace;
+ Compile_Context_Stack = cc->next;
+ Default_Variable_Mode = cc->compile_variable_mode;
+ Default_Define_Function = cc->define_function;
+ Compile_Mode_Function = cc->compile_mode_function;
+
+ Lang_Defining_Function = cc->lang_defining_function;
+ Local_Variable_Number = cc->local_variable_number;
+ Function_Args_Number = cc->function_args_number;
+
+#if _SLANG_HAS_DEBUG_CODE
+ SLang_free_slstring (This_Compile_Filename);
+ This_Compile_Filename = cc->compile_filename;
+#endif
+
+ SLfree ((char *) Locals_Hash_Table);
+ Locals_Hash_Table = cc->locals_hash_table;
+
+ SLfree ((char *) cc);
+
+ return 0;
+}
+
+static int push_compile_context (char *name)
+{
+ Compile_Context_Type *cc;
+ SLang_Name_Type **lns;
+
+ cc = (Compile_Context_Type *)SLmalloc (sizeof (Compile_Context_Type));
+ if (cc == NULL)
+ return -1;
+ memset ((char *) cc, 0, sizeof (Compile_Context_Type));
+
+ lns = (SLang_Name_Type **) SLcalloc (sizeof (SLang_Name_Type *), SLLOCALS_HASH_TABLE_SIZE);
+ if (lns == NULL)
+ {
+ SLfree ((char *) cc);
+ return -1;
+ }
+
+#if _SLANG_HAS_DEBUG_CODE
+ if ((name != NULL)
+ && (NULL == (name = SLang_create_slstring (name))))
+ {
+ SLfree ((char *) cc);
+ SLfree ((char *) lns);
+ return -1;
+ }
+
+ cc->compile_filename = This_Compile_Filename;
+ This_Compile_Filename = name;
+#endif
+
+ cc->static_namespace = This_Static_NameSpace;
+ cc->compile_variable_mode = Default_Variable_Mode;
+ cc->define_function = Default_Define_Function;
+ cc->locals_hash_table = Locals_Hash_Table;
+
+ cc->lang_defining_function = Lang_Defining_Function;
+ cc->local_variable_number = Local_Variable_Number;
+ cc->function_args_number = Function_Args_Number;
+ cc->locals_hash_table = Locals_Hash_Table;
+ cc->compile_mode_function = Compile_Mode_Function;
+
+ cc->next = Compile_Context_Stack;
+ Compile_Context_Stack = cc;
+
+ Compile_Mode_Function = compile_basic_token_mode;
+ Default_Variable_Mode = compile_public_variable_mode;
+ Default_Define_Function = define_public_function;
+ Lang_Defining_Function = 0;
+ Local_Variable_Number = 0;
+ Function_Args_Number = 0;
+ Locals_Hash_Table = lns;
+ return 0;
+}
+
+static int init_interpreter (void)
+{
+ SLang_NameSpace_Type *ns;
+
+ if (Global_NameSpace != NULL)
+ return 0;
+
+ if (NULL == (ns = _SLns_allocate_namespace ("***GLOBAL***", SLGLOBALS_HASH_TABLE_SIZE)))
+ return -1;
+ if (-1 == _SLns_set_namespace_name (ns, "Global"))
+ return -1;
+ Global_NameSpace = ns;
+
+ _SLRun_Stack = (SLang_Object_Type *) SLcalloc (SLANG_MAX_STACK_LEN,
+ sizeof (SLang_Object_Type));
+ if (_SLRun_Stack == NULL)
+ return -1;
+
+ _SLStack_Pointer = _SLRun_Stack;
+ _SLStack_Pointer_Max = _SLRun_Stack + SLANG_MAX_STACK_LEN;
+
+ SLShort_Blocks[0].bc_main_type = _SLANG_BC_RETURN;
+ SLShort_Blocks[2].bc_main_type = _SLANG_BC_BREAK;
+ SLShort_Blocks[4].bc_main_type = _SLANG_BC_CONTINUE;
+
+ Num_Args_Stack = (int *) SLmalloc (sizeof (int) * SLANG_MAX_RECURSIVE_DEPTH);
+ if (Num_Args_Stack == NULL)
+ {
+ SLfree ((char *) _SLRun_Stack);
+ return -1;
+ }
+ Recursion_Depth = 0;
+ Frame_Pointer_Stack = (unsigned int *) SLmalloc (sizeof (unsigned int) * SLANG_MAX_RECURSIVE_DEPTH);
+ if (Frame_Pointer_Stack == NULL)
+ {
+ SLfree ((char *) _SLRun_Stack);
+ SLfree ((char *)Num_Args_Stack);
+ return -1;
+ }
+ Frame_Pointer_Depth = 0;
+ Frame_Pointer = _SLRun_Stack;
+
+ Default_Variable_Mode = compile_public_variable_mode;
+ Default_Define_Function = define_public_function;
+ return 0;
+}
+
+static int add_generic_table (SLang_NameSpace_Type *ns,
+ SLang_Name_Type *table, char *pp_name,
+ unsigned int entry_len)
+{
+ SLang_Name_Type *t, **ns_table;
+ char *name;
+ unsigned int table_size;
+
+ if (-1 == init_interpreter ())
+ return -1;
+
+ if (ns == NULL)
+ ns = Global_NameSpace;
+
+ ns_table = ns->table;
+ table_size = ns->table_size;
+
+ if ((pp_name != NULL)
+ && (-1 == SLdefine_for_ifdef (pp_name)))
+ return -1;
+
+ t = table;
+ while (NULL != (name = t->name))
+ {
+ unsigned long hash;
+
+ /* Backward compatibility: '.' WAS used as hash marker */
+ if (*name == '.')
+ {
+ name++;
+ t->name = name;
+ }
+
+ if (NULL == (name = SLang_create_slstring (name)))
+ return -1;
+
+ t->name = name;
+
+ hash = _SLcompute_string_hash (name);
+ hash = hash % table_size;
+
+ t->next = ns_table [(unsigned int) hash];
+ ns_table [(unsigned int) hash] = t;
+
+ t = (SLang_Name_Type *) ((char *)t + entry_len);
+ }
+
+ return 0;
+}
+
+int SLadd_intrin_fun_table (SLang_Intrin_Fun_Type *tbl, char *pp)
+{
+ return add_generic_table (NULL, (SLang_Name_Type *) tbl, pp, sizeof (SLang_Intrin_Fun_Type));
+}
+
+int SLadd_intrin_var_table (SLang_Intrin_Var_Type *tbl, char *pp)
+{
+ return add_generic_table (NULL, (SLang_Name_Type *) tbl, pp, sizeof (SLang_Intrin_Var_Type));
+}
+
+int SLadd_app_unary_table (SLang_App_Unary_Type *tbl, char *pp)
+{
+ return add_generic_table (NULL, (SLang_Name_Type *) tbl, pp, sizeof (SLang_App_Unary_Type));
+}
+
+int SLadd_math_unary_table (SLang_Math_Unary_Type *tbl, char *pp)
+{
+ return add_generic_table (NULL, (SLang_Name_Type *) tbl, pp, sizeof (SLang_Math_Unary_Type));
+}
+
+int SLadd_iconstant_table (SLang_IConstant_Type *tbl, char *pp)
+{
+ return add_generic_table (NULL, (SLang_Name_Type *) tbl, pp, sizeof (SLang_IConstant_Type));
+}
+
+#if SLANG_HAS_FLOAT
+int SLadd_dconstant_table (SLang_DConstant_Type *tbl, char *pp)
+{
+ return add_generic_table (NULL, (SLang_Name_Type *) tbl, pp, sizeof (SLang_DConstant_Type));
+}
+#endif
+
+/* ----------- */
+int SLns_add_intrin_fun_table (SLang_NameSpace_Type *ns, SLang_Intrin_Fun_Type *tbl, char *pp)
+{
+ return add_generic_table (ns, (SLang_Name_Type *) tbl, pp, sizeof (SLang_Intrin_Fun_Type));
+}
+
+int SLns_add_intrin_var_table (SLang_NameSpace_Type *ns, SLang_Intrin_Var_Type *tbl, char *pp)
+{
+ return add_generic_table (ns, (SLang_Name_Type *) tbl, pp, sizeof (SLang_Intrin_Var_Type));
+}
+
+int SLns_add_app_unary_table (SLang_NameSpace_Type *ns, SLang_App_Unary_Type *tbl, char *pp)
+{
+ return add_generic_table (ns, (SLang_Name_Type *) tbl, pp, sizeof (SLang_App_Unary_Type));
+}
+
+int SLns_add_math_unary_table (SLang_NameSpace_Type *ns, SLang_Math_Unary_Type *tbl, char *pp)
+{
+ return add_generic_table (ns, (SLang_Name_Type *) tbl, pp, sizeof (SLang_Math_Unary_Type));
+}
+
+int SLns_add_iconstant_table (SLang_NameSpace_Type *ns, SLang_IConstant_Type *tbl, char *pp)
+{
+ return add_generic_table (ns, (SLang_Name_Type *) tbl, pp, sizeof (SLang_IConstant_Type));
+}
+
+#if SLANG_HAS_FLOAT
+int SLns_add_dconstant_table (SLang_NameSpace_Type *ns, SLang_DConstant_Type *tbl, char *pp)
+{
+ return add_generic_table (ns, (SLang_Name_Type *) tbl, pp, sizeof (SLang_DConstant_Type));
+}
+#endif
+
+/* what is a bitmapped value:
+ * 1 intrin fun
+ * 2 user fun
+ * 4 intrin var
+ * 8 user defined var
+ */
+SLang_Array_Type *_SLang_apropos (char *namespace_name, char *pat, unsigned int what)
+{
+ SLang_NameSpace_Type *ns;
+
+ if (namespace_name == NULL)
+ namespace_name = "Global";
+
+ if (*namespace_name == 0)
+ ns = This_Static_NameSpace;
+ else ns = _SLns_find_namespace (namespace_name);
+
+ return _SLnspace_apropos (ns, pat, what);
+}
+
+void _SLang_implements_intrinsic (char *name)
+{
+ if (This_Static_NameSpace == NULL)
+ {
+ SLang_verror (SL_INTRINSIC_ERROR, "No namespace available");
+ return;
+ }
+
+ (void) _SLns_set_namespace_name (This_Static_NameSpace, name);
+
+ Default_Define_Function = define_static_function;
+ Default_Variable_Mode = compile_static_variable_mode;
+}
+
+void _SLang_use_namespace_intrinsic (char *name)
+{
+ SLang_NameSpace_Type *ns;
+
+ if (NULL == (ns = _SLns_find_namespace (name)))
+ {
+ SLang_verror (SL_INTRINSIC_ERROR, "Namespace %s does not exist", name);
+ return;
+ }
+ This_Static_NameSpace = ns;
+ if (Global_NameSpace == ns)
+ {
+ Default_Define_Function = define_public_function;
+ Default_Variable_Mode = compile_public_variable_mode;
+ }
+ else
+ {
+ Default_Define_Function = define_static_function;
+ Default_Variable_Mode = compile_static_variable_mode;
+ }
+}
+
+
+char *_SLang_cur_namespace_intrinsic (void)
+{
+ if (This_Static_NameSpace == NULL)
+ return "Global";
+
+ if (This_Static_NameSpace->namespace_name == NULL)
+ return "";
+
+ return This_Static_NameSpace->namespace_name;
+}
diff --git a/mdk-stage1/slang/slang.h b/mdk-stage1/slang/slang.h
new file mode 100644
index 000000000..900b14043
--- /dev/null
+++ b/mdk-stage1/slang/slang.h
@@ -0,0 +1,1930 @@
+#ifndef DAVIS_SLANG_H_
+#define DAVIS_SLANG_H_
+/* -*- mode: C; mode: fold; -*- */
+/* Copyright (c) 1992, 1999, 2001 John E. Davis
+ * This file is part of the S-Lang library.
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Perl Artistic License.
+ */
+#define SLANG_VERSION 10404
+#define SLANG_VERSION_STRING "1.4.4"
+
+/*{{{ System Dependent Macros and Typedefs */
+
+#if defined(__WATCOMC__) && defined(DOS)
+# ifndef __MSDOS__
+# define __MSDOS__
+# endif
+# ifndef DOS386
+# define DOS386
+# endif
+# ifndef IBMPC_SYSTEM
+# define IBMPC_SYSTEM
+# endif
+#endif /* __watcomc__ */
+
+#if defined(unix) || defined(__unix)
+# ifndef __unix__
+# define __unix__ 1
+# endif
+#endif
+
+#if !defined(__GO32__)
+# ifdef __unix__
+# define REAL_UNIX_SYSTEM
+# endif
+#endif
+
+/* Set of the various defines for pc systems. This includes OS/2 */
+#ifdef __GO32__
+# ifndef __DJGPP__
+# define __DJGPP__ 1
+# endif
+# ifndef IBMPC_SYSTEM
+# define IBMPC_SYSTEM
+# endif
+#endif
+
+#ifdef __BORLANDC__
+# ifndef IBMPC_SYSTEM
+# define IBMPC_SYSTEM
+# endif
+#endif
+
+#ifdef __MSDOS__
+# ifndef IBMPC_SYSTEM
+# define IBMPC_SYSTEM
+# endif
+#endif
+
+#if defined(OS2) || defined(__os2__)
+# ifndef IBMPC_SYSTEM
+# define IBMPC_SYSTEM
+# endif
+# ifndef __os2__
+# define __os2__
+# endif
+#endif
+
+#if defined(__NT__) || defined(__MINGW32__) || defined(__CYGWIN32__)
+# ifndef IBMPC_SYSTEM
+# define IBMPC_SYSTEM
+# endif
+#endif
+
+#if defined(IBMPC_SYSTEM) || defined(VMS)
+# ifdef REAL_UNIX_SYSTEM
+# undef REAL_UNIX_SYSTEM
+# endif
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+#if 0
+}
+#endif
+
+#include <stdio.h>
+#include <stdarg.h>
+#if defined(__STDC__) || defined(__BORLANDC__) || defined(__cplusplus)
+# include <stddef.h> /* for offsetof */
+#endif
+
+/* ---------------------------- Generic Macros ----------------------------- */
+
+/* __SC__ is defined for Symantec C++
+ DOS386 is defined for -mx memory model, 32 bit DOS extender. */
+
+#if defined(__SC__) && !defined(DOS386)
+# include <dos.h>
+#endif
+
+#if defined(__BORLANDC__)
+# include <alloc.h>
+#endif
+
+#if defined (__cplusplus) || defined(__STDC__) || defined(IBMPC_SYSTEM)
+ typedef void *VOID_STAR;
+#else
+ typedef unsigned char *VOID_STAR;
+#endif
+
+typedef int (*FVOID_STAR)(void);
+
+#if defined(__MSDOS_) && defined(__BORLANDC__)
+# define SLFREE(buf) farfree((void far *)(buf))
+# define SLMALLOC(x) farmalloc((unsigned long) (x))
+# define SLREALLOC(buf, n) farrealloc((void far *) (buf), (unsigned long) (n))
+# define SLCALLOC(n, m) farcalloc((unsigned long) (n), (unsigned long) (m))
+#else
+# if defined(VMS) && !defined(__DECC)
+# define SLFREE VAXC$FREE_OPT
+# define SLMALLOC VAXC$MALLOC_OPT
+# define SLREALLOC VAXC$REALLOC_OPT
+# define SLCALLOC VAXC$CALLOC_OPT
+# else
+# define SLFREE(x) free((char *)(x))
+# define SLMALLOC malloc
+# define SLREALLOC realloc
+# define SLCALLOC calloc
+# endif
+#endif
+
+ extern char *SLdebug_malloc (unsigned long);
+ extern char *SLdebug_calloc (unsigned long, unsigned long);
+ extern char *SLdebug_realloc (char *, unsigned long);
+ extern void SLdebug_free (char *);
+ extern void SLmalloc_dump_statistics (void);
+ extern char *SLstrcpy(register char *, register char *);
+ extern int SLstrcmp(register char *, register char *);
+ extern char *SLstrncpy(char *, register char *, register int);
+
+ extern void SLmemset (char *, char, int);
+ extern char *SLmemchr (register char *, register char, register int);
+ extern char *SLmemcpy (char *, char *, int);
+ extern int SLmemcmp (char *, char *, int);
+
+/*}}}*/
+
+/*{{{ Interpreter Typedefs */
+
+typedef struct _SLang_Name_Type
+{
+ char *name;
+ struct _SLang_Name_Type *next;
+ char name_type;
+ /* These values must be less than 0x10 because they map directly
+ * to byte codes. See _slang.h.
+ */
+#define SLANG_LVARIABLE 0x01
+#define SLANG_GVARIABLE 0x02
+#define SLANG_IVARIABLE 0x03 /* intrinsic variables */
+ /* Note!!! For Macro MAKE_VARIABLE below to work, SLANG_IVARIABLE Must
+ be 1 less than SLANG_RVARIABLE!!! */
+#define SLANG_RVARIABLE 0x04 /* read only variable */
+#define SLANG_INTRINSIC 0x05
+#define SLANG_FUNCTION 0x06
+#define SLANG_MATH_UNARY 0x07
+#define SLANG_APP_UNARY 0x08
+#define SLANG_ICONSTANT 0x09
+#define SLANG_DCONSTANT 0x0A
+#define SLANG_PVARIABLE 0x0B /* private */
+#define SLANG_PFUNCTION 0x0C /* private */
+
+ /* Rest of fields depend on name type */
+}
+SLang_Name_Type;
+
+typedef struct
+{
+ char *name;
+ struct _SLang_Name_Type *next; /* this is for the hash table */
+ char name_type;
+
+ FVOID_STAR i_fun; /* address of object */
+
+ /* Do not change this without modifying slang.c:execute_intrinsic_fun */
+#define SLANG_MAX_INTRIN_ARGS 7
+ unsigned char arg_types [SLANG_MAX_INTRIN_ARGS];
+ unsigned char num_args;
+ unsigned char return_type;
+}
+SLang_Intrin_Fun_Type;
+
+typedef struct
+{
+ char *name;
+ SLang_Name_Type *next;
+ char name_type;
+
+ VOID_STAR addr;
+ unsigned char type;
+}
+SLang_Intrin_Var_Type;
+
+typedef struct
+{
+ char *name;
+ SLang_Name_Type *next;
+ char name_type;
+
+ int unary_op;
+}
+SLang_App_Unary_Type;
+
+typedef struct
+{
+ char *name;
+ SLang_Name_Type *next;
+ char name_type;
+
+ int unary_op;
+}
+SLang_Math_Unary_Type;
+
+typedef struct
+{
+ char *name;
+ SLang_Name_Type *next;
+ char name_type;
+ int i;
+}
+SLang_IConstant_Type;
+
+typedef struct
+{
+ char *name;
+ SLang_Name_Type *next;
+ char name_type;
+ double d;
+}
+SLang_DConstant_Type;
+
+typedef struct
+{
+ char *field_name;
+ unsigned int offset;
+ unsigned char type;
+ unsigned char read_only;
+}
+SLang_IStruct_Field_Type;
+
+extern int SLadd_intrin_fun_table (SLang_Intrin_Fun_Type *, char *);
+extern int SLadd_intrin_var_table (SLang_Intrin_Var_Type *, char *);
+extern int SLadd_app_unary_table (SLang_App_Unary_Type *, char *);
+extern int SLadd_math_unary_table (SLang_Math_Unary_Type *, char *);
+extern int SLadd_iconstant_table (SLang_IConstant_Type *, char *);
+extern int SLadd_dconstant_table (SLang_DConstant_Type *, char *);
+extern int SLadd_istruct_table (SLang_IStruct_Field_Type *, VOID_STAR, char *);
+
+typedef struct _SLang_NameSpace_Type SLang_NameSpace_Type;
+
+extern int SLns_add_intrin_fun_table (SLang_NameSpace_Type *, SLang_Intrin_Fun_Type *, char *);
+extern int SLns_add_intrin_var_table (SLang_NameSpace_Type *, SLang_Intrin_Var_Type *, char *);
+extern int SLns_add_app_unary_table (SLang_NameSpace_Type *, SLang_App_Unary_Type *, char *);
+extern int SLns_add_math_unary_table (SLang_NameSpace_Type *, SLang_Math_Unary_Type *, char *);
+extern int SLns_add_iconstant_table (SLang_NameSpace_Type *, SLang_IConstant_Type *, char *);
+extern int SLns_add_dconstant_table (SLang_NameSpace_Type *, SLang_DConstant_Type *, char *);
+extern int SLns_add_istruct_table (SLang_NameSpace_Type *, SLang_IStruct_Field_Type *, VOID_STAR, char *);
+
+extern SLang_NameSpace_Type *SLns_create_namespace (char *);
+extern void SLns_delete_namespace (SLang_NameSpace_Type *);
+
+typedef struct SLang_Load_Type
+{
+ int type;
+
+ VOID_STAR client_data;
+ /* Pointer to data that client needs for loading */
+
+ int auto_declare_globals;
+ /* if non-zero, undefined global variables are declared as static */
+
+ char *(*read)(struct SLang_Load_Type *);
+ /* function to call to read next line from obj. */
+
+ unsigned int line_num;
+ /* Number of lines read, used for error reporting */
+
+ int parse_level;
+ /* 0 if at top level of parsing */
+
+ char *name;
+ /* Name of this object, e.g., filename. This name should be unique because
+ * it alone determines the name space for static objects associated with
+ * the compilable unit.
+ */
+
+ unsigned long reserved[4];
+ /* For future expansion */
+} SLang_Load_Type;
+
+extern SLang_Load_Type *SLallocate_load_type (char *);
+extern void SLdeallocate_load_type (SLang_Load_Type *);
+
+/* Returns SLang_Error upon failure */
+extern int SLang_load_object (SLang_Load_Type *);
+extern int (*SLang_Load_File_Hook)(char *);
+extern int (*SLang_Auto_Declare_Var_Hook) (char *);
+
+extern int SLang_generate_debug_info (int);
+
+
+#if defined(ultrix) && !defined(__GNUC__)
+# ifndef NO_PROTOTYPES
+# define NO_PROTOTYPES
+# endif
+#endif
+
+#ifndef NO_PROTOTYPES
+# define _PROTO(x) x
+#else
+# define _PROTO(x) ()
+#endif
+
+typedef struct SL_OOBinary_Type
+{
+ unsigned char data_type; /* partner type for binary op */
+
+ int (*binary_function)_PROTO((int,
+ unsigned char, VOID_STAR, unsigned int,
+ unsigned char, VOID_STAR, unsigned int,
+ VOID_STAR));
+
+ int (*binary_result) _PROTO((int, unsigned char, unsigned char, unsigned char *));
+ struct SL_OOBinary_Type *next;
+}
+SL_OOBinary_Type;
+
+typedef struct _SL_Typecast_Type
+{
+ unsigned char data_type; /* to_type */
+ int allow_implicit;
+
+ int (*typecast)_PROTO((unsigned char, VOID_STAR, unsigned int,
+ unsigned char, VOID_STAR));
+ struct _SL_Typecast_Type *next;
+}
+SL_Typecast_Type;
+
+typedef struct _SLang_Struct_Type SLang_Struct_Type;
+
+#if defined(SL_APP_WANTS_FOREACH)
+/* It is up to the application to define struct _SLang_Foreach_Context_Type */
+typedef struct _SLang_Foreach_Context_Type SLang_Foreach_Context_Type;
+#else
+typedef int SLang_Foreach_Context_Type;
+#endif
+
+typedef struct
+{
+ unsigned char cl_class_type;
+#define SLANG_CLASS_TYPE_MMT 0
+#define SLANG_CLASS_TYPE_SCALAR 1
+#define SLANG_CLASS_TYPE_VECTOR 2
+#define SLANG_CLASS_TYPE_PTR 3
+
+ unsigned int cl_data_type; /* SLANG_INTEGER_TYPE, etc... */
+ char *cl_name; /* slstring type */
+
+ unsigned int cl_sizeof_type;
+ VOID_STAR cl_transfer_buf; /* cl_sizeof_type bytes*/
+
+ /* Methods */
+
+ /* Most of the method functions are prototyped:
+ * int method (unsigned char type, VOID_STAR addr);
+ * Here, @type@ represents the type of object that the method is asked
+ * to deal with. The second parameter @addr@ will contain the ADDRESS of
+ * the object. For example, if type is SLANG_INT_TYPE, then @addr@ will
+ * actually be int *. Similary, if type is SLANG_STRING_TYPE,
+ * then @addr@ will contain the address of the string, i.e., char **.
+ */
+
+ void (*cl_destroy)_PROTO((unsigned char, VOID_STAR));
+ /* Prototype: void destroy(unsigned type, VOID_STAR val)
+ * Called to delete/free the object */
+
+ char *(*cl_string)_PROTO((unsigned char, VOID_STAR));
+ /* Prototype: char *to_string (unsigned char t, VOID_STAR p);
+ * Here p is a pointer to the object for which a string representation
+ * is to be returned. The returned pointer is to be a MALLOCED string.
+ */
+
+ /* Prototype: void push(unsigned char type, VOID_STAR v);
+ * Push a copy of the object of type @type@ at address @v@ onto the
+ * stack.
+ */
+ int (*cl_push)_PROTO((unsigned char, VOID_STAR));
+
+ /* Prototype: int pop(unsigned char type, VOID_STAR v);
+ * Pops value from stack and assign it to object, whose address is @v@.
+ */
+ int (*cl_pop)_PROTO((unsigned char, VOID_STAR));
+
+ int (*cl_unary_op_result_type)_PROTO((int, unsigned char, unsigned char *));
+ int (*cl_unary_op)_PROTO((int, unsigned char, VOID_STAR, unsigned int, VOID_STAR));
+
+ int (*cl_app_unary_op_result_type)_PROTO((int, unsigned char, unsigned char *));
+ int (*cl_app_unary_op)_PROTO((int, unsigned char, VOID_STAR, unsigned int, VOID_STAR));
+
+ /* If this function is non-NULL, it will be called for sin, cos, etc... */
+#define SLMATH_SIN 1
+#define SLMATH_COS 2
+#define SLMATH_TAN 3
+#define SLMATH_ATAN 4
+#define SLMATH_ASIN 5
+#define SLMATH_ACOS 6
+#define SLMATH_EXP 7
+#define SLMATH_LOG 8
+#define SLMATH_SQRT 9
+#define SLMATH_LOG10 10
+#define SLMATH_REAL 11
+#define SLMATH_IMAG 12
+#define SLMATH_SINH 13
+#define SLMATH_COSH 14
+#define SLMATH_TANH 15
+#define SLMATH_ATANH 16
+#define SLMATH_ASINH 17
+#define SLMATH_ACOSH 18
+#define SLMATH_TODOUBLE 19
+#define SLMATH_CONJ 20
+
+ int (*cl_math_op)_PROTO((int, unsigned char, VOID_STAR, unsigned int, VOID_STAR));
+ int (*cl_math_op_result_type)_PROTO((int, unsigned char, unsigned char *));
+
+ SL_OOBinary_Type *cl_binary_ops;
+ SL_Typecast_Type *cl_typecast_funs;
+
+ void (*cl_byte_code_destroy)_PROTO((unsigned char, VOID_STAR));
+ void (*cl_user_destroy_fun)_PROTO((unsigned char, VOID_STAR));
+ int (*cl_init_array_object)_PROTO((unsigned char, VOID_STAR));
+ int (*cl_datatype_deref)_PROTO((unsigned char));
+ SLang_Struct_Type *cl_struct_def;
+ int (*cl_dereference) _PROTO((unsigned char, VOID_STAR));
+ int (*cl_acopy) (unsigned char, VOID_STAR, VOID_STAR);
+ int (*cl_apop) _PROTO((unsigned char, VOID_STAR));
+ int (*cl_apush) _PROTO((unsigned char, VOID_STAR));
+ int (*cl_push_literal) _PROTO((unsigned char, VOID_STAR));
+ void (*cl_adestroy)_PROTO((unsigned char, VOID_STAR));
+ int (*cl_push_intrinsic)_PROTO((unsigned char, VOID_STAR));
+ int (*cl_void_typecast)_PROTO((unsigned char, VOID_STAR, unsigned int, unsigned char, VOID_STAR));
+
+ int (*cl_anytype_typecast)_PROTO((unsigned char, VOID_STAR, unsigned int, unsigned char, VOID_STAR));
+
+ /* Array access functions */
+ int (*cl_aput) (unsigned char, unsigned int);
+ int (*cl_aget) (unsigned char, unsigned int);
+ int (*cl_anew) (unsigned char, unsigned int);
+
+ /* length method */
+ int (*cl_length) (unsigned char, VOID_STAR, unsigned int *);
+
+ /* foreach */
+ SLang_Foreach_Context_Type *(*cl_foreach_open) (unsigned char, unsigned int);
+ void (*cl_foreach_close) (unsigned char, SLang_Foreach_Context_Type *);
+ int (*cl_foreach) (unsigned char, SLang_Foreach_Context_Type *);
+
+ /* Structure access: get and put (assign to) fields */
+ int (*cl_sput) (unsigned char, char *);
+ int (*cl_sget) (unsigned char, char *);
+
+ /* File I/O */
+ int (*cl_fread) (unsigned char, FILE *, VOID_STAR, unsigned int, unsigned int *);
+ int (*cl_fwrite) (unsigned char, FILE *, VOID_STAR, unsigned int, unsigned int *);
+ int (*cl_fdread) (unsigned char, int, VOID_STAR, unsigned int, unsigned int *);
+ int (*cl_fdwrite) (unsigned char, int, VOID_STAR, unsigned int, unsigned int *);
+
+ int (*cl_to_bool) (unsigned char, int *);
+
+ int (*cl_cmp)(unsigned char, VOID_STAR, VOID_STAR, int *);
+
+} SLang_Class_Type;
+
+/* These are the low-level functions for building push/pop methods. They
+ * know nothing about memory management. For SLANG_CLASS_TYPE_MMT, use the
+ * MMT push/pop functions instead.
+ */
+extern int SLclass_push_double_obj (unsigned char, double);
+extern int SLclass_push_float_obj (unsigned char, float);
+extern int SLclass_push_long_obj (unsigned char, long);
+extern int SLclass_push_int_obj (unsigned char, int);
+extern int SLclass_push_short_obj (unsigned char, short);
+extern int SLclass_push_char_obj (unsigned char, char);
+extern int SLclass_push_ptr_obj (unsigned char, VOID_STAR);
+extern int SLclass_pop_double_obj (unsigned char, double *);
+extern int SLclass_pop_float_obj (unsigned char, float *);
+extern int SLclass_pop_long_obj (unsigned char, long *);
+extern int SLclass_pop_int_obj (unsigned char, int *);
+extern int SLclass_pop_short_obj (unsigned char, short *);
+extern int SLclass_pop_char_obj (unsigned char, char *);
+extern int SLclass_pop_ptr_obj (unsigned char, VOID_STAR *);
+
+extern SLang_Class_Type *SLclass_allocate_class (char *);
+extern int SLclass_get_class_id (SLang_Class_Type *cl);
+extern int SLclass_create_synonym (char *, unsigned char);
+extern int SLclass_is_class_defined (unsigned char);
+
+extern int SLclass_register_class (SLang_Class_Type *, unsigned char, unsigned int, unsigned char);
+extern int SLclass_set_string_function (SLang_Class_Type *, char *(*)(unsigned char, VOID_STAR));
+extern int SLclass_set_destroy_function (SLang_Class_Type *, void (*)(unsigned char, VOID_STAR));
+extern int SLclass_set_push_function (SLang_Class_Type *, int (*)(unsigned char, VOID_STAR));
+extern int SLclass_set_pop_function (SLang_Class_Type *, int (*)(unsigned char, VOID_STAR));
+
+extern int SLclass_set_aget_function (SLang_Class_Type *, int (*)(unsigned char, unsigned int));
+extern int SLclass_set_aput_function (SLang_Class_Type *, int (*)(unsigned char, unsigned int));
+extern int SLclass_set_anew_function (SLang_Class_Type *, int (*)(unsigned char, unsigned int));
+
+extern int SLclass_set_sget_function (SLang_Class_Type *, int (*)(unsigned char, char *));
+extern int SLclass_set_sput_function (SLang_Class_Type *, int (*)(unsigned char, char *));
+
+/* Typecast object on the stack to type p1. p2 and p3 should be set to 1 */
+extern int SLclass_typecast (unsigned char, int, int);
+
+extern int SLclass_add_unary_op (unsigned char,
+ int (*) (int,
+ unsigned char, VOID_STAR, unsigned int,
+ VOID_STAR),
+ int (*) (int, unsigned char, unsigned char *));
+
+extern int
+SLclass_add_app_unary_op (unsigned char,
+ int (*) (int,
+ unsigned char, VOID_STAR, unsigned int,
+ VOID_STAR),
+ int (*) (int, unsigned char, unsigned char *));
+
+extern int
+SLclass_add_binary_op (unsigned char, unsigned char,
+ int (*) (int,
+ unsigned char, VOID_STAR, unsigned int,
+ unsigned char, VOID_STAR, unsigned int,
+ VOID_STAR),
+ int (*) (int, unsigned char, unsigned char, unsigned char *));
+
+extern int
+SLclass_add_math_op (unsigned char,
+ int (*)(int,
+ unsigned char, VOID_STAR, unsigned int,
+ VOID_STAR),
+ int (*)(int, unsigned char, unsigned char *));
+
+extern int
+SLclass_add_typecast (unsigned char /* from */, unsigned char /* to */,
+ int (*)_PROTO((unsigned char, VOID_STAR, unsigned int,
+ unsigned char, VOID_STAR)),
+ int /* allow implicit typecasts */
+ );
+
+extern char *SLclass_get_datatype_name (unsigned char);
+
+extern double SLcomplex_abs (double *);
+extern double *SLcomplex_times (double *, double *, double *);
+extern double *SLcomplex_divide (double *, double *, double *);
+extern double *SLcomplex_sin (double *, double *);
+extern double *SLcomplex_cos (double *, double *);
+extern double *SLcomplex_tan (double *, double *);
+extern double *SLcomplex_asin (double *, double *);
+extern double *SLcomplex_acos (double *, double *);
+extern double *SLcomplex_atan (double *, double *);
+extern double *SLcomplex_exp (double *, double *);
+extern double *SLcomplex_log (double *, double *);
+extern double *SLcomplex_log10 (double *, double *);
+extern double *SLcomplex_sqrt (double *, double *);
+extern double *SLcomplex_sinh (double *, double *);
+extern double *SLcomplex_cosh (double *, double *);
+extern double *SLcomplex_tanh (double *, double *);
+extern double *SLcomplex_pow (double *, double *, double *);
+extern double SLmath_hypot (double x, double y);
+
+/* Not implemented yet */
+extern double *SLcomplex_asinh (double *, double *);
+extern double *SLcomplex_acosh (double *, double *);
+extern double *SLcomplex_atanh (double *, double *);
+
+#ifdef _SLANG_SOURCE_
+typedef struct _SLang_MMT_Type SLang_MMT_Type;
+#else
+typedef int SLang_MMT_Type;
+#endif
+
+extern void SLang_free_mmt (SLang_MMT_Type *);
+extern VOID_STAR SLang_object_from_mmt (SLang_MMT_Type *);
+extern SLang_MMT_Type *SLang_create_mmt (unsigned char, VOID_STAR);
+extern int SLang_push_mmt (SLang_MMT_Type *);
+extern SLang_MMT_Type *SLang_pop_mmt (unsigned char);
+extern void SLang_inc_mmt (SLang_MMT_Type *);
+
+/* Maximum number of dimensions of an array. */
+#define SLARRAY_MAX_DIMS 7
+typedef struct _SLang_Array_Type
+{
+ unsigned char data_type;
+ unsigned int sizeof_type;
+ VOID_STAR data;
+ unsigned int num_elements;
+ unsigned int num_dims;
+ int dims [SLARRAY_MAX_DIMS];
+ VOID_STAR (*index_fun)_PROTO((struct _SLang_Array_Type *, int *));
+ /* This function is designed to allow a type to store an array in
+ * any manner it chooses. This function returns the address of the data
+ * value at the specified index location.
+ */
+ unsigned int flags;
+#define SLARR_DATA_VALUE_IS_READ_ONLY 1
+#define SLARR_DATA_VALUE_IS_POINTER 2
+#define SLARR_DATA_VALUE_IS_RANGE 4
+#define SLARR_DATA_VALUE_IS_INTRINSIC 8
+ SLang_Class_Type *cl;
+ unsigned int num_refs;
+}
+SLang_Array_Type;
+
+extern int SLang_pop_array_of_type (SLang_Array_Type **, unsigned char);
+extern int SLang_pop_array (SLang_Array_Type **, int);
+extern int SLang_push_array (SLang_Array_Type *, int);
+extern void SLang_free_array (SLang_Array_Type *);
+extern SLang_Array_Type *SLang_create_array (unsigned char, int, VOID_STAR, int *, unsigned int);
+extern SLang_Array_Type *SLang_duplicate_array (SLang_Array_Type *);
+extern int SLang_get_array_element (SLang_Array_Type *, int *, VOID_STAR);
+extern int SLang_set_array_element (SLang_Array_Type *, int *, VOID_STAR);
+
+
+/*}}}*/
+
+/*{{{ Interpreter Function Prototypes */
+
+ extern volatile int SLang_Error;
+/* Non zero if error occurs. Must be reset to zero to continue. */
+/* error codes, severe errors are less than 0 */
+#define SL_APPLICATION_ERROR -2
+#define SL_VARIABLE_UNINITIALIZED -3
+#define SL_INTERNAL_ERROR -5
+#define SL_STACK_OVERFLOW -6
+#define SL_STACK_UNDERFLOW -7
+#define SL_UNDEFINED_NAME -8
+#define SL_SYNTAX_ERROR -9
+#define SL_DUPLICATE_DEFINITION -10
+#define SL_TYPE_MISMATCH -11
+#define SL_OBJ_UNKNOWN -13
+#define SL_UNKNOWN_ERROR -14
+#define SL_TYPE_UNDEFINED_OP_ERROR -16
+
+#define SL_INTRINSIC_ERROR 1
+/* Intrinsic error is an error generated by intrinsic functions */
+#define SL_USER_BREAK 2
+#define SL_DIVIDE_ERROR 3
+#define SL_OBJ_NOPEN 4
+#define SL_USER_ERROR 5
+#define SL_USAGE_ERROR 6
+#define SL_READONLY_ERROR 7
+#define SL_INVALID_PARM 8
+#define SL_NOT_IMPLEMENTED 9
+#define SL_MALLOC_ERROR 10
+#define SL_OVERFLOW 11
+#define SL_FLOATING_EXCEPTION 12
+
+/* Compatibility */
+#define USER_BREAK SL_USER_BREAK
+#define INTRINSIC_ERROR SL_INTRINSIC_ERROR
+
+ extern int SLang_Traceback;
+ /* If non-zero, dump an S-Lang traceback upon error. Available as
+ _traceback in S-Lang. */
+
+ extern char *SLang_User_Prompt;
+ /* Prompt to use when reading from stdin */
+ extern int SLang_Version;
+ extern char *SLang_Version_String;
+extern char *SLang_Doc_Dir;
+
+extern void (*SLang_VMessage_Hook) (char *, va_list);
+extern void SLang_vmessage (char *, ...);
+
+ extern void (*SLang_Error_Hook)(char *);
+ /* Pointer to application dependent error messaging routine. By default,
+ messages are displayed on stderr. */
+
+ extern void (*SLang_Exit_Error_Hook)(char *, va_list);
+ extern void SLang_exit_error (char *, ...);
+ extern void (*SLang_Dump_Routine)(char *);
+ /* Called if S-Lang traceback is enabled as well as other debugging
+ routines (e.g., trace). By default, these messages go to stderr. */
+
+ extern void (*SLang_Interrupt)(void);
+ /* function to call whenever inner interpreter is entered. This is
+ a good place to set SLang_Error to USER_BREAK. */
+
+ extern void (*SLang_User_Clear_Error)(void);
+ /* function that gets called when '_clear_error' is called. */
+
+ /* If non null, these call C functions before and after a slang function. */
+ extern void (*SLang_Enter_Function)(char *);
+extern void (*SLang_Exit_Function)(char *);
+
+extern int SLang_Num_Function_Args;
+
+/* Functions: */
+
+extern int SLang_init_all (void);
+/* Initializes interpreter and all modules */
+
+extern int SLang_init_slang (void);
+/* This function is mandatory and must be called by all applications that
+ * use the interpreter
+ */
+extern int SLang_init_posix_process (void); /* process specific intrinsics */
+extern int SLang_init_stdio (void); /* fgets, etc. stdio functions */
+extern int SLang_init_posix_dir (void);
+extern int SLang_init_ospath (void);
+
+extern int SLang_init_slmath (void);
+/* called if math functions sin, cos, etc... are needed. */
+
+ extern int SLang_init_slfile (void);
+ extern int SLang_init_slunix (void);
+ /* These functions are obsolte. Use init_stdio, posix_process, etc. */
+
+extern int SLang_init_slassoc (void);
+/* Assoc Arrays (Hashes) */
+
+extern int SLang_init_array (void);
+/* Additional arrays functions: transpose, etc... */
+
+/* Dynamic linking facility */
+extern int SLang_init_import (void);
+
+ extern int SLang_load_file (char *);
+ /* Load a file of S-Lang code for interpreting. If the parameter is
+ * NULL, input comes from stdin. */
+
+ extern void SLang_restart(int);
+ /* should be called if an error occurs. If the passed integer is
+ * non-zero, items are popped off the stack; otherwise, the stack is
+ * left intact. Any time the stack is believed to be trashed, this routine
+ * should be called with a non-zero argument (e.g., if setjmp/longjmp is
+ * called). */
+
+ extern int SLang_byte_compile_file(char *, int);
+ /* takes a file of S-Lang code and ``byte-compiles'' it for faster
+ * loading. The new filename is equivalent to the old except that a `c' is
+ * appended to the name. (e.g., init.sl --> init.slc). The second
+ * specified the method; currently, it is not used.
+ */
+
+ extern int SLang_autoload(char *, char *);
+ /* Automatically load S-Lang function p1 from file p2. This function
+ is also available via S-Lang */
+
+ extern int SLang_load_string(char *);
+ /* Like SLang_load_file except input is from a null terminated string. */
+
+ extern int SLdo_pop(void);
+ /* pops item off stack and frees any memory associated with it */
+ extern int SLdo_pop_n(unsigned int);
+ /* pops n items off stack and frees any memory associated with them */
+
+extern int SLang_pop_integer(int *);
+extern int SLang_pop_uinteger(unsigned int *);
+ /* pops integer *p0 from the stack. Returns 0 upon success and non-zero
+ * if the stack is empty or a type mismatch occurs, setting SLang_Error.
+ */
+extern int SLang_pop_char (char *);
+extern int SLang_pop_uchar (unsigned char *);
+extern int SLang_pop_short(short *);
+extern int SLang_pop_ushort(unsigned short *);
+extern int SLang_pop_long(long *);
+extern int SLang_pop_ulong(unsigned long *);
+
+extern int SLang_pop_float(float *);
+extern int SLang_pop_double(double *, int *, int *);
+ /* Pops double *p1 from stack. If *p3 is non-zero, *p1 was derived
+ from the integer *p2. Returns zero upon success. */
+
+ extern int SLang_pop_complex (double *, double *);
+
+ extern int SLpop_string (char **);
+ extern int SLang_pop_string(char **, int *);
+ /* pops string *p0 from stack. If *p1 is non-zero, the string must be
+ * freed after its use. DO NOT FREE p0 if *p1 IS ZERO! Returns 0 upon
+ * success */
+
+ extern int SLang_push_complex (double, double);
+
+ extern int SLang_push_char (char);
+ extern int SLang_push_uchar (unsigned char);
+
+ extern int SLang_push_integer(int);
+ extern int SLang_push_uinteger(unsigned int);
+ /* push integer p1 on stack */
+
+ extern int SLang_push_short(short);
+ extern int SLang_push_ushort(unsigned short);
+ extern int SLang_push_long(long);
+ extern int SLang_push_ulong(unsigned long);
+ extern int SLang_push_float(float);
+ extern int SLang_push_double(double);
+ /* Push double onto stack */
+
+ extern int SLang_push_string(char *);
+ /* Push string p1 onto stack */
+
+ extern int SLang_push_malloced_string(char *);
+ /* The normal SLang_push_string pushes an slstring. This one converts
+ * a normally malloced string to an slstring, and then frees the
+ * malloced string. So, do NOT use the malloced string after calling
+ * this routine because it will be freed! The routine returns -1 upon
+ * error, but the string will be freed.
+ */
+
+extern int SLang_push_null (void);
+extern int SLang_pop_null (void);
+
+extern int SLang_push_value (unsigned char type, VOID_STAR);
+extern int SLang_pop_value (unsigned char type, VOID_STAR);
+extern void SLang_free_value (unsigned char type, VOID_STAR);
+
+typedef struct _SLang_Object_Type SLang_Any_Type;
+
+extern int SLang_pop_anytype (SLang_Any_Type **);
+extern int SLang_push_anytype (SLang_Any_Type *);
+extern void SLang_free_anytype (SLang_Any_Type *);
+
+#ifdef _SLANG_SOURCE_
+typedef struct _SLang_Ref_Type SLang_Ref_Type;
+#else
+typedef int SLang_Ref_Type;
+#endif
+
+extern int SLang_pop_ref (SLang_Ref_Type **);
+extern void SLang_free_ref (SLang_Ref_Type *);
+extern int SLang_assign_to_ref (SLang_Ref_Type *, unsigned char, VOID_STAR);
+extern SLang_Name_Type *SLang_pop_function (void);
+extern SLang_Name_Type *SLang_get_fun_from_ref (SLang_Ref_Type *);
+extern void SLang_free_function (SLang_Name_Type *f);
+
+ extern int SLang_is_defined(char *);
+ /* Return non-zero is p1 is defined otherwise returns 0. */
+
+ extern int SLang_run_hooks(char *, unsigned int, ...);
+ /* calls S-Lang function p1 pushing p2 strings in the variable argument
+ * list onto the stack first.
+ * Returns -1 upon error, 1 if hooks exists and it ran,
+ * or 0 if hook does not exist. Thus it returns non-zero is hook was called.
+ */
+
+/* These functions return 1 if the indicated function exists and the function
+ * runs without error. If the function does not exist, the function returns
+ * 0. Otherwise -1 is returned with SLang_Error set appropriately.
+ */
+extern int SLexecute_function (SLang_Name_Type *);
+extern int SLang_execute_function(char *);
+
+
+extern int SLang_end_arg_list (void);
+extern int SLang_start_arg_list (void);
+
+extern void SLang_verror (int, char *, ...);
+
+extern void SLang_doerror(char *);
+ /* set SLang_Error and display p1 as error message */
+
+extern int SLang_add_intrinsic_array (char *, /* name */
+ unsigned char, /* type */
+ int, /* readonly */
+ VOID_STAR, /* data */
+ unsigned int, ...); /* num dims */
+
+extern int SLextract_list_element (char *, unsigned int, char,
+ char *, unsigned int);
+
+extern void SLexpand_escaped_string (register char *, register char *,
+ register char *);
+
+extern SLang_Name_Type *SLang_get_function (char *);
+extern void SLang_release_function (SLang_Name_Type *);
+
+extern int SLreverse_stack (int);
+extern int SLroll_stack (int);
+/* If argument p is positive, the top p objects on the stack are rolled
+ * up. If negative, the stack is rolled down.
+ */
+extern int SLdup_n (int n);
+/* Duplicate top n elements of stack */
+
+extern int SLang_peek_at_stack1 (void);
+extern int SLang_peek_at_stack (void);
+/* Returns type of next object on stack-- -1 upon stack underflow. */
+extern void SLmake_lut (unsigned char *, unsigned char *, unsigned char);
+
+ extern int SLang_guess_type (char *);
+
+extern int SLstruct_create_struct (unsigned int,
+ char **,
+ unsigned char *,
+ VOID_STAR *);
+
+/*}}}*/
+
+/*{{{ Misc Functions */
+
+/* This is an interface to atexit */
+extern int SLang_add_cleanup_function (void (*)(void));
+
+extern char *SLmake_string (char *);
+extern char *SLmake_nstring (char *, unsigned int);
+/* Returns a null terminated string made from the first n characters of the
+ * string.
+ */
+
+/* The string created by this routine must be freed by SLang_free_slstring
+ * and nothing else!! Also these strings must not be modified. Use
+ * SLmake_string if you intend to modify them!!
+ */
+extern char *SLang_create_nslstring (char *, unsigned int);
+extern char *SLang_create_slstring (char *);
+extern void SLang_free_slstring (char *); /* handles NULL */
+extern int SLang_pop_slstring (char **); /* free with SLang_free_slstring */
+extern char *SLang_concat_slstrings (char *a, char *b);
+extern char *SLang_create_static_slstring (char *); /* adds a string that will not get deleted */
+extern void SLstring_dump_stats (void);
+
+/* Binary strings */
+/* The binary string is an opaque type. Use the SLbstring_get_pointer function
+ * to get a pointer and length.
+ */
+typedef struct _SLang_BString_Type SLang_BString_Type;
+extern unsigned char *SLbstring_get_pointer (SLang_BString_Type *, unsigned int *);
+
+extern SLang_BString_Type *SLbstring_dup (SLang_BString_Type *);
+extern SLang_BString_Type *SLbstring_create (unsigned char *, unsigned int);
+
+/* The create_malloced function used the first argument which is assumed
+ * to be a pointer to a len + 1 malloced string. The extra byte is for
+ * \0 termination.
+ */
+extern SLang_BString_Type *SLbstring_create_malloced (unsigned char *, unsigned int, int);
+
+/* Create a bstring from an slstring */
+extern SLang_BString_Type *SLbstring_create_slstring (char *);
+
+extern void SLbstring_free (SLang_BString_Type *);
+extern int SLang_pop_bstring (SLang_BString_Type **);
+extern int SLang_push_bstring (SLang_BString_Type *);
+
+extern char *SLmalloc (unsigned int);
+extern char *SLcalloc (unsigned int, unsigned int);
+extern void SLfree(char *); /* This function handles NULL */
+extern char *SLrealloc (char *, unsigned int);
+
+extern char *SLcurrent_time_string (void);
+
+extern int SLatoi(unsigned char *);
+extern long SLatol (unsigned char *);
+extern unsigned long SLatoul (unsigned char *);
+
+extern int SLang_pop_fileptr (SLang_MMT_Type **, FILE **);
+extern char *SLang_get_name_from_fileptr (SLang_MMT_Type *);
+
+typedef struct _SLFile_FD_Type SLFile_FD_Type;
+extern SLFile_FD_Type *SLfile_create_fd (char *, int);
+extern void SLfile_free_fd (SLFile_FD_Type *);
+extern int SLfile_push_fd (SLFile_FD_Type *);
+extern int SLfile_pop_fd (SLFile_FD_Type **);
+extern int SLfile_get_fd (SLFile_FD_Type *, int *);
+extern SLFile_FD_Type *SLfile_dup_fd (SLFile_FD_Type *f0);
+extern int SLang_init_posix_io (void);
+
+typedef double (*SLang_To_Double_Fun_Type)(VOID_STAR);
+extern SLang_To_Double_Fun_Type SLarith_get_to_double_fun (unsigned char, unsigned int *);
+
+extern int SLang_set_argc_argv (int, char **);
+
+/*}}}*/
+
+/*{{{ SLang getkey interface Functions */
+
+#ifdef REAL_UNIX_SYSTEM
+extern int SLang_TT_Baud_Rate;
+extern int SLang_TT_Read_FD;
+#endif
+
+extern int SLang_init_tty (int, int, int);
+/* Initializes the tty for single character input. If the first parameter *p1
+ * is in the range 0-255, it will be used for the abort character;
+ * otherwise, (unix only) if it is -1, the abort character will be the one
+ * used by the terminal. If the second parameter p2 is non-zero, flow
+ * control is enabled. If the last parmeter p3 is zero, output processing
+ * is NOT turned on. A value of zero is required for the screen management
+ * routines. Returns 0 upon success. In addition, if SLang_TT_Baud_Rate ==
+ * 0 when this function is called, SLang will attempt to determine the
+ * terminals baud rate. As far as the SLang library is concerned, if
+ * SLang_TT_Baud_Rate is less than or equal to zero, the baud rate is
+ * effectively infinite.
+ */
+
+extern void SLang_reset_tty (void);
+/* Resets tty to what it was prior to a call to SLang_init_tty */
+#ifdef REAL_UNIX_SYSTEM
+extern void SLtty_set_suspend_state (int);
+ /* If non-zero argument, terminal driver will be told to react to the
+ * suspend character. If 0, it will not.
+ */
+extern int (*SLang_getkey_intr_hook) (void);
+#endif
+
+#define SLANG_GETKEY_ERROR 0xFFFF
+extern unsigned int SLang_getkey (void);
+/* reads a single key from the tty. If the read fails, 0xFFFF is returned. */
+
+#ifdef IBMPC_SYSTEM
+extern int SLgetkey_map_to_ansi (int);
+#endif
+
+extern int SLang_ungetkey_string (unsigned char *, unsigned int);
+extern int SLang_buffer_keystring (unsigned char *, unsigned int);
+extern int SLang_ungetkey (unsigned char);
+extern void SLang_flush_input (void);
+extern int SLang_input_pending (int);
+extern int SLang_Abort_Char;
+/* The value of the character (0-255) used to trigger SIGINT */
+extern int SLang_Ignore_User_Abort;
+/* If non-zero, pressing the abort character will not result in USER_BREAK
+ * SLang_Error. */
+
+extern int SLang_set_abort_signal (void (*)(int));
+/* If SIGINT is generated, the function p1 will be called. If p1 is NULL
+ * the SLang_default signal handler is called. This sets SLang_Error to
+ * USER_BREAK. I suspect most users will simply want to pass NULL.
+ */
+extern unsigned int SLang_Input_Buffer_Len;
+
+extern volatile int SLKeyBoard_Quit;
+
+#ifdef VMS
+/* If this function returns -1, ^Y will be added to input buffer. */
+extern int (*SLtty_VMS_Ctrl_Y_Hook) (void);
+#endif
+/*}}}*/
+
+/*{{{ SLang Keymap routines */
+
+typedef struct SLKeymap_Function_Type
+{
+ char *name;
+ int (*f)(void);
+}
+SLKeymap_Function_Type;
+
+#define SLANG_MAX_KEYMAP_KEY_SEQ 14
+typedef struct SLang_Key_Type
+{
+ struct SLang_Key_Type *next;
+ union
+ {
+ char *s;
+ FVOID_STAR f;
+ unsigned int keysym;
+ }
+ f;
+ unsigned char type; /* type of function */
+#define SLKEY_F_INTERPRET 0x01
+#define SLKEY_F_INTRINSIC 0x02
+#define SLKEY_F_KEYSYM 0x03
+ unsigned char str[SLANG_MAX_KEYMAP_KEY_SEQ + 1];/* key sequence */
+}
+SLang_Key_Type;
+
+typedef struct SLKeyMap_List_Type
+{
+ char *name; /* hashed string */
+ SLang_Key_Type *keymap;
+ SLKeymap_Function_Type *functions; /* intrinsic functions */
+}
+SLKeyMap_List_Type;
+
+/* This is arbitrary but I have got to start somewhere */
+#define SLANG_MAX_KEYMAPS 30
+extern SLKeyMap_List_Type SLKeyMap_List[SLANG_MAX_KEYMAPS];
+
+extern char *SLang_process_keystring(char *);
+
+extern int SLkm_define_key (char *, FVOID_STAR, SLKeyMap_List_Type *);
+
+extern int SLang_define_key(char *, char *, SLKeyMap_List_Type *);
+/* Like define_key1 except that p2 is a string that is to be associated with
+ * a function in the functions field of p3. This routine calls define_key1.
+ */
+
+extern int SLkm_define_keysym (char *, unsigned int, SLKeyMap_List_Type *);
+
+extern void SLang_undefine_key(char *, SLKeyMap_List_Type *);
+
+extern SLKeyMap_List_Type *SLang_create_keymap(char *, SLKeyMap_List_Type *);
+/* create and returns a pointer to a new keymap named p1 created by copying
+ * keymap p2. If p2 is NULL, it is up to the calling routine to initialize
+ * the keymap.
+ */
+
+extern char *SLang_make_keystring(unsigned char *);
+
+extern SLang_Key_Type *SLang_do_key(SLKeyMap_List_Type *, int (*)(void));
+/* read a key using keymap p1 with getkey function p2 */
+
+extern
+ FVOID_STAR
+ SLang_find_key_function(char *, SLKeyMap_List_Type *);
+
+extern SLKeyMap_List_Type *SLang_find_keymap(char *);
+
+extern int SLang_Last_Key_Char;
+extern int SLang_Key_TimeOut_Flag;
+
+/*}}}*/
+
+/*{{{ SLang Readline Interface */
+
+typedef struct SLang_Read_Line_Type
+{
+ struct SLang_Read_Line_Type *prev, *next;
+ unsigned char *buf;
+ int buf_len; /* number of chars in the buffer */
+ int num; /* num and misc are application specific*/
+ int misc;
+} SLang_Read_Line_Type;
+
+/* Maximum size of display */
+#define SLRL_DISPLAY_BUFFER_SIZE 256
+
+typedef struct
+{
+ SLang_Read_Line_Type *root, *tail, *last;
+ unsigned char *buf; /* edit buffer */
+ int buf_len; /* sizeof buffer */
+ int point; /* current editing point */
+ int tab; /* tab width */
+ int len; /* current line size */
+
+ /* display variables */
+ int edit_width; /* length of display field */
+ int curs_pos; /* current column */
+ int start_column; /* column offset of display */
+ int dhscroll; /* amount to use for horiz scroll */
+ char *prompt;
+
+ FVOID_STAR last_fun; /* last function executed by rl */
+
+ /* These two contain an image of what is on the display */
+ unsigned char upd_buf1[SLRL_DISPLAY_BUFFER_SIZE];
+ unsigned char upd_buf2[SLRL_DISPLAY_BUFFER_SIZE];
+ unsigned char *old_upd, *new_upd; /* pointers to previous two buffers */
+ int new_upd_len, old_upd_len; /* length of output buffers */
+
+ SLKeyMap_List_Type *keymap;
+
+ /* tty variables */
+ unsigned int flags; /* */
+#define SL_RLINE_NO_ECHO 1
+#define SL_RLINE_USE_ANSI 2
+#define SL_RLINE_BLINK_MATCH 4
+ unsigned int (*getkey)(void); /* getkey function -- required */
+ void (*tt_goto_column)(int);
+ void (*tt_insert)(char);
+ void (*update_hook)(unsigned char *, int, int);
+ /* The update hook is called with a pointer to a buffer p1 that contains
+ * an image of what the update hook is suppoed to produce. The length
+ * of the buffer is p2 and after the update, the cursor is to be placed
+ * in column p3.
+ */
+ /* This function is only called when blinking matches */
+ int (*input_pending)(int);
+ unsigned long reserved[4];
+} SLang_RLine_Info_Type;
+
+extern int SLang_RL_EOF_Char;
+
+extern SLang_Read_Line_Type * SLang_rline_save_line (SLang_RLine_Info_Type *);
+extern int SLang_init_readline (SLang_RLine_Info_Type *);
+extern int SLang_read_line (SLang_RLine_Info_Type *);
+extern int SLang_rline_insert (char *);
+extern void SLrline_redraw (SLang_RLine_Info_Type *);
+extern int SLang_Rline_Quit;
+
+/*}}}*/
+
+/*{{{ Low Level Screen Output Interface */
+
+extern unsigned long SLtt_Num_Chars_Output;
+extern int SLtt_Baud_Rate;
+
+typedef unsigned long SLtt_Char_Type;
+
+#define SLTT_BOLD_MASK 0x01000000UL
+#define SLTT_BLINK_MASK 0x02000000UL
+#define SLTT_ULINE_MASK 0x04000000UL
+#define SLTT_REV_MASK 0x08000000UL
+#define SLTT_ALTC_MASK 0x10000000UL
+
+extern int SLtt_Screen_Rows;
+extern int SLtt_Screen_Cols;
+extern int SLtt_Term_Cannot_Insert;
+extern int SLtt_Term_Cannot_Scroll;
+extern int SLtt_Use_Ansi_Colors;
+extern int SLtt_Ignore_Beep;
+#if defined(REAL_UNIX_SYSTEM)
+extern int SLtt_Force_Keypad_Init;
+extern int SLang_TT_Write_FD;
+#endif
+
+#ifndef IBMPC_SYSTEM
+extern char *SLtt_Graphics_Char_Pairs;
+#endif
+
+#ifndef __GO32__
+#if defined(VMS) || defined(REAL_UNIX_SYSTEM)
+extern int SLtt_Blink_Mode;
+extern int SLtt_Use_Blink_For_ACS;
+extern int SLtt_Newline_Ok;
+extern int SLtt_Has_Alt_Charset;
+extern int SLtt_Has_Status_Line; /* if 0, NO. If > 0, YES, IF -1, ?? */
+# ifndef VMS
+extern int SLtt_Try_Termcap;
+# endif
+#endif
+#endif
+
+#if defined(IBMPC_SYSTEM)
+extern int SLtt_Msdos_Cheap_Video;
+#endif
+
+typedef unsigned short SLsmg_Char_Type;
+#define SLSMG_EXTRACT_CHAR(x) ((x) & 0xFF)
+#define SLSMG_EXTRACT_COLOR(x) (((x)>>8)&0xFF)
+#define SLSMG_BUILD_CHAR(ch,color) (((SLsmg_Char_Type)(unsigned char)(ch))|((color)<<8))
+
+extern int SLtt_flush_output (void);
+extern void SLtt_set_scroll_region(int, int);
+extern void SLtt_reset_scroll_region(void);
+extern void SLtt_reverse_video (int);
+extern void SLtt_bold_video (void);
+extern void SLtt_begin_insert(void);
+extern void SLtt_end_insert(void);
+extern void SLtt_del_eol(void);
+extern void SLtt_goto_rc (int, int);
+extern void SLtt_delete_nlines(int);
+extern void SLtt_delete_char(void);
+extern void SLtt_erase_line(void);
+extern void SLtt_normal_video(void);
+extern void SLtt_cls(void);
+extern void SLtt_beep(void);
+extern void SLtt_reverse_index(int);
+extern void SLtt_smart_puts(SLsmg_Char_Type *, SLsmg_Char_Type *, int, int);
+extern void SLtt_write_string (char *);
+extern void SLtt_putchar(char);
+extern int SLtt_init_video (void);
+extern int SLtt_reset_video (void);
+extern void SLtt_get_terminfo(void);
+extern void SLtt_get_screen_size (void);
+extern int SLtt_set_cursor_visibility (int);
+
+extern int SLtt_set_mouse_mode (int, int);
+
+#if defined(VMS) || defined(REAL_UNIX_SYSTEM)
+extern int SLtt_initialize (char *);
+extern void SLtt_enable_cursor_keys(void);
+extern void SLtt_set_term_vtxxx(int *);
+extern void SLtt_set_color_esc (int, char *);
+extern void SLtt_wide_width(void);
+extern void SLtt_narrow_width(void);
+extern void SLtt_set_alt_char_set (int);
+extern int SLtt_write_to_status_line (char *, int);
+extern void SLtt_disable_status_line (void);
+# ifdef REAL_UNIX_SYSTEM
+/* These are termcap/terminfo routines that assume SLtt_initialize has
+ * been called.
+ */
+extern char *SLtt_tgetstr (char *);
+extern int SLtt_tgetnum (char *);
+extern int SLtt_tgetflag (char *);
+
+/* The following are terminfo-only routines -- these prototypes will change
+ * in V2.x.
+ */
+extern char *SLtt_tigetent (char *);
+extern char *SLtt_tigetstr (char *, char **);
+extern int SLtt_tigetnum (char *, char **);
+# endif
+#endif
+
+extern SLtt_Char_Type SLtt_get_color_object (int);
+extern void SLtt_set_color_object (int, SLtt_Char_Type);
+extern void SLtt_set_color (int, char *, char *, char *);
+extern void SLtt_set_mono (int, char *, SLtt_Char_Type);
+extern void SLtt_add_color_attribute (int, SLtt_Char_Type);
+extern void SLtt_set_color_fgbg (int, SLtt_Char_Type, SLtt_Char_Type);
+
+/*}}}*/
+
+/*{{{ SLang Preprocessor Interface */
+
+typedef struct
+{
+ int this_level;
+ int exec_level;
+ int prev_exec_level;
+ char preprocess_char;
+ char comment_char;
+ unsigned char flags;
+#define SLPREP_BLANK_LINES_OK 1
+#define SLPREP_COMMENT_LINES_OK 2
+}
+SLPreprocess_Type;
+
+extern int SLprep_open_prep (SLPreprocess_Type *);
+extern void SLprep_close_prep (SLPreprocess_Type *);
+extern int SLprep_line_ok (char *, SLPreprocess_Type *);
+ extern int SLdefine_for_ifdef (char *);
+ /* Adds a string to the SLang #ifdef preparsing defines. SLang already
+ defines MSDOS, UNIX, and VMS on the appropriate system. */
+extern int (*SLprep_exists_hook) (char *, char);
+
+/*}}}*/
+
+/*{{{ SLsmg Screen Management Functions */
+
+extern void SLsmg_fill_region (int, int, unsigned int, unsigned int, unsigned char);
+extern void SLsmg_set_char_set (int);
+#ifndef IBMPC_SYSTEM
+extern int SLsmg_Scroll_Hash_Border;
+#endif
+extern int SLsmg_suspend_smg (void);
+extern int SLsmg_resume_smg (void);
+extern void SLsmg_erase_eol (void);
+extern void SLsmg_gotorc (int, int);
+extern void SLsmg_erase_eos (void);
+extern void SLsmg_reverse_video (void);
+extern void SLsmg_set_color (int);
+extern void SLsmg_normal_video (void);
+extern void SLsmg_printf (char *, ...);
+extern void SLsmg_vprintf (char *, va_list);
+extern void SLsmg_write_string (char *);
+extern void SLsmg_write_nstring (char *, unsigned int);
+extern void SLsmg_write_char (char);
+extern void SLsmg_write_nchars (char *, unsigned int);
+extern void SLsmg_write_wrapped_string (char *, int, int, unsigned int, unsigned int, int);
+extern void SLsmg_cls (void);
+extern void SLsmg_refresh (void);
+extern void SLsmg_touch_lines (int, unsigned int);
+extern void SLsmg_touch_screen (void);
+extern int SLsmg_init_smg (void);
+extern int SLsmg_reinit_smg (void);
+extern void SLsmg_reset_smg (void);
+extern SLsmg_Char_Type SLsmg_char_at(void);
+extern void SLsmg_set_screen_start (int *, int *);
+extern void SLsmg_draw_hline (unsigned int);
+extern void SLsmg_draw_vline (int);
+extern void SLsmg_draw_object (int, int, unsigned char);
+extern void SLsmg_draw_box (int, int, unsigned int, unsigned int);
+extern int SLsmg_get_column(void);
+extern int SLsmg_get_row(void);
+extern void SLsmg_forward (int);
+extern void SLsmg_write_color_chars (SLsmg_Char_Type *, unsigned int);
+extern unsigned int SLsmg_read_raw (SLsmg_Char_Type *, unsigned int);
+extern unsigned int SLsmg_write_raw (SLsmg_Char_Type *, unsigned int);
+extern void SLsmg_set_color_in_region (int, int, int, unsigned int, unsigned int);
+extern int SLsmg_Display_Eight_Bit;
+extern int SLsmg_Tab_Width;
+
+#define SLSMG_NEWLINE_IGNORED 0 /* default */
+#define SLSMG_NEWLINE_MOVES 1 /* moves to next line, column 0 */
+#define SLSMG_NEWLINE_SCROLLS 2 /* moves but scrolls at bottom of screen */
+#define SLSMG_NEWLINE_PRINTABLE 3 /* prints as ^J */
+extern int SLsmg_Newline_Behavior;
+
+extern int SLsmg_Backspace_Moves;
+
+#ifdef IBMPC_SYSTEM
+# define SLSMG_HLINE_CHAR 0xC4
+# define SLSMG_VLINE_CHAR 0xB3
+# define SLSMG_ULCORN_CHAR 0xDA
+# define SLSMG_URCORN_CHAR 0xBF
+# define SLSMG_LLCORN_CHAR 0xC0
+# define SLSMG_LRCORN_CHAR 0xD9
+# define SLSMG_RTEE_CHAR 0xB4
+# define SLSMG_LTEE_CHAR 0xC3
+# define SLSMG_UTEE_CHAR 0xC2
+# define SLSMG_DTEE_CHAR 0xC1
+# define SLSMG_PLUS_CHAR 0xC5
+/* There are several to choose from: 0xB0, 0xB1, and 0xB2 */
+# define SLSMG_CKBRD_CHAR 0xB0
+# define SLSMG_DIAMOND_CHAR 0x04
+# define SLSMG_DEGREE_CHAR 0xF8
+# define SLSMG_PLMINUS_CHAR 0xF1
+# define SLSMG_BULLET_CHAR 0xF9
+# define SLSMG_LARROW_CHAR 0x1B
+# define SLSMG_RARROW_CHAR 0x1A
+# define SLSMG_DARROW_CHAR 0x19
+# define SLSMG_UARROW_CHAR 0x18
+# define SLSMG_BOARD_CHAR 0xB2
+# define SLSMG_BLOCK_CHAR 0xDB
+#else
+# if defined(AMIGA)
+# define SLSMG_HLINE_CHAR '-'
+# define SLSMG_VLINE_CHAR '|'
+# define SLSMG_ULCORN_CHAR '+'
+# define SLSMG_URCORN_CHAR '+'
+# define SLSMG_LLCORN_CHAR '+'
+# define SLSMG_LRCORN_CHAR '+'
+# define SLSMG_CKBRD_CHAR '#'
+# define SLSMG_RTEE_CHAR '+'
+# define SLSMG_LTEE_CHAR '+'
+# define SLSMG_UTEE_CHAR '+'
+# define SLSMG_DTEE_CHAR '+'
+# define SLSMG_PLUS_CHAR '+'
+# define SLSMG_DIAMOND_CHAR '+'
+# define SLSMG_DEGREE_CHAR '\\'
+# define SLSMG_PLMINUS_CHAR '#'
+# define SLSMG_BULLET_CHAR 'o'
+# define SLSMG_LARROW_CHAR '<'
+# define SLSMG_RARROW_CHAR '>'
+# define SLSMG_DARROW_CHAR 'v'
+# define SLSMG_UARROW_CHAR '^'
+# define SLSMG_BOARD_CHAR '#'
+# define SLSMG_BLOCK_CHAR '#'
+# else
+# define SLSMG_HLINE_CHAR 'q'
+# define SLSMG_VLINE_CHAR 'x'
+# define SLSMG_ULCORN_CHAR 'l'
+# define SLSMG_URCORN_CHAR 'k'
+# define SLSMG_LLCORN_CHAR 'm'
+# define SLSMG_LRCORN_CHAR 'j'
+# define SLSMG_CKBRD_CHAR 'a'
+# define SLSMG_RTEE_CHAR 'u'
+# define SLSMG_LTEE_CHAR 't'
+# define SLSMG_UTEE_CHAR 'w'
+# define SLSMG_DTEE_CHAR 'v'
+# define SLSMG_PLUS_CHAR 'n'
+# define SLSMG_DIAMOND_CHAR '`'
+# define SLSMG_DEGREE_CHAR 'f'
+# define SLSMG_PLMINUS_CHAR 'g'
+# define SLSMG_BULLET_CHAR '~'
+# define SLSMG_LARROW_CHAR ','
+# define SLSMG_RARROW_CHAR '+'
+# define SLSMG_DARROW_CHAR '.'
+# define SLSMG_UARROW_CHAR '-'
+# define SLSMG_BOARD_CHAR 'h'
+# define SLSMG_BLOCK_CHAR '0'
+# endif /* AMIGA */
+#endif /* IBMPC_SYSTEM */
+
+#ifndef IBMPC_SYSTEM
+# define SLSMG_COLOR_BLACK 0x000000
+# define SLSMG_COLOR_RED 0x000001
+# define SLSMG_COLOR_GREEN 0x000002
+# define SLSMG_COLOR_BROWN 0x000003
+# define SLSMG_COLOR_BLUE 0x000004
+# define SLSMG_COLOR_MAGENTA 0x000005
+# define SLSMG_COLOR_CYAN 0x000006
+# define SLSMG_COLOR_LGRAY 0x000007
+# define SLSMG_COLOR_GRAY 0x000008
+# define SLSMG_COLOR_BRIGHT_RED 0x000009
+# define SLSMG_COLOR_BRIGHT_GREEN 0x00000A
+# define SLSMG_COLOR_BRIGHT_BROWN 0x00000B
+# define SLSMG_COLOR_BRIGHT_BLUE 0x00000C
+# define SLSMG_COLOR_BRIGHT_CYAN 0x00000D
+# define SLSMG_COLOR_BRIGHT_MAGENTA 0x00000E
+# define SLSMG_COLOR_BRIGHT_WHITE 0x00000F
+#endif
+
+typedef struct
+{
+ void (*tt_normal_video)(void);
+ void (*tt_set_scroll_region)(int, int);
+ void (*tt_goto_rc)(int, int);
+ void (*tt_reverse_index)(int);
+ void (*tt_reset_scroll_region)(void);
+ void (*tt_delete_nlines)(int);
+ void (*tt_cls) (void);
+ void (*tt_del_eol) (void);
+ void (*tt_smart_puts) (SLsmg_Char_Type *, SLsmg_Char_Type *, int, int);
+ int (*tt_flush_output) (void);
+ int (*tt_reset_video) (void);
+ int (*tt_init_video) (void);
+
+ int *tt_screen_rows;
+ int *tt_screen_cols;
+
+ int *tt_term_cannot_scroll;
+ int *tt_has_alt_charset;
+ int *tt_use_blink_for_acs;
+ char **tt_graphic_char_pairs;
+
+ long reserved[4];
+}
+SLsmg_Term_Type;
+extern void SLsmg_set_terminal_info (SLsmg_Term_Type *);
+
+/*}}}*/
+
+/*{{{ SLang Keypad Interface */
+
+#define SL_KEY_ERR 0xFFFF
+
+#define SL_KEY_UP 0x101
+#define SL_KEY_DOWN 0x102
+#define SL_KEY_LEFT 0x103
+#define SL_KEY_RIGHT 0x104
+#define SL_KEY_PPAGE 0x105
+#define SL_KEY_NPAGE 0x106
+#define SL_KEY_HOME 0x107
+#define SL_KEY_END 0x108
+#define SL_KEY_A1 0x109
+#define SL_KEY_A3 0x10A
+#define SL_KEY_B2 0x10B
+#define SL_KEY_C1 0x10C
+#define SL_KEY_C3 0x10D
+#define SL_KEY_REDO 0x10E
+#define SL_KEY_UNDO 0x10F
+#define SL_KEY_BACKSPACE 0x110
+#define SL_KEY_ENTER 0x111
+#define SL_KEY_IC 0x112
+#define SL_KEY_DELETE 0x113
+
+#define SL_KEY_F0 0x200
+#define SL_KEY_F(X) (SL_KEY_F0 + X)
+
+/* I do not intend to use keysymps > 0x1000. Applications can use those. */
+/* Returns 0 upon success or -1 upon error. */
+extern int SLkp_define_keysym (char *, unsigned int);
+
+/* This function must be called AFTER SLtt_get_terminfo and not before. */
+extern int SLkp_init (void);
+
+/* This function uses SLang_getkey and assumes that what ever initialization
+ * is required for SLang_getkey has been performed.
+ */
+extern int SLkp_getkey (void);
+
+/*}}}*/
+
+/*{{{ SLang Scroll Interface */
+
+typedef struct _SLscroll_Type
+{
+ struct _SLscroll_Type *next;
+ struct _SLscroll_Type *prev;
+ unsigned int flags;
+}
+SLscroll_Type;
+
+typedef struct
+{
+ unsigned int flags;
+ SLscroll_Type *top_window_line; /* list element at top of window */
+ SLscroll_Type *bot_window_line; /* list element at bottom of window */
+ SLscroll_Type *current_line; /* current list element */
+ SLscroll_Type *lines; /* first list element */
+ unsigned int nrows; /* number of rows in window */
+ unsigned int hidden_mask; /* applied to flags in SLscroll_Type */
+ unsigned int line_num; /* current line number (visible) */
+ unsigned int num_lines; /* total number of lines (visible) */
+ unsigned int window_row; /* row of current_line in window */
+ unsigned int border; /* number of rows that form scroll border */
+ int cannot_scroll; /* should window scroll or recenter */
+}
+SLscroll_Window_Type;
+
+extern int SLscroll_find_top (SLscroll_Window_Type *);
+extern int SLscroll_find_line_num (SLscroll_Window_Type *);
+extern unsigned int SLscroll_next_n (SLscroll_Window_Type *, unsigned int);
+extern unsigned int SLscroll_prev_n (SLscroll_Window_Type *, unsigned int);
+extern int SLscroll_pageup (SLscroll_Window_Type *);
+extern int SLscroll_pagedown (SLscroll_Window_Type *);
+
+/*}}}*/
+
+/*{{{ Signal Routines */
+
+typedef void SLSig_Fun_Type (int);
+extern SLSig_Fun_Type *SLsignal (int, SLSig_Fun_Type *);
+extern SLSig_Fun_Type *SLsignal_intr (int, SLSig_Fun_Type *);
+extern int SLsig_block_signals (void);
+extern int SLsig_unblock_signals (void);
+extern int SLsystem (char *);
+
+extern char *SLerrno_strerror (int);
+extern int SLerrno_set_errno (int);
+
+/*}}}*/
+
+/*{{{ Interpreter Macro Definitions */
+
+/* The definitions here are for objects that may be on the run-time stack.
+ * They are actually sub_types of literal and data main_types. The actual
+ * numbers are historical.
+ */
+#define SLANG_UNDEFINED_TYPE 0x00 /* MUST be 0 */
+#define SLANG_VOID_TYPE 0x01 /* also matches ANY type */
+#define SLANG_INT_TYPE 0x02
+#define SLANG_DOUBLE_TYPE 0x03
+#define SLANG_CHAR_TYPE 0x04
+#define SLANG_INTP_TYPE 0x05
+/* An object of SLANG_INTP_TYPE should never really occur on the stack. Rather,
+ * the integer to which it refers will be there instead. It is defined here
+ * because it is a valid type for MAKE_VARIABLE.
+ */
+#define SLANG_REF_TYPE 0x06
+/* SLANG_REF_TYPE refers to an object on the stack that is a pointer (reference)
+ * to some other object.
+ */
+#define SLANG_COMPLEX_TYPE 0x07
+#define SLANG_NULL_TYPE 0x08
+#define SLANG_UCHAR_TYPE 0x09
+#define SLANG_SHORT_TYPE 0x0A
+#define SLANG_USHORT_TYPE 0x0B
+#define SLANG_UINT_TYPE 0x0C
+#define SLANG_LONG_TYPE 0x0D
+#define SLANG_ULONG_TYPE 0x0E
+#define SLANG_STRING_TYPE 0x0F
+#define SLANG_FLOAT_TYPE 0x10
+#define SLANG_STRUCT_TYPE 0x11
+#define SLANG_ISTRUCT_TYPE 0x12
+#define SLANG_ARRAY_TYPE 0x20
+#define SLANG_DATATYPE_TYPE 0x21
+#define SLANG_FILE_PTR_TYPE 0x22
+#define SLANG_ASSOC_TYPE 0x23
+#define SLANG_ANY_TYPE 0x24
+#define SLANG_BSTRING_TYPE 0x25
+#define SLANG_FILE_FD_TYPE 0x26
+
+/* Compatibility */
+#ifdef FLOAT_TYPE
+# undef FLOAT_TYPE
+#endif
+#define VOID_TYPE SLANG_VOID_TYPE
+#define INT_TYPE SLANG_INT_TYPE
+#define INTP_TYPE SLANG_INTP_TYPE
+#define FLOAT_TYPE SLANG_DOUBLE_TYPE
+#define ARRAY_TYPE SLANG_ARRAY_TYPE
+#define CHAR_TYPE SLANG_CHAR_TYPE
+#define STRING_TYPE SLANG_STRING_TYPE
+
+/* I am reserving values greater than or equal to 128 for user applications.
+ * The first 127 are reserved for S-Lang.
+ */
+
+/* Binary and Unary Subtypes */
+/* Since the application can define new types and can overload the binary
+ * and unary operators, these definitions must be present in this file.
+ * The current implementation assumes both unary and binary are distinct.
+ */
+#define SLANG_PLUS 0x01
+#define SLANG_MINUS 0x02
+#define SLANG_TIMES 0x03
+#define SLANG_DIVIDE 0x04
+#define SLANG_EQ 0x05
+#define SLANG_NE 0x06
+#define SLANG_GT 0x07
+#define SLANG_GE 0x08
+#define SLANG_LT 0x09
+#define SLANG_LE 0x0A
+#define SLANG_POW 0x0B
+#define SLANG_OR 0x0C
+#define SLANG_AND 0x0D
+#define SLANG_BAND 0x0E
+#define SLANG_BOR 0x0F
+#define SLANG_BXOR 0x10
+#define SLANG_SHL 0x11
+#define SLANG_SHR 0x12
+#define SLANG_MOD 0x13
+
+/* UNARY subtypes (may be overloaded) */
+#define SLANG_PLUSPLUS 0x20
+#define SLANG_MINUSMINUS 0x21
+#define SLANG_ABS 0x22
+#define SLANG_SIGN 0x23
+#define SLANG_SQR 0x24
+#define SLANG_MUL2 0x25
+#define SLANG_CHS 0x26
+#define SLANG_NOT 0x27
+#define SLANG_BNOT 0x28
+
+extern char *SLang_Error_Message;
+
+int SLadd_intrinsic_variable (char *, VOID_STAR, unsigned char, int);
+int SLadd_intrinsic_function (char *, FVOID_STAR, unsigned char, unsigned int,...);
+
+int SLns_add_intrinsic_variable (SLang_NameSpace_Type *, char *, VOID_STAR, unsigned char, int);
+int SLns_add_intrinsic_function (SLang_NameSpace_Type *, char *, FVOID_STAR, unsigned char, unsigned int,...);
+
+extern void SLadd_at_handler (long *, char *);
+
+#define MAKE_INTRINSIC_N(n,f,out,in,a1,a2,a3,a4,a5,a6,a7) \
+ {(n), NULL, SLANG_INTRINSIC, (FVOID_STAR) (f), \
+ {a1,a2,a3,a4,a5,a6,a7}, (in), (out)}
+
+#define MAKE_INTRINSIC_7(n,f,out,a1,a2,a3,a4,a5,a6,a7) \
+ MAKE_INTRINSIC_N(n,f,out,7,a1,a2,a3,a4,a5,a6,a7)
+#define MAKE_INTRINSIC_6(n,f,out,a1,a2,a3,a4,a5,a6) \
+ MAKE_INTRINSIC_N(n,f,out,6,a1,a2,a3,a4,a5,a6,0)
+#define MAKE_INTRINSIC_5(n,f,out,a1,a2,a3,a4,a5) \
+ MAKE_INTRINSIC_N(n,f,out,5,a1,a2,a3,a4,a5,0,0)
+#define MAKE_INTRINSIC_4(n,f,out,a1,a2,a3,a4) \
+ MAKE_INTRINSIC_N(n,f,out,4,a1,a2,a3,a4,0,0,0)
+#define MAKE_INTRINSIC_3(n,f,out,a1,a2,a3) \
+ MAKE_INTRINSIC_N(n,f,out,3,a1,a2,a3,0,0,0,0)
+#define MAKE_INTRINSIC_2(n,f,out,a1,a2) \
+ MAKE_INTRINSIC_N(n,f,out,2,a1,a2,0,0,0,0,0)
+#define MAKE_INTRINSIC_1(n,f,out,a1) \
+ MAKE_INTRINSIC_N(n,f,out,1,a1,0,0,0,0,0,0)
+#define MAKE_INTRINSIC_0(n,f,out) \
+ MAKE_INTRINSIC_N(n,f,out,0,0,0,0,0,0,0,0)
+
+#define MAKE_INTRINSIC_S(n,f,r) \
+ MAKE_INTRINSIC_1(n,f,r,SLANG_STRING_TYPE)
+#define MAKE_INTRINSIC_I(n,f,r) \
+ MAKE_INTRINSIC_1(n,f,r,SLANG_INT_TYPE)
+
+#define MAKE_INTRINSIC_SS(n,f,r) \
+ MAKE_INTRINSIC_2(n,f,r,SLANG_STRING_TYPE,SLANG_STRING_TYPE)
+#define MAKE_INTRINSIC_SI(n,f,r) \
+ MAKE_INTRINSIC_2(n,f,r,SLANG_STRING_TYPE,SLANG_INT_TYPE)
+#define MAKE_INTRINSIC_IS(n,f,r) \
+ MAKE_INTRINSIC_2(n,f,r,SLANG_INT_TYPE,SLANG_STRING_TYPE)
+#define MAKE_INTRINSIC_II(n,f,r) \
+ MAKE_INTRINSIC_2(n,f,r,SLANG_INT_TYPE,SLANG_INT_TYPE)
+
+#define MAKE_INTRINSIC_SSS(n,f,r) \
+ MAKE_INTRINSIC_3(n,f,r,SLANG_STRING_TYPE,SLANG_STRING_TYPE,SLANG_STRING_TYPE)
+#define MAKE_INTRINSIC_SSI(n,f,r) \
+ MAKE_INTRINSIC_3(n,f,r,SLANG_STRING_TYPE,SLANG_STRING_TYPE,SLANG_INT_TYPE)
+#define MAKE_INTRINSIC_SIS(n,f,r) \
+ MAKE_INTRINSIC_3(n,f,r,SLANG_STRING_TYPE,SLANG_INT_TYPE,SLANG_STRING_TYPE)
+#define MAKE_INTRINSIC_SII(n,f,r) \
+ MAKE_INTRINSIC_3(n,f,r,SLANG_STRING_TYPE,SLANG_INT_TYPE,SLANG_INT_TYPE)
+#define MAKE_INTRINSIC_ISS(n,f,r) \
+ MAKE_INTRINSIC_3(n,f,r,SLANG_INT_TYPE,SLANG_STRING_TYPE,SLANG_STRING_TYPE)
+#define MAKE_INTRINSIC_ISI(n,f,r) \
+ MAKE_INTRINSIC_3(n,f,r,SLANG_INT_TYPE,SLANG_STRING_TYPE,SLANG_INT_TYPE)
+#define MAKE_INTRINSIC_IIS(n,f,r) \
+ MAKE_INTRINSIC_3(n,f,r,SLANG_INT_TYPE,SLANG_INT_TYPE,SLANG_STRING_TYPE)
+#define MAKE_INTRINSIC_III(n,f,r) \
+ MAKE_INTRINSIC_3(n,f,r,SLANG_INT_TYPE,SLANG_INT_TYPE,SLANG_INT_TYPE)
+
+#define MAKE_INTRINSIC(n, f, out, in) \
+ MAKE_INTRINSIC_N(n,f,out,in,0,0,0,0,0,0,0)
+
+#define MAKE_VARIABLE(n, v, t, r) \
+ {n, NULL, SLANG_IVARIABLE + (r), (VOID_STAR)(v), (t)}
+
+#define MAKE_APP_UNARY(n,op) \
+ {(n), NULL, SLANG_APP_UNARY, (op)}
+
+#define MAKE_MATH_UNARY(n,op) \
+ {(n), NULL, SLANG_MATH_UNARY, (op)}
+
+#define MAKE_ICONSTANT(n,val) \
+ {(n),NULL, SLANG_ICONSTANT, (val)}
+
+#define MAKE_DCONSTANT(n,val) \
+ {(n),NULL, SLANG_DCONSTANT, (val)}
+
+#ifndef offsetof
+# define offsetof(T,F) ((unsigned int)((char *)&((T *)0L)->F - (char *)0L))
+#endif
+#define MAKE_ISTRUCT_FIELD(s,f,n,t,r) {(n), offsetof(s,f), (t), (r)}
+
+#define SLANG_END_TABLE {NULL}
+#define SLANG_END_INTRIN_FUN_TABLE MAKE_INTRINSIC_0(NULL,NULL,0)
+#define SLANG_END_DCONST_TABLE MAKE_DCONSTANT(NULL,0)
+#define SLANG_END_MATH_UNARY_TABLE MAKE_MATH_UNARY(NULL,0)
+#define SLANG_END_INTRIN_VAR_TABLE MAKE_VARIABLE(NULL,NULL,0,0)
+#define SLANG_END_ICONST_TABLE MAKE_ICONSTANT(NULL,0)
+#define SLANG_END_ISTRUCT_TABLE {NULL, 0, 0, 0}
+
+
+
+/*}}}*/
+
+/*{{{ Upper/Lowercase Functions */
+
+extern void SLang_define_case(int *, int *);
+extern void SLang_init_case_tables (void);
+
+extern unsigned char _SLChg_UCase_Lut[256];
+extern unsigned char _SLChg_LCase_Lut[256];
+#define UPPER_CASE(x) (_SLChg_UCase_Lut[(unsigned char) (x)])
+#define LOWER_CASE(x) (_SLChg_LCase_Lut[(unsigned char) (x)])
+#define CHANGE_CASE(x) (((x) == _SLChg_LCase_Lut[(unsigned char) (x)]) ?\
+ _SLChg_UCase_Lut[(unsigned char) (x)] : _SLChg_LCase_Lut[(unsigned char) (x)])
+
+/*}}}*/
+
+/*{{{ Regular Expression Interface */
+
+typedef struct
+{
+ /* These must be set by calling routine. */
+ unsigned char *pat; /* regular expression pattern */
+ unsigned char *buf; /* buffer for compiled regexp */
+ unsigned int buf_len; /* length of buffer */
+ int case_sensitive; /* 1 if match is case sensitive */
+
+ /* The rest are set by SLang_regexp_compile */
+
+ int must_match; /* 1 if line must contain substring */
+ int must_match_bol; /* true if it must match beginning of line */
+ unsigned char must_match_str[16]; /* 15 char null term substring */
+ int osearch; /* 1 if ordinary search suffices */
+ unsigned int min_length; /* minimum length the match must be */
+ int beg_matches[10]; /* offset of start of \( */
+ unsigned int end_matches[10]; /* length of nth submatch
+ * Note that the entire match corresponds
+ * to \0
+ */
+ int offset; /* offset to be added to beg_matches */
+ int reserved[10];
+} SLRegexp_Type;
+
+extern unsigned char *SLang_regexp_match(unsigned char *,
+ unsigned int,
+ SLRegexp_Type *);
+
+/* Returns 0 upon success. If failure, the offset into the
+ * pattern is returned (start = 1).
+ */
+extern int SLang_regexp_compile (SLRegexp_Type *);
+extern char *SLregexp_quote_string (char *, char *, unsigned int);
+
+/*}}}*/
+
+/*{{{ SLang Command Interface */
+
+struct _SLcmd_Cmd_Type; /* Pre-declaration is needed below */
+typedef struct
+{
+ struct _SLcmd_Cmd_Type *table;
+ int argc;
+ /* Version 2.0 needs to use a union!! */
+ char **string_args;
+ int *int_args;
+ double *double_args;
+ unsigned char *arg_type;
+ unsigned long reserved[4];
+} SLcmd_Cmd_Table_Type;
+
+typedef struct _SLcmd_Cmd_Type
+{
+ int (*cmdfun)(int, SLcmd_Cmd_Table_Type *);
+ char *cmd;
+ char *arg_type;
+} SLcmd_Cmd_Type;
+
+extern int SLcmd_execute_string (char *, SLcmd_Cmd_Table_Type *);
+
+/*}}}*/
+
+/*{{{ SLang Search Interface */
+
+typedef struct
+{
+ int cs; /* case sensitive */
+ unsigned char key[256];
+ int ind[256];
+ int key_len;
+ int dir;
+} SLsearch_Type;
+
+extern int SLsearch_init (char *, int, int, SLsearch_Type *);
+/* This routine must first be called before any search can take place.
+ * The second parameter specifies the direction of the search: greater than
+ * zero for a forwrd search and less than zero for a backward search. The
+ * third parameter specifies whether the search is case sensitive or not.
+ * The last parameter is a pointer to a structure that is filled by this
+ * function and it is this structure that must be passed to SLsearch.
+ */
+
+extern unsigned char *SLsearch (unsigned char *, unsigned char *, SLsearch_Type *);
+/* To use this routine, you must first call 'SLsearch_init'. Then the first
+ * two parameters p1 and p2 serve to define the region over which the search
+ * is to take place. The third parameter is the structure that was previously
+ * initialized by SLsearch_init.
+ *
+ * The routine returns a pointer to the match if found otherwise it returns
+ * NULL.
+ */
+
+/*}}}*/
+
+/*{{{ SLang Pathname Interface */
+
+/* These function return pointers to the original space */
+extern char *SLpath_basename (char *);
+extern char *SLpath_extname (char *);
+extern int SLpath_is_absolute_path (char *);
+
+/* These return malloced strings--- NOT slstrings */
+extern char *SLpath_dircat (char *, char *);
+extern char *SLpath_find_file_in_path (char *, char *);
+extern char *SLpath_dirname (char *);
+extern int SLpath_file_exists (char *);
+extern char *SLpath_pathname_sans_extname (char *);
+
+/*}}}*/
+
+extern int SLang_set_module_load_path (char *);
+
+#define SLANG_MODULE(name) \
+ extern int init_##name##_module_ns (char *); \
+ extern void deinit_##name##_module (void)
+
+#if 0
+{
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DAVIS_SLANG_H_ */
diff --git a/mdk-stage1/slang/slarith.c b/mdk-stage1/slang/slarith.c
new file mode 100644
index 000000000..07ad68687
--- /dev/null
+++ b/mdk-stage1/slang/slarith.c
@@ -0,0 +1,1656 @@
+
+/* Copyright (c) 1998, 1999, 2001 John E. Davis
+ * This file is part of the S-Lang library.
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Perl Artistic License.
+ */
+
+#include "slinclud.h"
+
+#include <math.h>
+
+#ifdef HAVE_LOCALE_H
+# include <locale.h>
+#endif
+
+#include "slang.h"
+#include "_slang.h"
+
+/*
+ * This file defines binary and unary operations on all integer types.
+ * Supported types include:
+ *
+ * SLANG_CHAR_TYPE (char)
+ * SLANG_SHORT_TYPE (short)
+ * SLANG_INT_TYPE (int)
+ * SLANG_LONG_TYPE (long)
+ * SLANG_FLOAT_TYPE (float)
+ * SLANG_DOUBLE_TYPE (double)
+ *
+ * as well as unsigned types. The result-type of an arithmentic operation
+ * will depend upon the data types involved. I am going to distinguish
+ * between the boolean operations such as `and' and `or' from the arithmetic
+ * operations such as `plus'. Since the result of a boolean operation is
+ * either 1 or 0, a boolean result will be represented by SLANG_CHAR_TYPE.
+ * Ordinarily I would use an integer but for arrays it makes more sense to
+ * use a character data type.
+ *
+ * So, the following will be assumed (`+' is any arithmetic operator)
+ *
+ * char + char = int
+ * char|short + short = int
+ * char|short|int + int = int
+ * char|short|int|long + long = long
+ * char|short|int|long|float + float = float
+ * char|short|int|long|float|double + double = double
+ *
+ * In the actual implementation, a brute force approach is avoided. Such
+ * an approach would mean defining different functions for all possible
+ * combinations of types. Including the unsigned types, and not including
+ * the complex number type, there are 10 arithmetic types and 10*10=100
+ * different combinations of types. Clearly this would be too much.
+ *
+ * One approach would be to define binary functions only between operands of
+ * the same type and then convert types as appropriate. This would require
+ * just 6 such functions (int, uint, long, ulong, float, double).
+ * However, many conversion functions are going to be required, particularly
+ * since we are going to allow typecasting from one arithmetic to another.
+ * Since the bit pattern of signed and unsigned types are the same, and only
+ * the interpretation differs, there will be no functions to convert between
+ * signed and unsigned forms of a given type.
+ */
+
+#define MAX_ARITHMETIC_TYPES 10
+
+unsigned char _SLarith_Is_Arith_Type [256];
+
+unsigned char _SLarith_Arith_Types[] =
+{
+ SLANG_CHAR_TYPE,
+ SLANG_UCHAR_TYPE,
+ SLANG_SHORT_TYPE,
+ SLANG_USHORT_TYPE,
+ SLANG_INT_TYPE,
+ SLANG_UINT_TYPE,
+ SLANG_LONG_TYPE,
+ SLANG_ULONG_TYPE,
+ SLANG_FLOAT_TYPE,
+ SLANG_DOUBLE_TYPE,
+ 0
+};
+
+/* Here are a bunch of functions to convert from one type to another. To
+ * facilitate the process, a macros will be used.
+ */
+
+#define DEFUN_1(f,from_type,to_type) \
+static void f (to_type *y, from_type *x, unsigned int n) \
+{ \
+ unsigned int i; \
+ for (i = 0; i < n; i++) y[i] = (to_type) x[i]; \
+}
+
+#define DEFUN_2(f,from_type,to_type,copy_fun) \
+static VOID_STAR f (VOID_STAR xp, unsigned int n) \
+{ \
+ from_type *x; \
+ to_type *y; \
+ x = (from_type *) xp; \
+ if (NULL == (y = (to_type *) SLmalloc (sizeof (to_type) * n))) return NULL; \
+ copy_fun (y, x, n); \
+ return (VOID_STAR) y; \
+}
+typedef VOID_STAR (*Convert_Fun_Type)(VOID_STAR, unsigned int);
+
+DEFUN_1(copy_char_to_char,char,char)
+#if SIZEOF_INT != SIZEOF_SHORT
+DEFUN_1(copy_char_to_short,char,short)
+DEFUN_1(copy_char_to_ushort,char,unsigned short)
+#else
+# define copy_char_to_short copy_char_to_int
+# define copy_char_to_ushort copy_char_to_uint
+#endif
+DEFUN_1(copy_char_to_int,char,int)
+DEFUN_1(copy_char_to_uint,char,unsigned int)
+#if SIZEOF_INT != SIZEOF_LONG
+DEFUN_1(copy_char_to_long,char,long)
+DEFUN_1(copy_char_to_ulong,char,unsigned long)
+#else
+# define copy_char_to_long copy_char_to_int
+# define copy_char_to_ulong copy_char_to_uint
+#endif
+DEFUN_1(copy_char_to_float,char,float)
+DEFUN_1(copy_char_to_double,char,double)
+
+#if SIZEOF_INT != SIZEOF_SHORT
+DEFUN_1(copy_uchar_to_short,unsigned char,short)
+DEFUN_1(copy_uchar_to_ushort,unsigned char,unsigned short)
+#else
+# define copy_uchar_to_short copy_uchar_to_int
+# define copy_uchar_to_ushort copy_uchar_to_uint
+#endif
+DEFUN_1(copy_uchar_to_int,unsigned char,int)
+DEFUN_1(copy_uchar_to_uint,unsigned char,unsigned int)
+#if SIZEOF_INT != SIZEOF_LONG
+DEFUN_1(copy_uchar_to_long,unsigned char,long)
+DEFUN_1(copy_uchar_to_ulong,unsigned char,unsigned long)
+#else
+# define copy_uchar_to_long copy_uchar_to_int
+# define copy_uchar_to_ulong copy_uchar_to_uint
+#endif
+DEFUN_1(copy_uchar_to_float,unsigned char,float)
+DEFUN_1(copy_uchar_to_double,unsigned char,double)
+
+#if SIZEOF_INT != SIZEOF_SHORT
+DEFUN_1(copy_short_to_char,short,char)
+DEFUN_1(copy_short_to_uchar,short,unsigned char)
+DEFUN_1(copy_short_to_short,short,short)
+DEFUN_1(copy_short_to_int,short,int)
+DEFUN_1(copy_short_to_uint,short,unsigned int)
+DEFUN_1(copy_short_to_long,short,long)
+DEFUN_1(copy_short_to_ulong,short,unsigned long)
+DEFUN_1(copy_short_to_float,short,float)
+DEFUN_1(copy_short_to_double,short,double)
+DEFUN_1(copy_ushort_to_char,unsigned short,char)
+DEFUN_1(copy_ushort_to_uchar,unsigned short,unsigned char)
+DEFUN_1(copy_ushort_to_int,unsigned short,int)
+DEFUN_1(copy_ushort_to_uint,unsigned short,unsigned int)
+DEFUN_1(copy_ushort_to_long,unsigned short,long)
+DEFUN_1(copy_ushort_to_ulong,unsigned short,unsigned long)
+DEFUN_1(copy_ushort_to_float,unsigned short,float)
+DEFUN_1(copy_ushort_to_double,unsigned short,double)
+#else
+# define copy_short_to_char copy_int_to_char
+# define copy_short_to_uchar copy_int_to_uchar
+# define copy_short_to_short copy_int_to_int
+# define copy_short_to_int copy_int_to_int
+# define copy_short_to_uint copy_int_to_int
+# define copy_short_to_long copy_int_to_long
+# define copy_short_to_ulong copy_int_to_ulong
+# define copy_short_to_float copy_int_to_float
+# define copy_short_to_double copy_int_to_double
+# define copy_ushort_to_char copy_uint_to_char
+# define copy_ushort_to_uchar copy_uint_to_uchar
+# define copy_ushort_to_int copy_int_to_int
+# define copy_ushort_to_uint copy_int_to_int
+# define copy_ushort_to_long copy_uint_to_long
+# define copy_ushort_to_ulong copy_uint_to_ulong
+# define copy_ushort_to_float copy_uint_to_float
+# define copy_ushort_to_double copy_uint_to_double
+#endif
+
+DEFUN_1(copy_int_to_char,int,char)
+DEFUN_1(copy_int_to_uchar,int,unsigned char)
+DEFUN_1(copy_uint_to_char,unsigned int,char)
+DEFUN_1(copy_uint_to_uchar,unsigned int,unsigned char)
+#if SIZEOF_INT != SIZEOF_SHORT
+DEFUN_1(copy_int_to_short,int,short)
+DEFUN_1(copy_int_to_ushort,int,unsigned short)
+DEFUN_1(copy_uint_to_short,unsigned int,short)
+DEFUN_1(copy_uint_to_ushort,unsigned int,unsigned short)
+#else
+# define copy_int_to_short copy_int_to_int
+# define copy_int_to_ushort copy_int_to_int
+# define copy_uint_to_short copy_int_to_int
+# define copy_uint_to_ushort copy_int_to_int
+#endif
+DEFUN_1(copy_int_to_int,int,int)
+#if SIZEOF_INT != SIZEOF_LONG
+DEFUN_1(copy_int_to_long,int,long)
+DEFUN_1(copy_int_to_ulong,int,unsigned long)
+DEFUN_1(copy_uint_to_long,unsigned int,long)
+DEFUN_1(copy_uint_to_ulong,unsigned int,unsigned long)
+#else
+# define copy_int_to_long copy_int_to_int
+# define copy_int_to_ulong copy_int_to_int
+# define copy_uint_to_long copy_int_to_int
+# define copy_uint_to_ulong copy_int_to_int
+#endif
+DEFUN_1(copy_int_to_float,int,float)
+DEFUN_1(copy_int_to_double,int,double)
+DEFUN_1(copy_uint_to_float,unsigned int,float)
+DEFUN_1(copy_uint_to_double,unsigned int,double)
+
+#if SIZEOF_INT != SIZEOF_LONG
+DEFUN_1(copy_long_to_char,long,char)
+DEFUN_1(copy_long_to_uchar,long,unsigned char)
+DEFUN_1(copy_long_to_short,long,short)
+DEFUN_1(copy_long_to_ushort,long,unsigned short)
+DEFUN_1(copy_long_to_int,long,int)
+DEFUN_1(copy_long_to_uint,long,unsigned int)
+DEFUN_1(copy_long_to_long,long,long)
+DEFUN_1(copy_long_to_float,long,float)
+DEFUN_1(copy_long_to_double,long,double)
+DEFUN_1(copy_ulong_to_char,unsigned long,char)
+DEFUN_1(copy_ulong_to_uchar,unsigned long,unsigned char)
+DEFUN_1(copy_ulong_to_short,unsigned long,short)
+DEFUN_1(copy_ulong_to_ushort,unsigned long,unsigned short)
+DEFUN_1(copy_ulong_to_int,unsigned long,int)
+DEFUN_1(copy_ulong_to_uint,unsigned long,unsigned int)
+DEFUN_1(copy_ulong_to_float,unsigned long,float)
+DEFUN_1(copy_ulong_to_double,unsigned long,double)
+#else
+#define copy_long_to_char copy_int_to_char
+#define copy_long_to_uchar copy_int_to_uchar
+#define copy_long_to_short copy_int_to_short
+#define copy_long_to_ushort copy_int_to_ushort
+#define copy_long_to_int copy_int_to_int
+#define copy_long_to_uint copy_int_to_int
+#define copy_long_to_long copy_int_to_int
+#define copy_long_to_float copy_int_to_float
+#define copy_long_to_double copy_int_to_double
+#define copy_ulong_to_char copy_uint_to_char
+#define copy_ulong_to_uchar copy_uint_to_uchar
+#define copy_ulong_to_short copy_uint_to_short
+#define copy_ulong_to_ushort copy_uint_to_ushort
+#define copy_ulong_to_int copy_int_to_int
+#define copy_ulong_to_uint copy_int_to_int
+#define copy_ulong_to_float copy_uint_to_float
+#define copy_ulong_to_double copy_uint_to_double
+#endif
+
+DEFUN_1(copy_float_to_char,float,char)
+DEFUN_1(copy_float_to_uchar,float,unsigned char)
+#if SIZEOF_INT != SIZEOF_SHORT
+DEFUN_1(copy_float_to_short,float,short)
+DEFUN_1(copy_float_to_ushort,float,unsigned short)
+#else
+# define copy_float_to_short copy_float_to_int
+# define copy_float_to_ushort copy_float_to_uint
+#endif
+DEFUN_1(copy_float_to_int,float,int)
+DEFUN_1(copy_float_to_uint,float,unsigned int)
+#if SIZEOF_INT != SIZEOF_LONG
+DEFUN_1(copy_float_to_long,float,long)
+DEFUN_1(copy_float_to_ulong,float,unsigned long)
+#else
+# define copy_float_to_long copy_float_to_int
+# define copy_float_to_ulong copy_float_to_uint
+#endif
+DEFUN_1(copy_float_to_float,float,float)
+DEFUN_1(copy_float_to_double,float,double)
+
+DEFUN_1(copy_double_to_char,double,char)
+DEFUN_1(copy_double_to_uchar,double,unsigned char)
+#if SIZEOF_INT != SIZEOF_SHORT
+DEFUN_1(copy_double_to_short,double,short)
+DEFUN_1(copy_double_to_ushort,double,unsigned short)
+#else
+# define copy_double_to_short copy_double_to_int
+# define copy_double_to_ushort copy_double_to_uint
+#endif
+DEFUN_1(copy_double_to_int,double,int)
+DEFUN_1(copy_double_to_uint,double,unsigned int)
+#if SIZEOF_INT != SIZEOF_LONG
+DEFUN_1(copy_double_to_long,double,long)
+DEFUN_1(copy_double_to_ulong,double,unsigned long)
+#else
+# define copy_double_to_long copy_double_to_int
+# define copy_double_to_ulong copy_double_to_uint
+#endif
+DEFUN_1(copy_double_to_float,double,float)
+DEFUN_1(copy_double_to_double,double,double)
+
+DEFUN_2(char_to_int,char,int,copy_char_to_int)
+DEFUN_2(char_to_uint,char,unsigned int,copy_char_to_uint)
+#if SIZEOF_INT != SIZEOF_LONG
+DEFUN_2(char_to_long,char,long,copy_char_to_long)
+DEFUN_2(char_to_ulong,char,unsigned long,copy_char_to_ulong)
+#else
+# define char_to_long char_to_int
+# define char_to_ulong char_to_uint
+#endif
+DEFUN_2(char_to_float,char,float,copy_char_to_float)
+DEFUN_2(char_to_double,char,double,copy_char_to_double)
+
+DEFUN_2(uchar_to_int,unsigned char,int,copy_uchar_to_int)
+DEFUN_2(uchar_to_uint,unsigned char,unsigned int,copy_uchar_to_uint)
+#if SIZEOF_INT != SIZEOF_LONG
+DEFUN_2(uchar_to_long,unsigned char,long,copy_uchar_to_long)
+DEFUN_2(uchar_to_ulong,unsigned char,unsigned long,copy_uchar_to_ulong)
+#else
+# define uchar_to_long uchar_to_int
+# define uchar_to_ulong uchar_to_uint
+#endif
+DEFUN_2(uchar_to_float,unsigned char,float,copy_uchar_to_float)
+DEFUN_2(uchar_to_double,unsigned char,double,copy_uchar_to_double)
+
+#if SIZEOF_INT != SIZEOF_SHORT
+DEFUN_2(short_to_int,short,int,copy_short_to_int)
+DEFUN_2(short_to_uint,short,unsigned int,copy_short_to_uint)
+DEFUN_2(short_to_long,short,long,copy_short_to_long)
+DEFUN_2(short_to_ulong,short,unsigned long,copy_short_to_ulong)
+DEFUN_2(short_to_float,short,float,copy_short_to_float)
+DEFUN_2(short_to_double,short,double,copy_short_to_double)
+DEFUN_2(ushort_to_int,unsigned short,int,copy_ushort_to_int)
+DEFUN_2(ushort_to_uint,unsigned short,unsigned int,copy_ushort_to_uint)
+DEFUN_2(ushort_to_long,unsigned short,long,copy_ushort_to_long)
+DEFUN_2(ushort_to_ulong,unsigned short,unsigned long,copy_ushort_to_ulong)
+DEFUN_2(ushort_to_float,unsigned short,float,copy_ushort_to_float)
+DEFUN_2(ushort_to_double,unsigned short,double,copy_ushort_to_double)
+#else
+# define short_to_int NULL
+# define short_to_uint NULL
+# define short_to_long int_to_long
+# define short_to_ulong int_to_ulong
+# define short_to_float int_to_float
+# define short_to_double int_to_double
+# define ushort_to_int NULL
+# define ushort_to_uint NULL
+# define ushort_to_long uint_to_long
+# define ushort_to_ulong uint_to_ulong
+# define ushort_to_float uint_to_float
+# define ushort_to_double uint_to_double
+#endif
+
+#if SIZEOF_INT != SIZEOF_LONG
+DEFUN_2(int_to_long,int,long,copy_int_to_long)
+DEFUN_2(int_to_ulong,int,unsigned long,copy_int_to_ulong)
+#else
+# define int_to_long NULL
+# define int_to_ulong NULL
+#endif
+DEFUN_2(int_to_float,int,float,copy_int_to_float)
+DEFUN_2(int_to_double,int,double,copy_int_to_double)
+
+#if SIZEOF_INT != SIZEOF_LONG
+DEFUN_2(uint_to_long,unsigned int,long,copy_uint_to_long)
+DEFUN_2(uint_to_ulong,unsigned int,unsigned long,copy_uint_to_ulong)
+#else
+# define uint_to_long NULL
+# define uint_to_ulong NULL
+#endif
+DEFUN_2(uint_to_float,unsigned int,float,copy_uint_to_float)
+DEFUN_2(uint_to_double,unsigned int,double,copy_uint_to_double)
+
+#if SIZEOF_INT != SIZEOF_LONG
+DEFUN_2(long_to_float,long,float,copy_long_to_float)
+DEFUN_2(long_to_double,long,double,copy_long_to_double)
+DEFUN_2(ulong_to_float,unsigned long,float,copy_ulong_to_float)
+DEFUN_2(ulong_to_double,unsigned long,double,copy_ulong_to_double)
+#else
+# define long_to_float int_to_float
+# define long_to_double int_to_double
+# define ulong_to_float uint_to_float
+# define ulong_to_double uint_to_double
+#endif
+
+DEFUN_2(float_to_double,float,double,copy_float_to_double)
+
+#define TO_DOUBLE_FUN(name,type) \
+static double name (VOID_STAR x) { return (double) *(type *) x; }
+TO_DOUBLE_FUN(char_to_one_double,char)
+TO_DOUBLE_FUN(uchar_to_one_double,unsigned char)
+#if SIZEOF_INT != SIZEOF_SHORT
+TO_DOUBLE_FUN(short_to_one_double,short)
+TO_DOUBLE_FUN(ushort_to_one_double,unsigned short)
+#else
+# define short_to_one_double int_to_one_double
+# define ushort_to_one_double uint_to_one_double
+#endif
+TO_DOUBLE_FUN(int_to_one_double,int)
+TO_DOUBLE_FUN(uint_to_one_double,unsigned int)
+#if SIZEOF_INT != SIZEOF_LONG
+TO_DOUBLE_FUN(long_to_one_double,long)
+TO_DOUBLE_FUN(ulong_to_one_double,unsigned long)
+#else
+# define long_to_one_double int_to_one_double
+# define ulong_to_one_double uint_to_one_double
+#endif
+TO_DOUBLE_FUN(float_to_one_double,float)
+TO_DOUBLE_FUN(double_to_one_double,double)
+
+SLang_To_Double_Fun_Type
+SLarith_get_to_double_fun (unsigned char type, unsigned int *sizeof_type)
+{
+ unsigned int da;
+ SLang_To_Double_Fun_Type to_double;
+
+ switch (type)
+ {
+ default:
+ return NULL;
+
+ case SLANG_CHAR_TYPE:
+ da = sizeof (char); to_double = char_to_one_double;
+ break;
+ case SLANG_UCHAR_TYPE:
+ da = sizeof (unsigned char); to_double = uchar_to_one_double;
+ break;
+ case SLANG_SHORT_TYPE:
+ da = sizeof (short); to_double = short_to_one_double;
+ break;
+ case SLANG_USHORT_TYPE:
+ da = sizeof (unsigned short); to_double = ushort_to_one_double;
+ break;
+ case SLANG_INT_TYPE:
+ da = sizeof (int); to_double = int_to_one_double;
+ break;
+ case SLANG_UINT_TYPE:
+ da = sizeof (unsigned int); to_double = uint_to_one_double;
+ break;
+ case SLANG_LONG_TYPE:
+ da = sizeof (long); to_double = long_to_one_double;
+ break;
+ case SLANG_ULONG_TYPE:
+ da = sizeof (unsigned long); to_double = ulong_to_one_double;
+ break;
+ case SLANG_FLOAT_TYPE:
+ da = sizeof (float); to_double = float_to_one_double;
+ break;
+ case SLANG_DOUBLE_TYPE:
+ da = sizeof (double); to_double = double_to_one_double;
+ break;
+ }
+
+ if (sizeof_type != NULL) *sizeof_type = da;
+ return to_double;
+}
+
+/* Each element of the matrix determines how the row maps onto the column.
+ * That is, let the matrix be B_ij. Where the i,j indices refer to
+ * precedence of the type. Then,
+ * B_ij->copy_function copies type i to type j. Similarly,
+ * B_ij->convert_function mallocs a new array of type j and copies i to it.
+ *
+ * Since types are always converted to higher levels of precedence for binary
+ * operations, many of the elements are NULL.
+ *
+ * Is the idea clear?
+ */
+typedef struct
+{
+ FVOID_STAR copy_function;
+ Convert_Fun_Type convert_function;
+}
+Binary_Matrix_Type;
+
+static Binary_Matrix_Type Binary_Matrix [MAX_ARITHMETIC_TYPES][MAX_ARITHMETIC_TYPES] =
+{
+ {
+ {(FVOID_STAR)copy_char_to_char, NULL},
+ {(FVOID_STAR)copy_char_to_char, NULL},
+ {(FVOID_STAR) copy_char_to_short, NULL},
+ {(FVOID_STAR) copy_char_to_ushort, NULL},
+ {(FVOID_STAR) copy_char_to_int, char_to_int},
+ {(FVOID_STAR) copy_char_to_uint, char_to_uint},
+ {(FVOID_STAR) copy_char_to_long, char_to_long},
+ {(FVOID_STAR) copy_char_to_ulong, char_to_ulong},
+ {(FVOID_STAR) copy_char_to_float, char_to_float},
+ {(FVOID_STAR) copy_char_to_double, char_to_double},
+ },
+
+ {
+ {(FVOID_STAR)copy_char_to_char, NULL},
+ {(FVOID_STAR)copy_char_to_char, NULL},
+ {(FVOID_STAR) copy_uchar_to_short, NULL},
+ {(FVOID_STAR) copy_uchar_to_ushort, NULL},
+ {(FVOID_STAR) copy_uchar_to_int, uchar_to_int},
+ {(FVOID_STAR) copy_uchar_to_uint, uchar_to_uint},
+ {(FVOID_STAR) copy_uchar_to_long, uchar_to_long},
+ {(FVOID_STAR) copy_uchar_to_ulong, uchar_to_ulong},
+ {(FVOID_STAR) copy_uchar_to_float, uchar_to_float},
+ {(FVOID_STAR) copy_uchar_to_double, uchar_to_double},
+ },
+
+ {
+ {(FVOID_STAR) copy_short_to_char, NULL},
+ {(FVOID_STAR) copy_short_to_uchar, NULL},
+ {(FVOID_STAR) copy_short_to_short, NULL},
+ {(FVOID_STAR) copy_short_to_short, NULL},
+ {(FVOID_STAR) copy_short_to_int, short_to_int},
+ {(FVOID_STAR) copy_short_to_uint, short_to_uint},
+ {(FVOID_STAR) copy_short_to_long, short_to_long},
+ {(FVOID_STAR) copy_short_to_ulong, short_to_ulong},
+ {(FVOID_STAR) copy_short_to_float, short_to_float},
+ {(FVOID_STAR) copy_short_to_double, short_to_double},
+ },
+
+ {
+ {(FVOID_STAR) copy_ushort_to_char, NULL},
+ {(FVOID_STAR) copy_ushort_to_uchar, NULL},
+ {(FVOID_STAR) copy_short_to_short, NULL},
+ {(FVOID_STAR) copy_short_to_short, NULL},
+ {(FVOID_STAR) copy_ushort_to_int, ushort_to_int},
+ {(FVOID_STAR) copy_ushort_to_uint, ushort_to_uint},
+ {(FVOID_STAR) copy_ushort_to_long, ushort_to_long},
+ {(FVOID_STAR) copy_ushort_to_ulong, ushort_to_ulong},
+ {(FVOID_STAR) copy_ushort_to_float, ushort_to_float},
+ {(FVOID_STAR) copy_ushort_to_double, ushort_to_double},
+ },
+
+ {
+ {(FVOID_STAR) copy_int_to_char, NULL},
+ {(FVOID_STAR) copy_int_to_uchar, NULL},
+ {(FVOID_STAR) copy_int_to_short, NULL},
+ {(FVOID_STAR) copy_int_to_ushort, NULL},
+ {(FVOID_STAR) copy_int_to_int, NULL},
+ {(FVOID_STAR) copy_int_to_int, NULL},
+ {(FVOID_STAR) copy_int_to_long, int_to_long},
+ {(FVOID_STAR) copy_int_to_ulong, int_to_ulong},
+ {(FVOID_STAR) copy_int_to_float, int_to_float},
+ {(FVOID_STAR) copy_int_to_double, int_to_double},
+ },
+
+ {
+ {(FVOID_STAR) copy_uint_to_char, NULL},
+ {(FVOID_STAR) copy_uint_to_uchar, NULL},
+ {(FVOID_STAR) copy_uint_to_short, NULL},
+ {(FVOID_STAR) copy_uint_to_ushort, NULL},
+ {(FVOID_STAR) copy_int_to_int, NULL},
+ {(FVOID_STAR) copy_int_to_int, NULL},
+ {(FVOID_STAR) copy_uint_to_long, uint_to_long},
+ {(FVOID_STAR) copy_uint_to_ulong, uint_to_ulong},
+ {(FVOID_STAR) copy_uint_to_float, uint_to_float},
+ {(FVOID_STAR) copy_uint_to_double, uint_to_double},
+ },
+
+ {
+ {(FVOID_STAR) copy_long_to_char, NULL},
+ {(FVOID_STAR) copy_long_to_uchar, NULL},
+ {(FVOID_STAR) copy_long_to_short, NULL},
+ {(FVOID_STAR) copy_long_to_ushort, NULL},
+ {(FVOID_STAR) copy_long_to_int, NULL},
+ {(FVOID_STAR) copy_long_to_uint, NULL},
+ {(FVOID_STAR) copy_long_to_long, NULL},
+ {(FVOID_STAR) copy_long_to_long, NULL},
+ {(FVOID_STAR) copy_long_to_float, long_to_float},
+ {(FVOID_STAR) copy_long_to_double, long_to_double},
+ },
+
+ {
+ {(FVOID_STAR) copy_ulong_to_char, NULL},
+ {(FVOID_STAR) copy_ulong_to_uchar, NULL},
+ {(FVOID_STAR) copy_ulong_to_short, NULL},
+ {(FVOID_STAR) copy_ulong_to_ushort, NULL},
+ {(FVOID_STAR) copy_ulong_to_int, NULL},
+ {(FVOID_STAR) copy_ulong_to_uint, NULL},
+ {(FVOID_STAR) copy_long_to_long, NULL},
+ {(FVOID_STAR) copy_long_to_long, NULL},
+ {(FVOID_STAR) copy_ulong_to_float, ulong_to_float},
+ {(FVOID_STAR) copy_ulong_to_double, ulong_to_double},
+ },
+
+ {
+ {(FVOID_STAR) copy_float_to_char, NULL},
+ {(FVOID_STAR) copy_float_to_uchar, NULL},
+ {(FVOID_STAR) copy_float_to_short, NULL},
+ {(FVOID_STAR) copy_float_to_ushort, NULL},
+ {(FVOID_STAR) copy_float_to_int, NULL},
+ {(FVOID_STAR) copy_float_to_uint, NULL},
+ {(FVOID_STAR) copy_float_to_long, NULL},
+ {(FVOID_STAR) copy_float_to_ulong, NULL},
+ {(FVOID_STAR) copy_float_to_float, NULL},
+ {(FVOID_STAR) copy_float_to_double, float_to_double},
+ },
+
+ {
+ {(FVOID_STAR) copy_double_to_char, NULL},
+ {(FVOID_STAR) copy_double_to_uchar, NULL},
+ {(FVOID_STAR) copy_double_to_short, NULL},
+ {(FVOID_STAR) copy_double_to_ushort, NULL},
+ {(FVOID_STAR) copy_double_to_int, NULL},
+ {(FVOID_STAR) copy_double_to_uint, NULL},
+ {(FVOID_STAR) copy_double_to_long, NULL},
+ {(FVOID_STAR) copy_double_to_ulong, NULL},
+ {(FVOID_STAR) copy_double_to_float, NULL},
+ {(FVOID_STAR) copy_double_to_double, NULL},
+ }
+};
+
+#define GENERIC_BINARY_FUNCTION int_int_bin_op
+#define GENERIC_BIT_OPERATIONS
+#define GENERIC_TYPE int
+#define POW_FUNCTION(a,b) pow((double)(a),(double)(b))
+#define POW_RESULT_TYPE double
+#define ABS_FUNCTION abs
+#define MOD_FUNCTION(a,b) ((a) % (b))
+#define GENERIC_UNARY_FUNCTION int_unary_op
+#define SIGN_FUNCTION(x) (((x) > 0) ? 1 : (((x) < 0) ? -1 : 0))
+#define SCALAR_BINARY_FUNCTION int_int_scalar_bin_op
+#define PUSH_SCALAR_OBJ_FUN(x) SLclass_push_int_obj(SLANG_INT_TYPE,(x))
+#define PUSH_POW_OBJ_FUN(x) SLclass_push_double_obj(SLANG_DOUBLE_TYPE, (x))
+#define CMP_FUNCTION int_cmp_function
+#include "slarith.inc"
+
+#define GENERIC_BINARY_FUNCTION uint_uint_bin_op
+#define GENERIC_BIT_OPERATIONS
+#define GENERIC_TYPE unsigned int
+#define POW_FUNCTION(a,b) pow((double)(a),(double)(b))
+#define POW_RESULT_TYPE double
+#define MOD_FUNCTION(a,b) ((a) % (b))
+#define GENERIC_UNARY_FUNCTION uint_unary_op
+#define ABS_FUNCTION(a) (a)
+#define SIGN_FUNCTION(x) (((x) > 0) ? 1 : 0)
+#define SCALAR_BINARY_FUNCTION uint_uint_scalar_bin_op
+#define PUSH_SCALAR_OBJ_FUN(x) SLclass_push_int_obj(SLANG_UINT_TYPE,(int)(x))
+#define PUSH_POW_OBJ_FUN(x) SLclass_push_double_obj(SLANG_DOUBLE_TYPE, (x))
+#define CMP_FUNCTION uint_cmp_function
+#include "slarith.inc"
+
+#if SIZEOF_LONG != SIZEOF_INT
+#define GENERIC_BINARY_FUNCTION long_long_bin_op
+#define GENERIC_BIT_OPERATIONS
+#define GENERIC_TYPE long
+#define POW_FUNCTION(a,b) pow((double)(a),(double)(b))
+#define POW_RESULT_TYPE double
+#define MOD_FUNCTION(a,b) ((a) % (b))
+#define GENERIC_UNARY_FUNCTION long_unary_op
+#define ABS_FUNCTION(a) (((a) >= 0) ? (a) : -(a))
+#define SIGN_FUNCTION(x) (((x) > 0) ? 1 : (((x) < 0) ? -1 : 0))
+#define SCALAR_BINARY_FUNCTION long_long_scalar_bin_op
+#define PUSH_SCALAR_OBJ_FUN(x) SLclass_push_long_obj(SLANG_LONG_TYPE,(x))
+#define PUSH_POW_OBJ_FUN(x) SLclass_push_double_obj(SLANG_DOUBLE_TYPE, (x))
+#define CMP_FUNCTION long_cmp_function
+#include "slarith.inc"
+
+#define GENERIC_BINARY_FUNCTION ulong_ulong_bin_op
+#define GENERIC_BIT_OPERATIONS
+#define GENERIC_TYPE unsigned long
+#define POW_FUNCTION(a,b) pow((double)(a),(double)(b))
+#define POW_RESULT_TYPE double
+#define MOD_FUNCTION(a,b) ((a) % (b))
+#define GENERIC_UNARY_FUNCTION ulong_unary_op
+#define ABS_FUNCTION(a) (a)
+#define SIGN_FUNCTION(x) (((x) > 0) ? 1 : 0)
+#define SCALAR_BINARY_FUNCTION ulong_ulong_scalar_bin_op
+#define PUSH_SCALAR_OBJ_FUN(x) SLclass_push_long_obj(SLANG_ULONG_TYPE,(long)(x))
+#define PUSH_POW_OBJ_FUN(x) SLclass_push_double_obj(SLANG_DOUBLE_TYPE, (x))
+#define CMP_FUNCTION ulong_cmp_function
+#include "slarith.inc"
+#else
+#define long_long_bin_op int_int_bin_op
+#define ulong_ulong_bin_op uint_uint_bin_op
+#define long_unary_op int_unary_op
+#define ulong_unary_op uint_unary_op
+#define long_cmp_function int_cmp_function
+#define ulong_cmp_function uint_cmp_function
+#endif /* SIZEOF_INT != SIZEOF_LONG */
+
+#define GENERIC_BINARY_FUNCTION float_float_bin_op
+#define GENERIC_TYPE float
+#define POW_FUNCTION(a,b) (float)pow((double)(a),(double)(b))
+#define POW_RESULT_TYPE float
+#define MOD_FUNCTION(a,b) (float)fmod((a),(b))
+#define GENERIC_UNARY_FUNCTION float_unary_op
+#define ABS_FUNCTION(a) (float)fabs((double) a)
+#define SIGN_FUNCTION(x) (((x) > 0) ? 1 : (((x) < 0) ? -1 : 0))
+#define SCALAR_BINARY_FUNCTION float_float_scalar_bin_op
+#define PUSH_SCALAR_OBJ_FUN(x) SLclass_push_float_obj(SLANG_FLOAT_TYPE,(x))
+#define PUSH_POW_OBJ_FUN(x) SLclass_push_float_obj(SLANG_FLOAT_TYPE, (x))
+#define CMP_FUNCTION float_cmp_function
+#include "slarith.inc"
+
+#define GENERIC_BINARY_FUNCTION double_double_bin_op
+#define GENERIC_TYPE double
+#define POW_FUNCTION(a,b) pow((double)(a),(double)(b))
+#define POW_RESULT_TYPE double
+#define MOD_FUNCTION(a,b) (float)fmod((a),(b))
+#define GENERIC_UNARY_FUNCTION double_unary_op
+#define ABS_FUNCTION(a) fabs(a)
+#define SIGN_FUNCTION(x) (((x) > 0) ? 1 : (((x) < 0) ? -1 : 0))
+#define SCALAR_BINARY_FUNCTION double_double_scalar_bin_op
+#define PUSH_SCALAR_OBJ_FUN(x) SLclass_push_double_obj(SLANG_DOUBLE_TYPE,(x))
+#define PUSH_POW_OBJ_FUN(x) SLclass_push_double_obj(SLANG_DOUBLE_TYPE, (x))
+#define CMP_FUNCTION double_cmp_function
+#include "slarith.inc"
+
+#define GENERIC_UNARY_FUNCTION char_unary_op
+#define GENERIC_BIT_OPERATIONS
+#define GENERIC_TYPE signed char
+#define ABS_FUNCTION abs
+#define SIGN_FUNCTION(x) (((x) > 0) ? 1 : (((x) < 0) ? -1 : 0))
+#define CMP_FUNCTION char_cmp_function
+#include "slarith.inc"
+
+#define GENERIC_UNARY_FUNCTION uchar_unary_op
+#define GENERIC_BIT_OPERATIONS
+#define GENERIC_TYPE unsigned char
+#define ABS_FUNCTION(x) (x)
+#define SIGN_FUNCTION(x) (((x) > 0) ? 1 : 0)
+#define CMP_FUNCTION uchar_cmp_function
+#include "slarith.inc"
+
+#if SIZEOF_SHORT != SIZEOF_INT
+#define GENERIC_UNARY_FUNCTION short_unary_op
+#define GENERIC_BIT_OPERATIONS
+#define GENERIC_TYPE short
+#define ABS_FUNCTION abs
+#define SIGN_FUNCTION(x) (((x) > 0) ? 1 : (((x) < 0) ? -1 : 0))
+#define CMP_FUNCTION short_cmp_function
+#include "slarith.inc"
+
+#define GENERIC_UNARY_FUNCTION ushort_unary_op
+#define GENERIC_BIT_OPERATIONS
+#define GENERIC_TYPE unsigned short
+#define ABS_FUNCTION(x) (x)
+#define SIGN_FUNCTION(x) (((x) > 0) ? 1 : 0)
+#define CMP_FUNCTION ushort_cmp_function
+#include "slarith.inc"
+#endif /* SIZEOF_INT != SIZEOF_SHORT */
+
+/* Unfortunately, the numbers that were assigned to the data-types were
+ * not well thought out. So, I need to use the following table.
+ */
+#define MAXIMUM_ARITH_TYPE_VALUE SLANG_FLOAT_TYPE
+#define IS_INTEGER_TYPE(x) \
+ (((x) <= MAXIMUM_ARITH_TYPE_VALUE) \
+ && (Type_Precedence_Table[x] < 8) && (Type_Precedence_Table[x] != -1))
+#define IS_ARITHMETIC_TYPE(x) \
+ (((x) <= MAXIMUM_ARITH_TYPE_VALUE) && (Type_Precedence_Table[x] != -1))
+
+#define LONG_PRECEDENCE_VALUE 6
+#define FLOAT_PRECEDENCE_VALUE 8
+
+static signed char Type_Precedence_Table [MAXIMUM_ARITH_TYPE_VALUE + 1] =
+{
+ -1, /* SLANG_UNDEFINED_TYPE */
+ -1, /* SLANG_VOID_TYPE */
+ 4, /* SLANG_INT_TYPE */
+ 9, /* SLANG_DOUBLE_TYPE */
+ 0, /* SLANG_CHAR_TYPE */
+ -1, /* SLANG_INTP_TYPE */
+ -1, /* SLANG_REF_TYPE */
+ -1, /* SLANG_COMPLEX_TYPE */
+ -1, /* SLANG_NULL_TYPE */
+ 1, /* SLANG_UCHAR_TYPE */
+ 2, /* SLANG_SHORT_TYPE */
+ 3, /* SLANG_USHORT_TYPE */
+ 5, /* SLANG_UINT_TYPE */
+ 6, /* SLANG_LONG_TYPE */
+ 7, /* SLANG_ULONG_TYPE */
+ -1, /* SLANG_STRING_TYPE */
+ 8 /* SLANG_FLOAT_TYPE */
+};
+
+int _SLarith_get_precedence (unsigned char type)
+{
+ if (type > MAXIMUM_ARITH_TYPE_VALUE)
+ return -1;
+
+ return Type_Precedence_Table[type];
+}
+
+unsigned char _SLarith_promote_type (unsigned char t)
+{
+ switch (t)
+ {
+ case SLANG_FLOAT_TYPE:
+ case SLANG_DOUBLE_TYPE:
+ case SLANG_LONG_TYPE:
+ case SLANG_ULONG_TYPE:
+ case SLANG_INT_TYPE:
+ case SLANG_UINT_TYPE:
+ break;
+
+ case SLANG_USHORT_TYPE:
+#if SIZEOF_INT == SIZEOF_SHORT
+ t = SLANG_UINT_TYPE;
+ break;
+#endif
+ /* drop */
+ case SLANG_CHAR_TYPE:
+ case SLANG_UCHAR_TYPE:
+ case SLANG_SHORT_TYPE:
+ default:
+ t = SLANG_INT_TYPE;
+ }
+
+ return t;
+}
+
+static unsigned char promote_to_common_type (unsigned char a, unsigned char b)
+{
+ a = _SLarith_promote_type (a);
+ b = _SLarith_promote_type (b);
+
+ return (Type_Precedence_Table[a] > Type_Precedence_Table[b]) ? a : b;
+}
+
+static int arith_bin_op_result (int op, unsigned char a_type, unsigned char b_type,
+ unsigned char *c_type)
+{
+ switch (op)
+ {
+ case SLANG_EQ:
+ case SLANG_NE:
+ case SLANG_GT:
+ case SLANG_GE:
+ case SLANG_LT:
+ case SLANG_LE:
+ case SLANG_OR:
+ case SLANG_AND:
+ *c_type = SLANG_CHAR_TYPE;
+ return 1;
+
+ case SLANG_POW:
+ if (SLANG_FLOAT_TYPE == promote_to_common_type (a_type, b_type))
+ *c_type = SLANG_FLOAT_TYPE;
+ else
+ *c_type = SLANG_DOUBLE_TYPE;
+ return 1;
+
+ case SLANG_BAND:
+ case SLANG_BXOR:
+ case SLANG_BOR:
+ case SLANG_SHL:
+ case SLANG_SHR:
+ /* The bit-level operations are defined just for integer types */
+ if ((0 == IS_INTEGER_TYPE (a_type))
+ || (0 == IS_INTEGER_TYPE(b_type)))
+ return 0;
+ break;
+
+ default:
+ break;
+ }
+
+ *c_type = promote_to_common_type (a_type, b_type);
+ return 1;
+}
+
+typedef int (*Bin_Fun_Type) (int,
+ unsigned char, VOID_STAR, unsigned int,
+ unsigned char, VOID_STAR, unsigned int,
+ VOID_STAR);
+
+/* This array of functions must be indexed by precedence after arithmetic
+ * promotions.
+ */
+static Bin_Fun_Type Bin_Fun_Map [MAX_ARITHMETIC_TYPES] =
+{
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ int_int_bin_op,
+ uint_uint_bin_op,
+ long_long_bin_op,
+ ulong_ulong_bin_op,
+ float_float_bin_op,
+ double_double_bin_op
+};
+
+static int arith_bin_op (int op,
+ unsigned char a_type, VOID_STAR ap, unsigned int na,
+ unsigned char b_type, VOID_STAR bp, unsigned int nb,
+ VOID_STAR cp)
+{
+ Convert_Fun_Type af, bf;
+ Bin_Fun_Type binfun;
+ int a_indx, b_indx, c_indx;
+ unsigned char c_type;
+ int ret;
+
+ c_type = promote_to_common_type (a_type, b_type);
+
+ a_indx = Type_Precedence_Table [a_type];
+ b_indx = Type_Precedence_Table [b_type];
+ c_indx = Type_Precedence_Table [c_type];
+
+ af = Binary_Matrix[a_indx][c_indx].convert_function;
+ bf = Binary_Matrix[b_indx][c_indx].convert_function;
+ binfun = Bin_Fun_Map[c_indx];
+
+ if ((af != NULL)
+ && (NULL == (ap = (VOID_STAR) (*af) (ap, na))))
+ return -1;
+
+ if ((bf != NULL)
+ && (NULL == (bp = (VOID_STAR) (*bf) (bp, nb))))
+ {
+ if (af != NULL) SLfree ((char *) ap);
+ return -1;
+ }
+
+ ret = (*binfun) (op, a_type, ap, na, b_type, bp, nb, cp);
+ if (af != NULL) SLfree ((char *) ap);
+ if (bf != NULL) SLfree ((char *) bp);
+
+ return ret;
+}
+
+static int arith_unary_op_result (int op, unsigned char a, unsigned char *b)
+{
+ (void) a;
+ switch (op)
+ {
+ default:
+ return 0;
+
+ case SLANG_SQR:
+ case SLANG_MUL2:
+ case SLANG_PLUSPLUS:
+ case SLANG_MINUSMINUS:
+ case SLANG_CHS:
+ case SLANG_ABS:
+ *b = a;
+ break;
+
+ case SLANG_NOT:
+ case SLANG_BNOT:
+ if (0 == IS_INTEGER_TYPE(a))
+ return 0;
+ *b = a;
+ break;
+
+ case SLANG_SIGN:
+ *b = SLANG_INT_TYPE;
+ break;
+ }
+ return 1;
+}
+
+static int integer_pop (unsigned char type, VOID_STAR ptr)
+{
+ SLang_Object_Type obj;
+ int i, j;
+ void (*f)(VOID_STAR, VOID_STAR, unsigned int);
+
+ if (-1 == SLang_pop (&obj))
+ return -1;
+
+ if ((obj.data_type > MAXIMUM_ARITH_TYPE_VALUE)
+ || ((j = Type_Precedence_Table[obj.data_type]) == -1)
+ || (j >= FLOAT_PRECEDENCE_VALUE))
+ {
+ _SLclass_type_mismatch_error (type, obj.data_type);
+ SLang_free_object (&obj);
+ return -1;
+ }
+
+ i = Type_Precedence_Table[type];
+ f = (void (*)(VOID_STAR, VOID_STAR, unsigned int))
+ Binary_Matrix[j][i].copy_function;
+
+ (*f) (ptr, (VOID_STAR)&obj.v, 1);
+
+ return 0;
+}
+
+static int integer_push (unsigned char type, VOID_STAR ptr)
+{
+ SLang_Object_Type obj;
+ int i;
+ void (*f)(VOID_STAR, VOID_STAR, unsigned int);
+
+ i = Type_Precedence_Table[type];
+ f = (void (*)(VOID_STAR, VOID_STAR, unsigned int))
+ Binary_Matrix[i][i].copy_function;
+
+ obj.data_type = type;
+
+ (*f) ((VOID_STAR)&obj.v, ptr, 1);
+
+ return SLang_push (&obj);
+}
+
+int SLang_pop_char (char *i)
+{
+ return integer_pop (SLANG_CHAR_TYPE, (VOID_STAR) i);
+}
+
+int SLang_pop_uchar (unsigned char *i)
+{
+ return integer_pop (SLANG_UCHAR_TYPE, (VOID_STAR) i);
+}
+
+int SLang_pop_short (short *i)
+{
+ return integer_pop (SLANG_SHORT_TYPE, (VOID_STAR) i);
+}
+
+int SLang_pop_ushort (unsigned short *i)
+{
+ return integer_pop (SLANG_USHORT_TYPE, (VOID_STAR) i);
+}
+
+int SLang_pop_long (long *i)
+{
+ return integer_pop (SLANG_LONG_TYPE, (VOID_STAR) i);
+}
+
+int SLang_pop_ulong (unsigned long *i)
+{
+ return integer_pop (SLANG_ULONG_TYPE, (VOID_STAR) i);
+}
+
+int SLang_pop_integer (int *i)
+{
+#if _SLANG_OPTIMIZE_FOR_SPEED
+ SLang_Object_Type obj;
+
+ if (-1 == _SLang_pop_object_of_type (SLANG_INT_TYPE, &obj, 0))
+ return -1;
+ *i = obj.v.int_val;
+ return 0;
+#else
+ return integer_pop (SLANG_INT_TYPE, (VOID_STAR) i);
+#endif
+}
+
+int SLang_pop_uinteger (unsigned int *i)
+{
+ return integer_pop (SLANG_UINT_TYPE, (VOID_STAR) i);
+}
+
+int SLang_push_integer (int i)
+{
+ return SLclass_push_int_obj (SLANG_INT_TYPE, i);
+}
+int SLang_push_uinteger (unsigned int i)
+{
+ return SLclass_push_int_obj (SLANG_UINT_TYPE, (int) i);
+}
+int SLang_push_char (char i)
+{
+ return SLclass_push_char_obj (SLANG_CHAR_TYPE, i);
+}
+int SLang_push_uchar (unsigned char i)
+{
+ return SLclass_push_char_obj (SLANG_UCHAR_TYPE, (char) i);
+}
+int SLang_push_short (short i)
+{
+ return SLclass_push_short_obj (SLANG_SHORT_TYPE, i);
+}
+int SLang_push_ushort (unsigned short i)
+{
+ return SLclass_push_short_obj (SLANG_USHORT_TYPE, (unsigned short) i);
+}
+int SLang_push_long (long i)
+{
+ return SLclass_push_long_obj (SLANG_LONG_TYPE, i);
+}
+int SLang_push_ulong (unsigned long i)
+{
+ return SLclass_push_long_obj (SLANG_ULONG_TYPE, (long) i);
+}
+
+_INLINE_
+int _SLarith_typecast (unsigned char a_type, VOID_STAR ap, unsigned int na,
+ unsigned char b_type, VOID_STAR bp)
+{
+ int i, j;
+
+ void (*copy)(VOID_STAR, VOID_STAR, unsigned int);
+
+ i = Type_Precedence_Table[a_type];
+ j = Type_Precedence_Table[b_type];
+
+ copy = (void (*)(VOID_STAR, VOID_STAR, unsigned int))
+ Binary_Matrix[i][j].copy_function;
+
+ (*copy) (bp, ap, na);
+ return 1;
+}
+
+#if SLANG_HAS_FLOAT
+
+int SLang_pop_double(double *x, int *convertp, int *ip)
+{
+ SLang_Object_Type obj;
+ int i, convert;
+
+ if (0 != SLang_pop (&obj))
+ return -1;
+
+ i = 0;
+ convert = 0;
+
+ switch (obj.data_type)
+ {
+ case SLANG_FLOAT_TYPE:
+ *x = (double) obj.v.float_val;
+ break;
+
+ case SLANG_DOUBLE_TYPE:
+ *x = obj.v.double_val;
+ break;
+
+ case SLANG_INT_TYPE:
+ i = (int) obj.v.long_val;
+ *x = (double) i;
+ convert = 1;
+ break;
+
+ case SLANG_CHAR_TYPE: *x = (double) obj.v.char_val; break;
+ case SLANG_UCHAR_TYPE: *x = (double) obj.v.uchar_val; break;
+ case SLANG_SHORT_TYPE: *x = (double) obj.v.short_val; break;
+ case SLANG_USHORT_TYPE: *x = (double) obj.v.ushort_val; break;
+ case SLANG_UINT_TYPE: *x = (double) obj.v.uint_val; break;
+ case SLANG_LONG_TYPE: *x = (double) obj.v.long_val; break;
+ case SLANG_ULONG_TYPE: *x = (double) obj.v.ulong_val; break;
+
+ default:
+ _SLclass_type_mismatch_error (SLANG_DOUBLE_TYPE, obj.data_type);
+ SLang_free_object (&obj);
+ return -1;
+ }
+
+ if (convertp != NULL) *convertp = convert;
+ if (ip != NULL) *ip = i;
+
+ return 0;
+}
+
+int SLang_push_double (double x)
+{
+ return SLclass_push_double_obj (SLANG_DOUBLE_TYPE, x);
+}
+
+int SLang_pop_float (float *x)
+{
+ double d;
+
+ /* Pop it as a double and let the double function do all the typcasting */
+ if (-1 == SLang_pop_double (&d, NULL, NULL))
+ return -1;
+
+ *x = (float) d;
+ return 0;
+}
+
+int SLang_push_float (float f)
+{
+ return SLclass_push_float_obj (SLANG_FLOAT_TYPE, (double) f);
+}
+
+/* Double */
+static int double_push (unsigned char unused, VOID_STAR ptr)
+{
+ (void) unused;
+ SLang_push_double (*(double *) ptr);
+ return 0;
+}
+
+static int double_push_literal (unsigned char type, VOID_STAR ptr)
+{
+ (void) type;
+ return SLang_push_double (**(double **)ptr);
+}
+
+static int double_pop (unsigned char unused, VOID_STAR ptr)
+{
+ (void) unused;
+ return SLang_pop_double ((double *) ptr, NULL, NULL);
+}
+
+static void double_byte_code_destroy (unsigned char unused, VOID_STAR ptr)
+{
+ (void) unused;
+ SLfree (*(char **) ptr);
+}
+
+static int float_push (unsigned char unused, VOID_STAR ptr)
+{
+ (void) unused;
+ SLang_push_float (*(float *) ptr);
+ return 0;
+}
+
+static int float_pop (unsigned char unused, VOID_STAR ptr)
+{
+ (void) unused;
+ return SLang_pop_float ((float *) ptr);
+}
+
+#endif /* SLANG_HAS_FLOAT */
+
+#if SLANG_HAS_FLOAT
+static char Double_Format[16] = "%g";
+
+void _SLset_double_format (char *s)
+{
+ strncpy (Double_Format, s, 15);
+ Double_Format[15] = 0;
+}
+#endif
+
+static char *arith_string (unsigned char type, VOID_STAR v)
+{
+ char buf [256];
+ char *s;
+
+ s = buf;
+
+ switch (type)
+ {
+ default:
+ s = SLclass_get_datatype_name (type);
+ break;
+
+ case SLANG_CHAR_TYPE:
+ sprintf (s, "%d", *(char *) v);
+ break;
+ case SLANG_UCHAR_TYPE:
+ sprintf (s, "%u", *(unsigned char *) v);
+ break;
+ case SLANG_SHORT_TYPE:
+ sprintf (s, "%d", *(short *) v);
+ break;
+ case SLANG_USHORT_TYPE:
+ sprintf (s, "%u", *(unsigned short *) v);
+ break;
+ case SLANG_INT_TYPE:
+ sprintf (s, "%d", *(int *) v);
+ break;
+ case SLANG_UINT_TYPE:
+ sprintf (s, "%u", *(unsigned int *) v);
+ break;
+ case SLANG_LONG_TYPE:
+ sprintf (s, "%ld", *(long *) v);
+ break;
+ case SLANG_ULONG_TYPE:
+ sprintf (s, "%lu", *(unsigned long *) v);
+ break;
+#if SLANG_HAS_FLOAT
+ case SLANG_FLOAT_TYPE:
+ if (EOF == _SLsnprintf (buf, sizeof (buf), Double_Format, *(float *) v))
+ sprintf (s, "%e", *(float *) v);
+ break;
+ case SLANG_DOUBLE_TYPE:
+ if (EOF == _SLsnprintf (buf, sizeof (buf), Double_Format, *(double *) v))
+ sprintf (s, "%e", *(double *) v);
+ break;
+#endif
+ }
+
+ return SLmake_string (s);
+}
+
+static int integer_to_bool (unsigned char type, int *t)
+{
+ (void) type;
+ return SLang_pop_integer (t);
+}
+
+static int push_int_literal (unsigned char type, VOID_STAR ptr)
+{
+ return SLclass_push_int_obj (type, (int) *(long *) ptr);
+}
+
+static int push_char_literal (unsigned char type, VOID_STAR ptr)
+{
+ return SLclass_push_char_obj (type, (char) *(long *) ptr);
+}
+
+#if SIZEOF_SHORT != SIZEOF_INT
+static int push_short_literal (unsigned char type, VOID_STAR ptr)
+{
+ return SLclass_push_short_obj (type, (short) *(long *) ptr);
+}
+#endif
+
+#if SIZEOF_INT != SIZEOF_LONG
+static int push_long_literal (unsigned char type, VOID_STAR ptr)
+{
+ return SLclass_push_long_obj (type, *(long *) ptr);
+}
+#endif
+
+typedef struct
+{
+ char *name;
+ unsigned char data_type;
+ unsigned int sizeof_type;
+ int (*unary_fun)(int, unsigned char, VOID_STAR, unsigned int, VOID_STAR);
+ int (*push_literal) (unsigned char, VOID_STAR);
+ int (*cmp_fun) (unsigned char, VOID_STAR, VOID_STAR, int *);
+}
+Integer_Info_Type;
+
+static Integer_Info_Type Integer_Types [8] =
+{
+ {"Char_Type", SLANG_CHAR_TYPE, sizeof (char), char_unary_op, push_char_literal, char_cmp_function},
+ {"UChar_Type", SLANG_UCHAR_TYPE, sizeof (unsigned char), uchar_unary_op, push_char_literal, uchar_cmp_function},
+#if SIZEOF_INT != SIZEOF_SHORT
+ {"Short_Type", SLANG_SHORT_TYPE, sizeof (short), short_unary_op, push_short_literal, short_cmp_function},
+ {"UShort_Type", SLANG_USHORT_TYPE, sizeof (unsigned short), ushort_unary_op, push_short_literal, ushort_cmp_function},
+#else
+ {NULL, SLANG_SHORT_TYPE},
+ {NULL, SLANG_USHORT_TYPE},
+#endif
+
+ {"Integer_Type", SLANG_INT_TYPE, sizeof (int), int_unary_op, push_int_literal, int_cmp_function},
+ {"UInteger_Type", SLANG_UINT_TYPE, sizeof (unsigned int), uint_unary_op, push_int_literal, uint_cmp_function},
+
+#if SIZEOF_INT != SIZEOF_LONG
+ {"Long_Type", SLANG_LONG_TYPE, sizeof (long), long_unary_op, push_long_literal, long_cmp_function},
+ {"ULong_Type", SLANG_ULONG_TYPE, sizeof (unsigned long), ulong_unary_op, push_long_literal, ulong_cmp_function}
+#else
+ {NULL, SLANG_LONG_TYPE, 0, NULL, NULL, NULL},
+ {NULL, SLANG_ULONG_TYPE, 0, NULL, NULL, NULL}
+#endif
+};
+
+static int create_synonyms (void)
+{
+ static char *names[8] =
+ {
+ "Int16_Type", "UInt16_Type", "Int32_Type", "UInt32_Type",
+ "Int64_Type", "UInt64_Type",
+ "Float32_Type", "Float64_Type"
+ };
+ int types[8];
+ unsigned int i;
+
+ memset ((char *) types, 0, sizeof (types));
+
+ /* The assumption is that sizeof(unsigned X) == sizeof (X) */
+#if SIZEOF_INT == 2
+ types[0] = SLANG_INT_TYPE;
+ types[1] = SLANG_UINT_TYPE;
+#else
+# if SIZEOF_SHORT == 2
+ types[0] = SLANG_SHORT_TYPE;
+ types[1] = SLANG_USHORT_TYPE;
+# else
+# if SIZEOF_LONG == 2
+ types[0] = SLANG_LONG_TYPE;
+ types[1] = SLANG_ULONG_TYPE;
+# endif
+# endif
+#endif
+
+#if SIZEOF_INT == 4
+ types[2] = SLANG_INT_TYPE;
+ types[3] = SLANG_UINT_TYPE;
+#else
+# if SIZEOF_SHORT == 4
+ types[2] = SLANG_SHORT_TYPE;
+ types[3] = SLANG_USHORT_TYPE;
+# else
+# if SIZEOF_LONG == 4
+ types[2] = SLANG_LONG_TYPE;
+ types[3] = SLANG_ULONG_TYPE;
+# endif
+# endif
+#endif
+
+#if SIZEOF_INT == 8
+ types[4] = SLANG_INT_TYPE;
+ types[5] = SLANG_UINT_TYPE;
+#else
+# if SIZEOF_SHORT == 8
+ types[4] = SLANG_SHORT_TYPE;
+ types[5] = SLANG_USHORT_TYPE;
+# else
+# if SIZEOF_LONG == 8
+ types[4] = SLANG_LONG_TYPE;
+ types[5] = SLANG_ULONG_TYPE;
+# endif
+# endif
+#endif
+
+#if SLANG_HAS_FLOAT
+
+#if SIZEOF_FLOAT == 4
+ types[6] = SLANG_FLOAT_TYPE;
+#else
+# if SIZEOF_DOUBLE == 4
+ types[6] = SLANG_DOUBLE_TYPE;
+# endif
+#endif
+#if SIZEOF_FLOAT == 8
+ types[7] = SLANG_FLOAT_TYPE;
+#else
+# if SIZEOF_DOUBLE == 8
+ types[7] = SLANG_DOUBLE_TYPE;
+# endif
+#endif
+
+#endif
+
+ if ((-1 == SLclass_create_synonym ("Int_Type", SLANG_INT_TYPE))
+ || (-1 == SLclass_create_synonym ("UInt_Type", SLANG_UINT_TYPE)))
+ return -1;
+
+ for (i = 0; i < 8; i++)
+ {
+ if (types[i] == 0) continue;
+
+ if (-1 == SLclass_create_synonym (names[i], types[i]))
+ return -1;
+ }
+
+#if SIZEOF_INT == SIZEOF_SHORT
+ if ((-1 == SLclass_create_synonym ("Short_Type", SLANG_INT_TYPE))
+ || (-1 == SLclass_create_synonym ("UShort_Type", SLANG_UINT_TYPE))
+ || (-1 == _SLclass_copy_class (SLANG_SHORT_TYPE, SLANG_INT_TYPE))
+ || (-1 == _SLclass_copy_class (SLANG_USHORT_TYPE, SLANG_UINT_TYPE)))
+ return -1;
+#endif
+#if SIZEOF_INT == SIZEOF_LONG
+ if ((-1 == SLclass_create_synonym ("Long_Type", SLANG_INT_TYPE))
+ || (-1 == SLclass_create_synonym ("ULong_Type", SLANG_UINT_TYPE))
+ || (-1 == _SLclass_copy_class (SLANG_LONG_TYPE, SLANG_INT_TYPE))
+ || (-1 == _SLclass_copy_class (SLANG_ULONG_TYPE, SLANG_UINT_TYPE)))
+ return -1;
+#endif
+ return 0;
+}
+
+int _SLarith_register_types (void)
+{
+ SLang_Class_Type *cl;
+ int a_type, b_type;
+ int i, j;
+
+#if defined(HAVE_SETLOCALE) && defined(LC_NUMERIC)
+ /* make sure decimal point it used --- the parser requires it */
+ (void) setlocale (LC_NUMERIC, "C");
+#endif
+
+ for (i = 0; i < 8; i++)
+ {
+ Integer_Info_Type *info;
+
+ info = Integer_Types + i;
+
+ if (info->name == NULL)
+ {
+ /* This happens when the object is the same size as an integer
+ * For this case, we really want to copy the integer class.
+ * We will handle that when the synonym is created.
+ */
+ continue;
+ }
+
+ if (NULL == (cl = SLclass_allocate_class (info->name)))
+ return -1;
+
+ (void) SLclass_set_string_function (cl, arith_string);
+ (void) SLclass_set_push_function (cl, integer_push);
+ (void) SLclass_set_pop_function (cl, integer_pop);
+ cl->cl_push_literal = info->push_literal;
+ cl->cl_to_bool = integer_to_bool;
+
+ cl->cl_cmp = info->cmp_fun;
+
+ if (-1 == SLclass_register_class (cl, info->data_type, info->sizeof_type,
+ SLANG_CLASS_TYPE_SCALAR))
+ return -1;
+ if (-1 == SLclass_add_unary_op (info->data_type, info->unary_fun, arith_unary_op_result))
+ return -1;
+
+ _SLarith_Is_Arith_Type [info->data_type] = 1;
+ }
+
+#if SLANG_HAS_FLOAT
+ if (NULL == (cl = SLclass_allocate_class ("Double_Type")))
+ return -1;
+ (void) SLclass_set_push_function (cl, double_push);
+ (void) SLclass_set_pop_function (cl, double_pop);
+ (void) SLclass_set_string_function (cl, arith_string);
+ cl->cl_byte_code_destroy = double_byte_code_destroy;
+ cl->cl_push_literal = double_push_literal;
+ cl->cl_cmp = double_cmp_function;
+
+ if (-1 == SLclass_register_class (cl, SLANG_DOUBLE_TYPE, sizeof (double),
+ SLANG_CLASS_TYPE_SCALAR))
+ return -1;
+ if (-1 == SLclass_add_unary_op (SLANG_DOUBLE_TYPE, double_unary_op, arith_unary_op_result))
+ return -1;
+ _SLarith_Is_Arith_Type [SLANG_DOUBLE_TYPE] = 2;
+
+ if (NULL == (cl = SLclass_allocate_class ("Float_Type")))
+ return -1;
+ (void) SLclass_set_string_function (cl, arith_string);
+ (void) SLclass_set_push_function (cl, float_push);
+ (void) SLclass_set_pop_function (cl, float_pop);
+ cl->cl_cmp = float_cmp_function;
+
+ if (-1 == SLclass_register_class (cl, SLANG_FLOAT_TYPE, sizeof (float),
+ SLANG_CLASS_TYPE_SCALAR))
+ return -1;
+ if (-1 == SLclass_add_unary_op (SLANG_FLOAT_TYPE, float_unary_op, arith_unary_op_result))
+ return -1;
+ _SLarith_Is_Arith_Type [SLANG_FLOAT_TYPE] = 2;
+#endif
+
+ if (-1 == create_synonyms ())
+ return -1;
+
+ for (a_type = 0; a_type <= MAXIMUM_ARITH_TYPE_VALUE; a_type++)
+ {
+ if (-1 == (i = Type_Precedence_Table [a_type]))
+ continue;
+
+ for (b_type = 0; b_type <= MAXIMUM_ARITH_TYPE_VALUE; b_type++)
+ {
+ int implicit_ok;
+
+ if (-1 == (j = Type_Precedence_Table [b_type]))
+ continue;
+
+ /* Allow implicit typecast, except from into to float */
+ implicit_ok = ((j >= FLOAT_PRECEDENCE_VALUE)
+ || (i < FLOAT_PRECEDENCE_VALUE));
+
+ if (-1 == SLclass_add_binary_op (a_type, b_type, arith_bin_op, arith_bin_op_result))
+ return -1;
+
+ if (i != j)
+ if (-1 == SLclass_add_typecast (a_type, b_type, _SLarith_typecast, implicit_ok))
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+#if _SLANG_OPTIMIZE_FOR_SPEED
+
+static void promote_objs (SLang_Object_Type *a, SLang_Object_Type *b,
+ SLang_Object_Type *c, SLang_Object_Type *d)
+{
+ unsigned char ia, ib, ic, id;
+ int i, j;
+ void (*copy)(VOID_STAR, VOID_STAR, unsigned int);
+
+ ia = a->data_type;
+ ib = b->data_type;
+
+ ic = _SLarith_promote_type (ia);
+
+ if (ic == ib) id = ic; /* already promoted */
+ else id = _SLarith_promote_type (ib);
+
+ i = Type_Precedence_Table[ic];
+ j = Type_Precedence_Table[id];
+ if (i > j)
+ {
+ id = ic;
+ j = i;
+ }
+
+ c->data_type = d->data_type = id;
+
+ i = Type_Precedence_Table[ia];
+ copy = (void (*)(VOID_STAR, VOID_STAR, unsigned int))
+ Binary_Matrix[i][j].copy_function;
+ (*copy) ((VOID_STAR) &c->v, (VOID_STAR)&a->v, 1);
+
+ i = Type_Precedence_Table[ib];
+ copy = (void (*)(VOID_STAR, VOID_STAR, unsigned int))
+ Binary_Matrix[i][j].copy_function;
+ (*copy) ((VOID_STAR) &d->v, (VOID_STAR)&b->v, 1);
+}
+
+int _SLarith_bin_op (SLang_Object_Type *oa, SLang_Object_Type *ob, int op)
+{
+ unsigned char a_type, b_type;
+
+ a_type = oa->data_type;
+ b_type = ob->data_type;
+
+ if (a_type != b_type)
+ {
+ SLang_Object_Type obj_a, obj_b;
+
+ /* Handle common cases */
+ if ((a_type == SLANG_INT_TYPE)
+ && (b_type == SLANG_DOUBLE_TYPE))
+ return double_double_scalar_bin_op (oa->v.int_val, ob->v.double_val, op);
+
+ if ((a_type == SLANG_DOUBLE_TYPE)
+ && (b_type == SLANG_INT_TYPE))
+ return double_double_scalar_bin_op (oa->v.double_val, ob->v.int_val, op);
+
+ /* Otherwise do it the hard way */
+ promote_objs (oa, ob, &obj_a, &obj_b);
+ oa = &obj_a;
+ ob = &obj_b;
+
+ a_type = oa->data_type;
+ b_type = ob->data_type;
+ }
+
+
+ switch (a_type)
+ {
+ case SLANG_CHAR_TYPE:
+ return int_int_scalar_bin_op (oa->v.char_val, ob->v.char_val, op);
+
+ case SLANG_UCHAR_TYPE:
+ return int_int_scalar_bin_op (oa->v.uchar_val, ob->v.uchar_val, op);
+
+ case SLANG_SHORT_TYPE:
+ return int_int_scalar_bin_op (oa->v.short_val, ob->v.short_val, op);
+
+ case SLANG_USHORT_TYPE:
+# if SIZEOF_INT == SIZEOF_SHORT
+ return uint_uint_scalar_bin_op (oa->v.ushort_val, ob->v.ushort_val, op);
+# else
+ return int_int_scalar_bin_op ((int)oa->v.ushort_val, (int)ob->v.ushort_val, op);
+# endif
+
+#if SIZEOF_LONG == SIZEOF_INT
+ case SLANG_LONG_TYPE:
+#endif
+ case SLANG_INT_TYPE:
+ return int_int_scalar_bin_op (oa->v.int_val, ob->v.int_val, op);
+
+#if SIZEOF_LONG == SIZEOF_INT
+ case SLANG_ULONG_TYPE:
+#endif
+ case SLANG_UINT_TYPE:
+ return uint_uint_scalar_bin_op (oa->v.uint_val, ob->v.uint_val, op);
+
+#if SIZEOF_LONG != SIZEOF_INT
+ case SLANG_LONG_TYPE:
+ return long_long_scalar_bin_op (oa->v.long_val, ob->v.long_val, op);
+ case SLANG_ULONG_TYPE:
+ return ulong_ulong_scalar_bin_op (oa->v.ulong_val, ob->v.ulong_val, op);
+#endif
+ case SLANG_FLOAT_TYPE:
+ return float_float_scalar_bin_op (oa->v.float_val, ob->v.float_val, op);
+ case SLANG_DOUBLE_TYPE:
+ return double_double_scalar_bin_op (oa->v.double_val, ob->v.double_val, op);
+ }
+
+ return 1;
+}
+#endif
diff --git a/mdk-stage1/slang/slarith.inc b/mdk-stage1/slang/slarith.inc
new file mode 100644
index 000000000..efa8a5e04
--- /dev/null
+++ b/mdk-stage1/slang/slarith.inc
@@ -0,0 +1,783 @@
+/* -*- c -*- */
+
+/* This include file is a template for defining arithmetic binary operations
+ * on arithmetic types. I realize that doing it this way is not very
+ * elegant but it minimizes the number of lines of code and I believe it
+ * promotes clarity.
+ */
+
+/* The following macros should be properly defined before including this file:
+ *
+ * GENERIC_BINARY_FUNCTION: The name of the binary function
+ * GENERIC_TYPE: The class data type
+ * MOD_FUNCTION: The function to use for mod
+ * ABS_FUNCTION: Name of the abs function
+ * SIGN_FUNCTION: Name of the sign function
+ * GENERIC_UNARY_FUNCTION Name of the unary function
+ *
+ * If GENERIC_BIT_OPERATIONS is defined, the bit-level binary operators
+ * will get included. If the data type has a power operation (SLANG_POW),
+ * then POW_FUNCTION should be defined to return POW_RESULT_TYPE.
+ */
+#ifdef GENERIC_BINARY_FUNCTION
+
+static int GENERIC_BINARY_FUNCTION
+(int op,
+ unsigned char a_type, VOID_STAR ap, unsigned int na,
+ unsigned char b_type, VOID_STAR bp, unsigned int nb,
+ VOID_STAR cp)
+{
+ GENERIC_TYPE *c, *a, *b;
+#ifdef POW_FUNCTION
+ POW_RESULT_TYPE *d;
+#endif
+ unsigned int n;
+#if _SLANG_OPTIMIZE_FOR_SPEED < 2
+ unsigned int n_max, da, db;
+#endif
+ char *cc;
+
+ (void) a_type; /* Both SLANG_INT_TYPE */
+ (void) b_type;
+
+ a = (GENERIC_TYPE *) ap;
+ b = (GENERIC_TYPE *) bp;
+ c = (GENERIC_TYPE *) cp;
+ cc = (char *) cp;
+
+#if _SLANG_OPTIMIZE_FOR_SPEED < 2
+ if (na == 1) da = 0; else da = 1;
+ if (nb == 1) db = 0; else db = 1;
+
+ if (na > nb) n_max = na; else n_max = nb;
+#endif
+
+ switch (op)
+ {
+ default:
+ return 0;
+#ifdef POW_FUNCTION
+ case SLANG_POW:
+ d = (POW_RESULT_TYPE *) cp;
+#if _SLANG_OPTIMIZE_FOR_SPEED < 2
+ for (n = 0; n < n_max; n++)
+ {
+ d[n] = POW_FUNCTION(*a, *b);
+ a += da; b += db;
+ }
+#else
+ if (na == nb)
+ {
+ for (n = 0; n < na; n++)
+ d[n] = POW_FUNCTION(a[n],b[n]);
+ }
+ else if (nb == 1)
+ {
+ GENERIC_TYPE xb = *b;
+ if (xb == 2)
+ for (n = 0; n < na; n++)
+ d[n] = a[n] * a[n];
+ else
+ for (n = 0; n < na; n++)
+ d[n] = POW_FUNCTION(a[n], xb);
+ }
+ else /* if (na == 1) */
+ {
+ GENERIC_TYPE xa = *a;
+ for (n = 0; n < nb; n++)
+ d[n] = POW_FUNCTION(xa, b[n]);
+ }
+#endif
+ break;
+#endif
+ case SLANG_PLUS:
+#if _SLANG_OPTIMIZE_FOR_SPEED < 2
+ for (n = 0; n < n_max; n++)
+ {
+ c[n] = (*a + *b); a += da; b += db;
+ }
+#else
+ if (na == nb)
+ {
+ for (n = 0; n < na; n++)
+ c[n] = a[n] + b[n];
+ }
+ else if (nb == 1)
+ {
+ GENERIC_TYPE xb = *b;
+ for (n = 0; n < na; n++)
+ c[n] = a[n] + xb;
+ }
+ else /* if (na == 1) */
+ {
+ GENERIC_TYPE xa = *a;
+ for (n = 0; n < nb; n++)
+ c[n] = xa + b[n];
+ }
+#endif
+ break;
+
+ case SLANG_MINUS:
+#if _SLANG_OPTIMIZE_FOR_SPEED < 2
+ for (n = 0; n < n_max; n++)
+ {
+ c[n] = (*a - *b); a += da; b += db;
+ }
+#else
+ if (na == nb)
+ {
+ for (n = 0; n < na; n++)
+ c[n] = a[n] - b[n];
+ }
+ else if (nb == 1)
+ {
+ GENERIC_TYPE xb = *b;
+ for (n = 0; n < na; n++)
+ c[n] = a[n] - xb;
+ }
+ else /* if (na == 1) */
+ {
+ GENERIC_TYPE xa = *a;
+ for (n = 0; n < nb; n++)
+ c[n] = xa - b[n];
+ }
+#endif
+ break;
+
+ case SLANG_TIMES:
+#if _SLANG_OPTIMIZE_FOR_SPEED < 2
+ for (n = 0; n < n_max; n++)
+ {
+ c[n] = (*a * *b); a += da; b += db;
+ }
+#else
+ if (na == nb)
+ {
+ for (n = 0; n < na; n++)
+ c[n] = a[n] * b[n];
+ }
+ else if (nb == 1)
+ {
+ GENERIC_TYPE xb = *b;
+ for (n = 0; n < na; n++)
+ c[n] = a[n] * xb;
+ }
+ else /* if (na == 1) */
+ {
+ GENERIC_TYPE xa = *a;
+ for (n = 0; n < nb; n++)
+ c[n] = xa * b[n];
+ }
+#endif
+ break;
+
+ case SLANG_DIVIDE:
+#if _SLANG_OPTIMIZE_FOR_SPEED < 2
+ for (n = 0; n < n_max; n++)
+ {
+ if (*b == 0)
+ {
+ SLang_Error = SL_DIVIDE_ERROR;
+ return -1;
+ }
+ c[n] = (*a / *b); a += da; b += db;
+ }
+#else
+ if (na == nb)
+ {
+ for (n = 0; n < na; n++)
+ {
+ if (b[n] == 0)
+ {
+ SLang_Error = SL_DIVIDE_ERROR;
+ return -1;
+ }
+ c[n] = a[n] / b[n];
+ }
+ }
+ else if (nb == 1)
+ {
+ GENERIC_TYPE xb = *b;
+
+ if (xb == 0)
+ {
+ SLang_Error = SL_DIVIDE_ERROR;
+ return -1;
+ }
+ for (n = 0; n < na; n++)
+ c[n] = a[n] / xb;
+ }
+ else /* if (na == 1) */
+ {
+ GENERIC_TYPE xa = *a;
+ for (n = 0; n < nb; n++)
+ {
+ if (b[n] == 0)
+ {
+ SLang_Error = SL_DIVIDE_ERROR;
+ return -1;
+ }
+ c[n] = xa / b[n];
+ }
+ }
+#endif
+ break;
+
+ case SLANG_MOD:
+#if _SLANG_OPTIMIZE_FOR_SPEED < 2
+ for (n = 0; n < n_max; n++)
+ {
+ if (*b == 0)
+ {
+ SLang_Error = SL_DIVIDE_ERROR;
+ return -1;
+ }
+ c[n] = MOD_FUNCTION(*a, *b); a += da; b += db;
+ }
+#else
+ if (na == nb)
+ {
+ for (n = 0; n < na; n++)
+ {
+ if (b[n] == 0)
+ {
+ SLang_Error = SL_DIVIDE_ERROR;
+ return -1;
+ }
+ c[n] = MOD_FUNCTION(a[n],b[n]);
+ }
+ }
+ else if (nb == 1)
+ {
+ GENERIC_TYPE xb = *b;
+ if (xb == 0)
+ {
+ SLang_Error = SL_DIVIDE_ERROR;
+ return -1;
+ }
+ for (n = 0; n < na; n++)
+ c[n] = MOD_FUNCTION(a[n],xb);
+ }
+ else /* if (na == 1) */
+ {
+ GENERIC_TYPE xa = *a;
+ for (n = 0; n < nb; n++)
+ {
+ if (b[n] == 0)
+ {
+ SLang_Error = SL_DIVIDE_ERROR;
+ return -1;
+ }
+ c[n] = MOD_FUNCTION(xa,b[n]);
+ }
+ }
+#endif
+ break;
+
+#ifdef GENERIC_BIT_OPERATIONS
+ case SLANG_BAND:
+#if _SLANG_OPTIMIZE_FOR_SPEED < 2
+ for (n = 0; n < n_max; n++)
+ {
+ c[n] = (*a & *b); a += da; b += db;
+ }
+#else
+ if (na == nb)
+ {
+ for (n = 0; n < na; n++)
+ c[n] = a[n] & b[n];
+ }
+ else if (nb == 1)
+ {
+ GENERIC_TYPE xb = *b;
+ for (n = 0; n < na; n++)
+ c[n] = a[n] & xb;
+ }
+ else /* if (na == 1) */
+ {
+ GENERIC_TYPE xa = *a;
+ for (n = 0; n < nb; n++)
+ c[n] = xa & b[n];
+ }
+#endif
+ break;
+
+ case SLANG_BXOR:
+#if _SLANG_OPTIMIZE_FOR_SPEED < 2
+ for (n = 0; n < n_max; n++)
+ {
+ c[n] = (*a ^ *b); a += da; b += db;
+ }
+#else
+ if (na == nb)
+ {
+ for (n = 0; n < na; n++)
+ c[n] = a[n] ^ b[n];
+ }
+ else if (nb == 1)
+ {
+ GENERIC_TYPE xb = *b;
+ for (n = 0; n < na; n++)
+ c[n] = a[n] ^ xb;
+ }
+ else /* if (na == 1) */
+ {
+ GENERIC_TYPE xa = *a;
+ for (n = 0; n < nb; n++)
+ c[n] = xa ^ b[n];
+ }
+#endif
+ break;
+
+ case SLANG_BOR:
+#if _SLANG_OPTIMIZE_FOR_SPEED < 2
+ for (n = 0; n < n_max; n++)
+ {
+ c[n] = (*a | *b); a += da; b += db;
+ }
+#else
+ if (na == nb)
+ {
+ for (n = 0; n < na; n++)
+ c[n] = a[n] | b[n];
+ }
+ else if (nb == 1)
+ {
+ GENERIC_TYPE xb = *b;
+ for (n = 0; n < na; n++)
+ c[n] = a[n] | xb;
+ }
+ else /* if (na == 1) */
+ {
+ GENERIC_TYPE xa = *a;
+ for (n = 0; n < nb; n++)
+ c[n] = xa | b[n];
+ }
+#endif
+ break;
+
+ case SLANG_SHL:
+#if _SLANG_OPTIMIZE_FOR_SPEED < 2
+ for (n = 0; n < n_max; n++)
+ {
+ c[n] = (*a << *b); a += da; b += db;
+ }
+#else
+ if (na == nb)
+ {
+ for (n = 0; n < na; n++)
+ c[n] = a[n] << b[n];
+ }
+ else if (nb == 1)
+ {
+ GENERIC_TYPE xb = *b;
+ for (n = 0; n < na; n++)
+ c[n] = a[n] << xb;
+ }
+ else /* if (na == 1) */
+ {
+ GENERIC_TYPE xa = *a;
+ for (n = 0; n < nb; n++)
+ c[n] = xa << b[n];
+ }
+#endif
+ break;
+
+ case SLANG_SHR:
+#if _SLANG_OPTIMIZE_FOR_SPEED < 2
+ for (n = 0; n < n_max; n++)
+ {
+ c[n] = (*a >> *b); a += da; b += db;
+ }
+#else
+ if (na == nb)
+ {
+ for (n = 0; n < na; n++)
+ c[n] = a[n] >> b[n];
+ }
+ else if (nb == 1)
+ {
+ GENERIC_TYPE xb = *b;
+ for (n = 0; n < na; n++)
+ c[n] = a[n] >> xb;
+ }
+ else /* if (na == 1) */
+ {
+ GENERIC_TYPE xa = *a;
+ for (n = 0; n < nb; n++)
+ c[n] = xa >> b[n];
+ }
+#endif
+ break;
+#endif /* GENERIC_BIT_OPERATIONS */
+ case SLANG_EQ:
+#if _SLANG_OPTIMIZE_FOR_SPEED < 2
+ for (n = 0; n < n_max; n++)
+ {
+ cc[n] = (*a == *b); a += da; b += db;
+ }
+#else
+ if (na == nb)
+ {
+ for (n = 0; n < na; n++)
+ cc[n] = (a[n] == b[n]);
+ }
+ else if (nb == 1)
+ {
+ GENERIC_TYPE xb = *b;
+ for (n = 0; n < na; n++)
+ cc[n] = (a[n] == xb);
+ }
+ else /* if (na == 1) */
+ {
+ GENERIC_TYPE xa = *a;
+ for (n = 0; n < nb; n++)
+ cc[n] = (xa == b[n]);
+ }
+#endif
+ break;
+
+ case SLANG_NE:
+#if _SLANG_OPTIMIZE_FOR_SPEED < 2
+ for (n = 0; n < n_max; n++)
+ {
+ cc[n] = (*a != *b); a += da; b += db;
+ }
+#else
+ if (na == nb)
+ {
+ for (n = 0; n < na; n++)
+ cc[n] = (a[n] != b[n]);
+ }
+ else if (nb == 1)
+ {
+ GENERIC_TYPE xb = *b;
+ for (n = 0; n < na; n++)
+ cc[n] = (a[n] != xb);
+ }
+ else /* if (na == 1) */
+ {
+ GENERIC_TYPE xa = *a;
+ for (n = 0; n < nb; n++)
+ cc[n] = (xa != b[n]);
+ }
+#endif
+ break;
+
+ case SLANG_GT:
+#if _SLANG_OPTIMIZE_FOR_SPEED < 2
+ for (n = 0; n < n_max; n++)
+ {
+ cc[n] = (*a > *b); a += da; b += db;
+ }
+#else
+ if (na == nb)
+ {
+ for (n = 0; n < na; n++)
+ cc[n] = (a[n] > b[n]);
+ }
+ else if (nb == 1)
+ {
+ GENERIC_TYPE xb = *b;
+ for (n = 0; n < na; n++)
+ cc[n] = (a[n] > xb);
+ }
+ else /* if (na == 1) */
+ {
+ GENERIC_TYPE xa = *a;
+ for (n = 0; n < nb; n++)
+ cc[n] = (xa > b[n]);
+ }
+#endif
+ break;
+
+ case SLANG_GE:
+#if _SLANG_OPTIMIZE_FOR_SPEED < 2
+ for (n = 0; n < n_max; n++)
+ {
+ cc[n] = (*a >= *b); a += da; b += db;
+ }
+#else
+ if (na == nb)
+ {
+ for (n = 0; n < na; n++)
+ cc[n] = (a[n] >= b[n]);
+ }
+ else if (nb == 1)
+ {
+ GENERIC_TYPE xb = *b;
+ for (n = 0; n < na; n++)
+ cc[n] = (a[n] >= xb);
+ }
+ else /* if (na == 1) */
+ {
+ GENERIC_TYPE xa = *a;
+ for (n = 0; n < nb; n++)
+ cc[n] = (xa >= b[n]);
+ }
+#endif
+ break;
+
+ case SLANG_LT:
+#if _SLANG_OPTIMIZE_FOR_SPEED < 2
+ for (n = 0; n < n_max; n++)
+ {
+ cc[n] = (*a < *b); a += da; b += db;
+ }
+#else
+ if (na == nb)
+ {
+ for (n = 0; n < na; n++)
+ cc[n] = (a[n] < b[n]);
+ }
+ else if (nb == 1)
+ {
+ GENERIC_TYPE xb = *b;
+ for (n = 0; n < na; n++)
+ cc[n] = (a[n] < xb);
+ }
+ else /* if (na == 1) */
+ {
+ GENERIC_TYPE xa = *a;
+ for (n = 0; n < nb; n++)
+ cc[n] = (xa < b[n]);
+ }
+#endif
+ break;
+
+ case SLANG_LE:
+#if _SLANG_OPTIMIZE_FOR_SPEED < 2
+ for (n = 0; n < n_max; n++)
+ {
+ cc[n] = (*a <= *b); a += da; b += db;
+ }
+#else
+ if (na == nb)
+ {
+ for (n = 0; n < na; n++)
+ cc[n] = (a[n] <= b[n]);
+ }
+ else if (nb == 1)
+ {
+ GENERIC_TYPE xb = *b;
+ for (n = 0; n < na; n++)
+ cc[n] = (a[n] <= xb);
+ }
+ else /* if (na == 1) */
+ {
+ GENERIC_TYPE xa = *a;
+ for (n = 0; n < nb; n++)
+ cc[n] = (xa <= b[n]);
+ }
+#endif
+ break;
+
+ case SLANG_OR:
+#if _SLANG_OPTIMIZE_FOR_SPEED < 2
+ for (n = 0; n < n_max; n++)
+ {
+ cc[n] = (*a || *b); a += da; b += db;
+ }
+#else
+ if (na == nb)
+ {
+ for (n = 0; n < na; n++)
+ cc[n] = (a[n] || b[n]);
+ }
+ else if (nb == 1)
+ {
+ GENERIC_TYPE xb = *b;
+ for (n = 0; n < na; n++)
+ cc[n] = (a[n] || xb);
+ }
+ else /* if (na == 1) */
+ {
+ GENERIC_TYPE xa = *a;
+ for (n = 0; n < nb; n++)
+ cc[n] = (xa || b[n]);
+ }
+#endif
+ break;
+
+ case SLANG_AND:
+#if _SLANG_OPTIMIZE_FOR_SPEED < 2
+ for (n = 0; n < n_max; n++)
+ {
+ cc[n] = (*a && *b); a += da; b += db;
+ }
+#else
+ if (na == nb)
+ {
+ for (n = 0; n < na; n++)
+ cc[n] = (a[n] && b[n]);
+ }
+ else if (nb == 1)
+ {
+ GENERIC_TYPE xb = *b;
+ for (n = 0; n < na; n++)
+ cc[n] = (a[n] && xb);
+ }
+ else /* if (na == 1) */
+ {
+ GENERIC_TYPE xa = *a;
+ for (n = 0; n < nb; n++)
+ cc[n] = (xa && b[n]);
+ }
+#endif
+ break;
+ }
+ return 1;
+}
+
+#endif /* GENERIC_BINARY_FUNCTION */
+
+
+#ifdef GENERIC_UNARY_FUNCTION
+
+static int GENERIC_UNARY_FUNCTION
+(int op,
+ unsigned char a_type, VOID_STAR ap, unsigned int na,
+ VOID_STAR bp
+ )
+{
+ GENERIC_TYPE *a, *b;
+ unsigned int n;
+ int *ib;
+
+ (void) a_type;
+
+ a = (GENERIC_TYPE *) ap;
+ b = (GENERIC_TYPE *) bp;
+
+ switch (op)
+ {
+ default:
+ return 0;
+
+ case SLANG_PLUSPLUS:
+ for (n = 0; n < na; n++) b[n] = (a[n] + 1);
+ break;
+ case SLANG_MINUSMINUS:
+ for (n = 0; n < na; n++) b[n] = (a[n] - 1);
+ break;
+ case SLANG_CHS:
+ for (n = 0; n < na; n++) b[n] = (GENERIC_TYPE) -(a[n]);
+ break;
+ case SLANG_SQR:
+ for (n = 0; n < na; n++) b[n] = (a[n] * a[n]);
+ break;
+ case SLANG_MUL2:
+ for (n = 0; n < na; n++) b[n] = (2 * a[n]);
+ break;
+ case SLANG_ABS:
+ for (n = 0; n < na; n++) b[n] = ABS_FUNCTION (a[n]);
+ break;
+ case SLANG_SIGN:
+ ib = (int *) bp;
+ for (n = 0; n < na; n++)
+ ib[n] = SIGN_FUNCTION(a[n]);
+ break;
+
+#ifdef GENERIC_BIT_OPERATIONS
+ case SLANG_NOT:
+ for (n = 0; n < na; n++) b[n] = !(a[n]);
+ break;
+ case SLANG_BNOT:
+ for (n = 0; n < na; n++) b[n] = ~(a[n]);
+ break;
+#endif
+ }
+
+ return 1;
+}
+#endif /* GENERIC_UNARY_FUNCTION */
+
+
+#ifdef SCALAR_BINARY_FUNCTION
+
+static int SCALAR_BINARY_FUNCTION (GENERIC_TYPE a, GENERIC_TYPE b, int op)
+{
+ switch (op)
+ {
+ default:
+ return 1;
+
+#ifdef POW_FUNCTION
+ case SLANG_POW:
+ return PUSH_POW_OBJ_FUN(POW_FUNCTION(a, b));
+#endif
+ case SLANG_PLUS:
+ return PUSH_SCALAR_OBJ_FUN (a + b);
+ case SLANG_MINUS:
+ return PUSH_SCALAR_OBJ_FUN (a - b);
+ case SLANG_TIMES:
+ return PUSH_SCALAR_OBJ_FUN (a * b);
+ case SLANG_DIVIDE:
+ if (b == 0)
+ {
+ SLang_Error = SL_DIVIDE_ERROR;
+ return -1;
+ }
+ return PUSH_SCALAR_OBJ_FUN (a / b);
+ case SLANG_MOD:
+ if (b == 0)
+ {
+ SLang_Error = SL_DIVIDE_ERROR;
+ return -1;
+ }
+ return PUSH_SCALAR_OBJ_FUN (MOD_FUNCTION(a,b));
+#ifdef GENERIC_BIT_OPERATIONS
+ case SLANG_BAND:
+ return PUSH_SCALAR_OBJ_FUN (a & b);
+ case SLANG_BXOR:
+ return PUSH_SCALAR_OBJ_FUN (a ^ b);
+ case SLANG_BOR:
+ return PUSH_SCALAR_OBJ_FUN (a | b);
+ case SLANG_SHL:
+ return PUSH_SCALAR_OBJ_FUN (a << b);
+ case SLANG_SHR:
+ return PUSH_SCALAR_OBJ_FUN (a >> b);
+#endif
+ case SLANG_GT: return SLclass_push_char_obj (SLANG_CHAR_TYPE, (char)(a > b));
+ case SLANG_LT: return SLclass_push_char_obj (SLANG_CHAR_TYPE, (char)(a < b));
+ case SLANG_GE: return SLclass_push_char_obj (SLANG_CHAR_TYPE, (char)(a >= b));
+ case SLANG_LE: return SLclass_push_char_obj (SLANG_CHAR_TYPE, (char)(a <= b));
+ case SLANG_EQ: return SLclass_push_char_obj (SLANG_CHAR_TYPE, (char)(a == b));
+ case SLANG_NE: return SLclass_push_char_obj (SLANG_CHAR_TYPE, (char)(a != b));
+ case SLANG_OR: return SLclass_push_char_obj (SLANG_CHAR_TYPE, (char)(a || b));
+ case SLANG_AND: return SLclass_push_char_obj (SLANG_CHAR_TYPE, (char)(a && b));
+ }
+}
+
+#endif /* SCALAR_BINARY_FUNCTION */
+
+#ifdef CMP_FUNCTION
+static int CMP_FUNCTION (unsigned char unused, VOID_STAR a, VOID_STAR b, int *c)
+{
+ GENERIC_TYPE x, y;
+
+ (void) unused;
+ x = *(GENERIC_TYPE *) a;
+ y = *(GENERIC_TYPE *) b;
+
+ if (x > y) *c = 1;
+ else if (x == y) *c = 0;
+ else *c = -1;
+
+ return 0;
+}
+#endif
+
+#undef CMP_FUNCTION
+#undef SCALAR_BINARY_FUNCTION
+#undef PUSH_POW_OBJ_FUN
+#undef PUSH_SCALAR_OBJ_FUN
+#undef GENERIC_BINARY_FUNCTION
+#undef GENERIC_UNARY_FUNCTION
+#undef GENERIC_BIT_OPERATIONS
+#undef GENERIC_TYPE
+#undef POW_FUNCTION
+#undef POW_RESULT_TYPE
+#undef MOD_FUNCTION
+#undef ABS_FUNCTION
+#undef SIGN_FUNCTION
diff --git a/mdk-stage1/slang/slarray.c b/mdk-stage1/slang/slarray.c
new file mode 100644
index 000000000..0b9a1406c
--- /dev/null
+++ b/mdk-stage1/slang/slarray.c
@@ -0,0 +1,3139 @@
+/* Array manipulation routines for S-Lang */
+/* Copyright (c) 1997, 1999, 2001 John E. Davis
+ * This file is part of the S-Lang library.
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Perl Artistic License.
+ */
+
+#include "slinclud.h"
+
+#define SL_APP_WANTS_FOREACH
+#include "slang.h"
+#include "_slang.h"
+
+typedef struct
+{
+ int first_index;
+ int last_index;
+ int delta;
+}
+SLarray_Range_Array_Type;
+
+/* Use SLang_pop_array when a linear array is required. */
+static int pop_array (SLang_Array_Type **at_ptr, int convert_scalar)
+{
+ SLang_Array_Type *at;
+ int one = 1;
+ int type;
+
+ *at_ptr = NULL;
+ type = SLang_peek_at_stack ();
+
+ switch (type)
+ {
+ case -1:
+ return -1;
+
+ case SLANG_ARRAY_TYPE:
+ return SLclass_pop_ptr_obj (SLANG_ARRAY_TYPE, (VOID_STAR *) at_ptr);
+
+ case SLANG_NULL_TYPE:
+ convert_scalar = 0;
+ /* drop */
+ default:
+ if (convert_scalar == 0)
+ {
+ SLdo_pop ();
+ SLang_verror (SL_TYPE_MISMATCH, "Context requires an array. Scalar not converted");
+ return -1;
+ }
+ break;
+ }
+
+ if (NULL == (at = SLang_create_array ((unsigned char) type, 0, NULL, &one, 1)))
+ return -1;
+
+ if (-1 == at->cl->cl_apop ((unsigned char) type, at->data))
+ {
+ SLang_free_array (at);
+ return -1;
+ }
+
+ *at_ptr = at;
+
+ return 0;
+}
+
+static VOID_STAR linear_get_data_addr (SLang_Array_Type *at, int *dims)
+{
+ unsigned int num_dims;
+ unsigned int ofs;
+ unsigned int i;
+ int *max_dims;
+
+ ofs = 0;
+ max_dims = at->dims;
+ num_dims = at->num_dims;
+
+ for (i = 0; i < num_dims; i++)
+ {
+ int d = dims[i];
+
+ if (d < 0)
+ d = d + max_dims[i];
+
+ ofs = ofs * (unsigned int)max_dims [i] + (unsigned int) d;
+ }
+
+ return (VOID_STAR) ((char *)at->data + (ofs * at->sizeof_type));
+}
+
+static VOID_STAR get_data_addr (SLang_Array_Type *at, int *dims)
+{
+ VOID_STAR data;
+
+ data = at->data;
+ if (data == NULL)
+ {
+ SLang_verror (SL_UNKNOWN_ERROR, "Array has no data");
+ return NULL;
+ }
+
+ data = (*at->index_fun) (at, dims);
+
+ if (data == NULL)
+ {
+ SLang_verror (SL_UNKNOWN_ERROR, "Unable to access array element");
+ return NULL;
+ }
+
+ return data;
+}
+
+void _SLarray_free_array_elements (SLang_Class_Type *cl, VOID_STAR s, unsigned int num)
+{
+ unsigned int sizeof_type;
+ void (*f) (unsigned char, VOID_STAR);
+ char *p;
+ unsigned char type;
+
+ if ((cl->cl_class_type == SLANG_CLASS_TYPE_SCALAR)
+ || (cl->cl_class_type == SLANG_CLASS_TYPE_VECTOR))
+ return;
+
+ f = cl->cl_destroy;
+ sizeof_type = cl->cl_sizeof_type;
+ type = cl->cl_data_type;
+
+ p = (char *) s;
+ while (num != 0)
+ {
+ if (NULL != *(VOID_STAR *)p)
+ {
+ (*f) (type, (VOID_STAR)p);
+ *(VOID_STAR *) p = NULL;
+ }
+ p += sizeof_type;
+ num--;
+ }
+}
+
+static int destroy_element (SLang_Array_Type *at,
+ int *dims,
+ VOID_STAR data)
+{
+ data = get_data_addr (at, dims);
+ if (data == NULL)
+ return -1;
+
+ /* This function should only get called for arrays that have
+ * pointer elements. Do not call the destroy method if the element
+ * is NULL.
+ */
+ if (NULL != *(VOID_STAR *)data)
+ {
+ (*at->cl->cl_destroy) (at->data_type, data);
+ *(VOID_STAR *) data = NULL;
+ }
+ return 0;
+}
+
+/* This function only gets called when a new array is created. Thus there
+ * is no need to destroy the object first.
+ */
+static int new_object_element (SLang_Array_Type *at,
+ int *dims,
+ VOID_STAR data)
+{
+ data = get_data_addr (at, dims);
+ if (data == NULL)
+ return -1;
+
+ return (*at->cl->cl_init_array_object) (at->data_type, data);
+}
+
+static int next_index (int *dims, int *max_dims, unsigned int num_dims)
+{
+ while (num_dims)
+ {
+ int dims_i;
+
+ num_dims--;
+
+ dims_i = dims [num_dims] + 1;
+ if (dims_i != (int) max_dims [num_dims])
+ {
+ dims [num_dims] = dims_i;
+ return 0;
+ }
+ dims [num_dims] = 0;
+ }
+
+ return -1;
+}
+
+static int do_method_for_all_elements (SLang_Array_Type *at,
+ int (*method)(SLang_Array_Type *,
+ int *,
+ VOID_STAR),
+ VOID_STAR client_data)
+{
+ int dims [SLARRAY_MAX_DIMS];
+ int *max_dims;
+ unsigned int num_dims;
+
+ if (at->num_elements == 0)
+ return 0;
+
+ max_dims = at->dims;
+ num_dims = at->num_dims;
+
+ SLMEMSET((char *)dims, 0, sizeof(dims));
+
+ do
+ {
+ if (-1 == (*method) (at, dims, client_data))
+ return -1;
+ }
+ while (0 == next_index (dims, max_dims, num_dims));
+
+ return 0;
+}
+
+void SLang_free_array (SLang_Array_Type *at)
+{
+ VOID_STAR data;
+ unsigned int flags;
+
+ if (at == NULL) return;
+
+ if (at->num_refs > 1)
+ {
+ at->num_refs -= 1;
+ return;
+ }
+
+ data = at->data;
+ flags = at->flags;
+
+ if (flags & SLARR_DATA_VALUE_IS_INTRINSIC)
+ return; /* not to be freed */
+
+ if (flags & SLARR_DATA_VALUE_IS_POINTER)
+ (void) do_method_for_all_elements (at, destroy_element, NULL);
+
+ SLfree ((char *) data);
+ SLfree ((char *) at);
+}
+
+SLang_Array_Type *
+SLang_create_array1 (unsigned char type, int read_only, VOID_STAR data,
+ int *dims, unsigned int num_dims, int no_init)
+{
+ SLang_Class_Type *cl;
+ unsigned int i;
+ SLang_Array_Type *at;
+ unsigned int num_elements;
+ unsigned int sizeof_type;
+ unsigned int size;
+
+ if (num_dims > SLARRAY_MAX_DIMS)
+ {
+ SLang_verror (SL_NOT_IMPLEMENTED, "%u dimensional arrays are not supported", num_dims);
+ return NULL;
+ }
+
+ for (i = 0; i < num_dims; i++)
+ {
+ if (dims[i] < 0)
+ {
+ SLang_verror (SL_INVALID_PARM, "Size of array dim %u is less than 0", i);
+ return NULL;
+ }
+ }
+
+ cl = _SLclass_get_class (type);
+
+ at = (SLang_Array_Type *) SLmalloc (sizeof(SLang_Array_Type));
+ if (at == NULL)
+ return NULL;
+
+ SLMEMSET ((char*) at, 0, sizeof(SLang_Array_Type));
+
+ at->data_type = type;
+ at->cl = cl;
+ at->num_dims = num_dims;
+ at->num_refs = 1;
+
+ if (read_only) at->flags = SLARR_DATA_VALUE_IS_READ_ONLY;
+ switch (cl->cl_class_type)
+ {
+ case SLANG_CLASS_TYPE_VECTOR:
+ case SLANG_CLASS_TYPE_SCALAR:
+ break;
+
+ default:
+ at->flags |= SLARR_DATA_VALUE_IS_POINTER;
+ }
+
+ num_elements = 1;
+ for (i = 0; i < num_dims; i++)
+ {
+ at->dims [i] = dims[i];
+ num_elements = dims [i] * num_elements;
+ }
+
+ /* Now set the rest of the unused dimensions to 1. This makes it easier
+ * when transposing arrays.
+ */
+ while (i < SLARRAY_MAX_DIMS)
+ at->dims[i++] = 1;
+
+ at->num_elements = num_elements;
+ at->index_fun = linear_get_data_addr;
+ at->sizeof_type = sizeof_type = cl->cl_sizeof_type;
+
+ if (data != NULL)
+ {
+ at->data = data;
+ return at;
+ }
+
+ size = num_elements * sizeof_type;
+
+ if (size == 0) size = 1;
+
+ if (NULL == (data = (VOID_STAR) SLmalloc (size)))
+ {
+ SLang_free_array (at);
+ return NULL;
+ }
+
+ if (no_init == 0)
+ SLMEMSET ((char *) data, 0, size);
+
+ at->data = data;
+
+ if ((cl->cl_init_array_object != NULL)
+ && (-1 == do_method_for_all_elements (at, new_object_element, NULL)))
+ {
+ SLang_free_array (at);
+ return NULL;
+ }
+ return at;
+}
+
+SLang_Array_Type *
+SLang_create_array (unsigned char type, int read_only, VOID_STAR data,
+ int *dims, unsigned int num_dims)
+{
+ return SLang_create_array1 (type, read_only, data, dims, num_dims, 0);
+}
+
+int SLang_add_intrinsic_array (char *name,
+ unsigned char type,
+ int read_only,
+ VOID_STAR data,
+ unsigned int num_dims, ...)
+{
+ va_list ap;
+ unsigned int i;
+ int dims[SLARRAY_MAX_DIMS];
+ SLang_Array_Type *at;
+
+ if ((num_dims > SLARRAY_MAX_DIMS)
+ || (name == NULL)
+ || (data == NULL))
+ {
+ SLang_verror (SL_INVALID_PARM, "Unable to create intrinsic array");
+ return -1;
+ }
+
+ va_start (ap, num_dims);
+ for (i = 0; i < num_dims; i++)
+ dims [i] = va_arg (ap, int);
+ va_end (ap);
+
+ at = SLang_create_array (type, read_only, data, dims, num_dims);
+ if (at == NULL)
+ return -1;
+ at->flags |= SLARR_DATA_VALUE_IS_INTRINSIC;
+
+ /* Note: The variable that refers to the intrinsic array is regarded as
+ * read-only. That way, Array_Name = another_array; will fail.
+ */
+ if (-1 == SLadd_intrinsic_variable (name, (VOID_STAR) at, SLANG_ARRAY_TYPE, 1))
+ {
+ SLang_free_array (at);
+ return -1;
+ }
+ return 0;
+}
+
+static int pop_array_indices (int *dims, unsigned int num_dims)
+{
+ unsigned int n;
+ int i;
+
+ if (num_dims > SLARRAY_MAX_DIMS)
+ {
+ SLang_verror (SL_INVALID_PARM, "Array size not supported");
+ return -1;
+ }
+
+ n = num_dims;
+ while (n != 0)
+ {
+ n--;
+ if (-1 == SLang_pop_integer (&i))
+ return -1;
+
+ dims[n] = i;
+ }
+
+ return 0;
+}
+
+int SLang_push_array (SLang_Array_Type *at, int free_flag)
+{
+ if (at == NULL)
+ return SLang_push_null ();
+
+ at->num_refs += 1;
+
+ if (0 == SLclass_push_ptr_obj (SLANG_ARRAY_TYPE, (VOID_STAR) at))
+ {
+ if (free_flag)
+ SLang_free_array (at);
+ return 0;
+ }
+
+ at->num_refs -= 1;
+
+ if (free_flag) SLang_free_array (at);
+ return -1;
+}
+
+/* This function gets called via expressions such as Double_Type[10, 20];
+ */
+static int push_create_new_array (void)
+{
+ unsigned int num_dims;
+ SLang_Array_Type *at;
+ unsigned char type;
+ int dims [SLARRAY_MAX_DIMS];
+ int (*anew) (unsigned char, unsigned int);
+
+ num_dims = (SLang_Num_Function_Args - 1);
+
+ if (-1 == _SLang_pop_datatype (&type))
+ return -1;
+
+ anew = (_SLclass_get_class (type))->cl_anew;
+ if (anew != NULL)
+ return (*anew) (type, num_dims);
+
+ if (-1 == pop_array_indices (dims, num_dims))
+ return -1;
+
+ if (NULL == (at = SLang_create_array (type, 0, NULL, dims, num_dims)))
+ return -1;
+
+ return SLang_push_array (at, 1);
+}
+
+static int push_element_at_addr (SLang_Array_Type *at,
+ VOID_STAR data, int allow_null)
+{
+ SLang_Class_Type *cl;
+
+ cl = at->cl;
+ if ((at->flags & SLARR_DATA_VALUE_IS_POINTER)
+ && (*(VOID_STAR *) data == NULL))
+ {
+ if (allow_null)
+ return SLang_push_null ();
+
+ SLang_verror (SL_VARIABLE_UNINITIALIZED,
+ "%s array has unitialized element", cl->cl_name);
+ return -1;
+ }
+
+ return (*cl->cl_apush)(at->data_type, data);
+}
+
+static int coerse_array_to_linear (SLang_Array_Type *at)
+{
+ SLarray_Range_Array_Type *range;
+ int *data;
+ int xmin, dx;
+ unsigned int i, imax;
+
+ /* FIXME: Priority = low. This assumes that if an array is not linear, then
+ * it is a range.
+ */
+ if (0 == (at->flags & SLARR_DATA_VALUE_IS_RANGE))
+ return 0;
+
+ range = (SLarray_Range_Array_Type *) at->data;
+ xmin = range->first_index;
+ dx = range->delta;
+
+ imax = at->num_elements;
+ data = (int *) SLmalloc ((imax + 1) * sizeof (int));
+ if (data == NULL)
+ return -1;
+
+ for (i = 0; i < imax; i++)
+ {
+ data [i] = xmin;
+ xmin += dx;
+ }
+
+ SLfree ((char *) range);
+ at->data = (VOID_STAR) data;
+ at->flags &= ~SLARR_DATA_VALUE_IS_RANGE;
+ at->index_fun = linear_get_data_addr;
+ return 0;
+}
+
+static void
+free_index_objects (SLang_Object_Type *index_objs, unsigned int num_indices)
+{
+ unsigned int i;
+ SLang_Object_Type *obj;
+
+ for (i = 0; i < num_indices; i++)
+ {
+ obj = index_objs + i;
+ if (obj->data_type != 0)
+ SLang_free_object (obj);
+ }
+}
+
+static int
+pop_indices (SLang_Object_Type *index_objs, unsigned int num_indices,
+ int *is_index_array)
+{
+ unsigned int i;
+
+ SLMEMSET((char *) index_objs, 0, num_indices * sizeof (SLang_Object_Type));
+
+ *is_index_array = 0;
+
+ if (num_indices >= SLARRAY_MAX_DIMS)
+ {
+ SLang_verror (SL_INVALID_PARM, "too many indices for array");
+ return -1;
+ }
+
+ i = num_indices;
+ while (i != 0)
+ {
+ SLang_Object_Type *obj;
+
+ i--;
+ obj = index_objs + i;
+ if (-1 == _SLang_pop_object_of_type (SLANG_INT_TYPE, obj, 1))
+ goto return_error;
+
+ if (obj->data_type == SLANG_ARRAY_TYPE)
+ {
+ SLang_Array_Type *at = obj->v.array_val;
+
+ if (at->num_dims == 1)
+ {
+ if ((num_indices == 1)
+ && (0 == (at->flags & SLARR_DATA_VALUE_IS_RANGE)))
+ *is_index_array = 1;
+ }
+ else
+ {
+ SLang_verror (SL_INVALID_PARM, "expecting a 1-d index array");
+ goto return_error;
+ }
+ }
+ }
+
+ return 0;
+
+ return_error:
+ free_index_objects (index_objs, num_indices);
+ return -1;
+}
+
+/* Here ind_at is a linear 1-d array of indices */
+static int
+check_index_array_ranges (SLang_Array_Type *at, SLang_Array_Type *ind_at)
+{
+ int *indices, *indices_max;
+ unsigned int num_elements;
+
+ num_elements = at->num_elements;
+ indices = (int *) ind_at->data;
+ indices_max = indices + ind_at->num_elements;
+
+ while (indices < indices_max)
+ {
+ unsigned int d;
+
+ d = (unsigned int) *indices++;
+ if (d >= num_elements)
+ {
+ SLang_verror (SL_INVALID_PARM,
+ "index-array is out of range");
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static int
+transfer_n_elements (SLang_Array_Type *at, VOID_STAR dest_data, VOID_STAR src_data,
+ unsigned int sizeof_type, unsigned int n, int is_ptr)
+{
+ unsigned char data_type;
+ SLang_Class_Type *cl;
+
+ if (is_ptr == 0)
+ {
+ SLMEMCPY ((char *) dest_data, (char *)src_data, n * sizeof_type);
+ return 0;
+ }
+
+ data_type = at->data_type;
+ cl = at->cl;
+
+ while (n != 0)
+ {
+ if (*(VOID_STAR *)dest_data != NULL)
+ {
+ (*cl->cl_destroy) (data_type, dest_data);
+ *(VOID_STAR *) dest_data = NULL;
+ }
+
+ if (*(VOID_STAR *) src_data == NULL)
+ *(VOID_STAR *) dest_data = NULL;
+ else
+ {
+ if (-1 == (*cl->cl_acopy) (data_type, src_data, dest_data))
+ /* No need to destroy anything */
+ return -1;
+ }
+
+ src_data = (VOID_STAR) ((char *)src_data + sizeof_type);
+ dest_data = (VOID_STAR) ((char *)dest_data + sizeof_type);
+
+ n--;
+ }
+
+ return 0;
+}
+
+int
+_SLarray_aget_transfer_elem (SLang_Array_Type *at, int *indices,
+ VOID_STAR new_data, unsigned int sizeof_type, int is_ptr)
+{
+ VOID_STAR at_data;
+
+ /* Since 1 element is being transferred, there is not need to coerse
+ * the array to linear.
+ */
+ if (NULL == (at_data = get_data_addr (at, indices)))
+ return -1;
+
+ return transfer_n_elements (at, new_data, at_data, sizeof_type, 1, is_ptr);
+}
+
+/* Here the ind_at index-array is a 1-d array of indices. This function
+ * creates a 1-d array of made up of values of 'at' at the locations
+ * specified by the indices. The result is pushed.
+ */
+static int
+aget_from_index_array (SLang_Array_Type *at,
+ SLang_Array_Type *ind_at)
+{
+ SLang_Array_Type *new_at;
+ int *indices, *indices_max;
+ unsigned char *new_data, *src_data;
+ unsigned int sizeof_type;
+ int is_ptr;
+
+ if (-1 == coerse_array_to_linear (at))
+ return -1;
+
+ if (-1 == coerse_array_to_linear (ind_at))
+ return -1;
+
+ if (-1 == check_index_array_ranges (at, ind_at))
+ return -1;
+
+ if (NULL == (new_at = SLang_create_array (at->data_type, 0, NULL, ind_at->dims, 1)))
+ return -1;
+
+ /* Since the index array is linear, I can address it directly */
+ indices = (int *) ind_at->data;
+ indices_max = indices + ind_at->num_elements;
+
+ src_data = (unsigned char *) at->data;
+ new_data = (unsigned char *) new_at->data;
+ sizeof_type = new_at->sizeof_type;
+ is_ptr = (new_at->flags & SLARR_DATA_VALUE_IS_POINTER);
+
+ while (indices < indices_max)
+ {
+ unsigned int offset;
+
+ offset = sizeof_type * (unsigned int)*indices;
+ if (-1 == transfer_n_elements (at, (VOID_STAR) new_data,
+ (VOID_STAR) (src_data + offset),
+ sizeof_type, 1, is_ptr))
+ {
+ SLang_free_array (new_at);
+ return -1;
+ }
+
+ new_data += sizeof_type;
+ indices++;
+ }
+
+ return SLang_push_array (new_at, 1);
+}
+
+/* This is extremely ugly. It is due to the fact that the index_objects
+ * may contain ranges. This is a utility function for the aget/aput
+ * routines
+ */
+static int
+convert_nasty_index_objs (SLang_Array_Type *at,
+ SLang_Object_Type *index_objs,
+ unsigned int num_indices,
+ int **index_data,
+ int *range_buf, int *range_delta_buf,
+ int *max_dims,
+ unsigned int *num_elements,
+ int *is_array, int is_dim_array[SLARRAY_MAX_DIMS])
+{
+ unsigned int i, total_num_elements;
+ SLang_Array_Type *ind_at;
+
+ if (num_indices != at->num_dims)
+ {
+ SLang_verror (SL_INVALID_PARM, "Array requires %u indices", at->num_dims);
+ return -1;
+ }
+
+ *is_array = 0;
+ total_num_elements = 1;
+ for (i = 0; i < num_indices; i++)
+ {
+ int max_index, min_index;
+ SLang_Object_Type *obj;
+ int at_dims_i;
+
+ at_dims_i = at->dims[i];
+ obj = index_objs + i;
+ range_delta_buf [i] = 0;
+
+ if (obj->data_type == SLANG_INT_TYPE)
+ {
+ range_buf [i] = min_index = max_index = obj->v.int_val;
+ max_dims [i] = 1;
+ index_data[i] = range_buf + i;
+ is_dim_array[i] = 0;
+ }
+ else
+ {
+ *is_array = 1;
+ is_dim_array[i] = 1;
+ ind_at = obj->v.array_val;
+
+ if (ind_at->flags & SLARR_DATA_VALUE_IS_RANGE)
+ {
+ SLarray_Range_Array_Type *r;
+ int delta;
+ int first_index, last_index;
+
+ r = (SLarray_Range_Array_Type *) ind_at->data;
+
+ /* In an array indexing context, range arrays have different
+ * semantics. Consider a[[0:10]]. Clearly this means elements
+ * 0-10 of a. But what does a[[0:-1]] mean? By itself,
+ * [0:-1] is a null matrix []. But, it is useful in an
+ * indexing context to allow -1 to refer to the last element
+ * of the array. Similarly, [-3:-1] refers to the last 3
+ * elements.
+ *
+ * However, [-1:-3] does not refer to any of the elements.
+ */
+ if ((first_index = r->first_index) < 0)
+ {
+ if (at_dims_i != 0)
+ first_index = (at_dims_i + first_index) % at_dims_i;
+ }
+
+ if ((last_index = r->last_index) < 0)
+ {
+ if (at_dims_i != 0)
+ last_index = (at_dims_i + last_index) % at_dims_i;
+ }
+
+ delta = r->delta;
+
+ range_delta_buf [i] = delta;
+ range_buf[i] = first_index;
+
+ if (delta > 0)
+ {
+ if (first_index > last_index)
+ max_dims[i] = min_index = max_index = 0;
+ else
+ {
+ max_index = min_index = first_index;
+ while (max_index + delta <= last_index)
+ max_index += delta;
+ max_dims [i] = 1 + (max_index - min_index) / delta;
+ }
+ }
+ else
+ {
+ if (first_index < last_index)
+ max_dims[i] = min_index = max_index = 0;
+ else
+ {
+ min_index = max_index = first_index;
+ while (min_index + delta >= last_index)
+ min_index += delta;
+ max_dims [i] = 1 + (max_index - min_index) / (-delta);
+ }
+ }
+ }
+ else
+ {
+ int *tmp, *tmp_max;
+
+ if (0 == (max_dims[i] = ind_at->num_elements))
+ {
+ total_num_elements = 0;
+ break;
+ }
+
+ tmp = (int *) ind_at->data;
+ tmp_max = tmp + ind_at->num_elements;
+ index_data [i] = tmp;
+
+ min_index = max_index = *tmp;
+ while (tmp < tmp_max)
+ {
+ if (max_index > *tmp)
+ max_index = *tmp;
+ if (min_index < *tmp)
+ min_index = *tmp;
+
+ tmp++;
+ }
+ }
+ }
+
+ if ((at_dims_i == 0) && (max_dims[i] == 0))
+ {
+ total_num_elements = 0;
+ continue;
+ }
+
+ if (max_index < 0)
+ max_index += at_dims_i;
+ if (min_index < 0)
+ min_index += at_dims_i;
+
+ if ((min_index < 0) || (min_index >= at_dims_i)
+ || (max_index < 0) || (max_index >= at_dims_i))
+ {
+ SLang_verror (SL_INVALID_PARM, "Array index %u ([%d:%d]) out of allowed range [0->%d]",
+ i, min_index, max_index, at_dims_i);
+ return -1;
+ }
+
+ total_num_elements = total_num_elements * max_dims[i];
+ }
+
+ *num_elements = total_num_elements;
+ return 0;
+}
+
+/* This routine pushes a 1-d vector of values from 'at' indexed by
+ * the objects 'index_objs'. These objects can either be integers or
+ * 1-d integer arrays. The fact that the 1-d arrays can be ranges
+ * makes this look ugly.
+ */
+static int
+aget_from_indices (SLang_Array_Type *at,
+ SLang_Object_Type *index_objs, unsigned int num_indices)
+{
+ int *index_data [SLARRAY_MAX_DIMS];
+ int range_buf [SLARRAY_MAX_DIMS];
+ int range_delta_buf [SLARRAY_MAX_DIMS];
+ int max_dims [SLARRAY_MAX_DIMS];
+ unsigned int i, num_elements;
+ SLang_Array_Type *new_at;
+ int map_indices[SLARRAY_MAX_DIMS];
+ int indices [SLARRAY_MAX_DIMS];
+ unsigned int sizeof_type;
+ int is_ptr, ret, is_array;
+ char *new_data;
+ SLang_Class_Type *cl;
+ int is_dim_array[SLARRAY_MAX_DIMS];
+
+ if (-1 == convert_nasty_index_objs (at, index_objs, num_indices,
+ index_data, range_buf, range_delta_buf,
+ max_dims, &num_elements, &is_array,
+ is_dim_array))
+ return -1;
+
+ is_ptr = (at->flags & SLARR_DATA_VALUE_IS_POINTER);
+ sizeof_type = at->sizeof_type;
+
+ cl = _SLclass_get_class (at->data_type);
+
+ if ((is_array == 0) && (num_elements == 1))
+ {
+ new_data = (char *)cl->cl_transfer_buf;
+ memset (new_data, 0, sizeof_type);
+ new_at = NULL;
+ }
+ else
+ {
+ int i_num_elements = (int)num_elements;
+
+ new_at = SLang_create_array (at->data_type, 0, NULL, &i_num_elements, 1);
+ if (NULL == new_at)
+ return -1;
+ if (num_elements == 0)
+ return SLang_push_array (new_at, 1);
+
+ new_data = (char *)new_at->data;
+ }
+
+ SLMEMSET((char *) map_indices, 0, sizeof(map_indices));
+ do
+ {
+ for (i = 0; i < num_indices; i++)
+ {
+ int j;
+
+ j = map_indices[i];
+
+ if (0 != range_delta_buf[i])
+ indices[i] = range_buf[i] + j * range_delta_buf[i];
+ else
+ indices[i] = index_data [i][j];
+ }
+
+ if (-1 == _SLarray_aget_transfer_elem (at, indices, (VOID_STAR)new_data, sizeof_type, is_ptr))
+ {
+ SLang_free_array (new_at);
+ return -1;
+ }
+ new_data += sizeof_type;
+ }
+ while (0 == next_index (map_indices, max_dims, num_indices));
+
+ if (new_at != NULL)
+ {
+ int num_dims = 0;
+ /* Fixup dimensions on array */
+ for (i = 0; i < num_indices; i++)
+ {
+ if (is_dim_array[i]) /* was: (max_dims[i] > 1) */
+ {
+ new_at->dims[num_dims] = max_dims[i];
+ num_dims++;
+ }
+ }
+
+ if (num_dims != 0) new_at->num_dims = num_dims;
+ return SLang_push_array (new_at, 1);
+ }
+
+ /* Here new_data is a whole new copy, so free it after the push */
+ new_data -= sizeof_type;
+ if (is_ptr && (*(VOID_STAR *)new_data == NULL))
+ ret = SLang_push_null ();
+ else
+ {
+ ret = (*cl->cl_apush) (at->data_type, (VOID_STAR)new_data);
+ (*cl->cl_adestroy) (at->data_type, (VOID_STAR)new_data);
+ }
+
+ return ret;
+}
+
+static int push_string_as_array (unsigned char *s, unsigned int len)
+{
+ int ilen;
+ SLang_Array_Type *at;
+
+ ilen = (int) len;
+
+ at = SLang_create_array (SLANG_UCHAR_TYPE, 0, NULL, &ilen, 1);
+ if (at == NULL)
+ return -1;
+
+ memcpy ((char *)at->data, (char *)s, len);
+ return SLang_push_array (at, 1);
+}
+
+static int pop_array_as_string (char **sp)
+{
+ SLang_Array_Type *at;
+ int ret;
+
+ *sp = NULL;
+
+ if (-1 == SLang_pop_array_of_type (&at, SLANG_UCHAR_TYPE))
+ return -1;
+
+ ret = 0;
+
+ if (NULL == (*sp = SLang_create_nslstring ((char *) at->data, at->num_elements)))
+ ret = -1;
+
+ SLang_free_array (at);
+ return ret;
+}
+
+static int pop_array_as_bstring (SLang_BString_Type **bs)
+{
+ SLang_Array_Type *at;
+ int ret;
+
+ *bs = NULL;
+
+ if (-1 == SLang_pop_array_of_type (&at, SLANG_UCHAR_TYPE))
+ return -1;
+
+ ret = 0;
+
+ if (NULL == (*bs = SLbstring_create ((unsigned char *) at->data, at->num_elements)))
+ ret = -1;
+
+ SLang_free_array (at);
+ return ret;
+}
+
+static int aget_from_array (unsigned int num_indices)
+{
+ SLang_Array_Type *at;
+ SLang_Object_Type index_objs [SLARRAY_MAX_DIMS];
+ int ret;
+ int is_index_array;
+ unsigned int i;
+
+ if (num_indices > SLARRAY_MAX_DIMS)
+ {
+ SLang_verror (SL_INVALID_PARM, "Number of dims must be less than %d", SLARRAY_MAX_DIMS);
+ return -1;
+ }
+
+ if (-1 == pop_array (&at, 1))
+ return -1;
+
+ if (-1 == pop_indices (index_objs, num_indices, &is_index_array))
+ {
+ SLang_free_array (at);
+ return -1;
+ }
+
+ if (is_index_array == 0)
+ ret = aget_from_indices (at, index_objs, num_indices);
+ else
+ ret = aget_from_index_array (at, index_objs[0].v.array_val);
+
+ SLang_free_array (at);
+ for (i = 0; i < num_indices; i++)
+ SLang_free_object (index_objs + i);
+
+ return ret;
+}
+
+static int push_string_element (unsigned char type, unsigned char *s, unsigned int len)
+{
+ int i;
+
+ if (SLang_peek_at_stack () == SLANG_ARRAY_TYPE)
+ {
+ char *str;
+
+ /* The indices are array values. So, do this: */
+ if (-1 == push_string_as_array (s, len))
+ return -1;
+
+ if (-1 == aget_from_array (1))
+ return -1;
+
+ if (type == SLANG_BSTRING_TYPE)
+ {
+ SLang_BString_Type *bs;
+ int ret;
+
+ if (-1 == pop_array_as_bstring (&bs))
+ return -1;
+
+ ret = SLang_push_bstring (bs);
+ SLbstring_free (bs);
+ return ret;
+ }
+
+ if (-1 == pop_array_as_string (&str))
+ return -1;
+ return _SLang_push_slstring (str); /* frees s upon error */
+ }
+
+ if (-1 == SLang_pop_integer (&i))
+ return -1;
+
+ if (i < 0) i = i + (int)len;
+ if ((unsigned int) i > len)
+ i = len; /* get \0 character --- bstrings include it as well */
+
+ i = s[(unsigned int) i];
+
+ return SLang_push_integer (i);
+}
+
+/* ARRAY[i, j, k] generates code: __args i j ...k ARRAY __aput/__aget
+ * Here i, j, ... k may be a mixture of integers and 1-d arrays, or
+ * a single 2-d array of indices. The 2-d index array is generated by the
+ * 'where' function.
+ *
+ * If ARRAY is of type DataType, then this function will create an array of
+ * the appropriate type. In that case, the indices i, j, ..., k must be
+ * integers.
+ */
+int _SLarray_aget (void)
+{
+ unsigned int num_indices;
+ int type;
+ int (*aget_fun) (unsigned char, unsigned int);
+
+ num_indices = (SLang_Num_Function_Args - 1);
+
+ type = SLang_peek_at_stack ();
+ switch (type)
+ {
+ case -1:
+ return -1; /* stack underflow */
+
+ case SLANG_DATATYPE_TYPE:
+ return push_create_new_array ();
+
+ case SLANG_BSTRING_TYPE:
+ if (1 == num_indices)
+ {
+ SLang_BString_Type *bs;
+ int ret;
+ unsigned int len;
+ unsigned char *s;
+
+ if (-1 == SLang_pop_bstring (&bs))
+ return -1;
+
+ if (NULL == (s = SLbstring_get_pointer (bs, &len)))
+ ret = -1;
+ else
+ ret = push_string_element (type, s, len);
+
+ SLbstring_free (bs);
+ return ret;
+ }
+ break;
+
+ case SLANG_STRING_TYPE:
+ if (1 == num_indices)
+ {
+ char *s;
+ int ret;
+
+ if (-1 == SLang_pop_slstring (&s))
+ return -1;
+
+ ret = push_string_element (type, (unsigned char *)s, strlen (s));
+ SLang_free_slstring (s);
+ return ret;
+ }
+ break;
+
+ case SLANG_ARRAY_TYPE:
+ break;
+
+ default:
+ aget_fun = _SLclass_get_class (type)->cl_aget;
+ if (NULL != aget_fun)
+ return (*aget_fun) (type, num_indices);
+ }
+
+ return aget_from_array (num_indices);
+}
+
+int
+_SLarray_aput_transfer_elem (SLang_Array_Type *at, int *indices,
+ VOID_STAR data_to_put, unsigned int sizeof_type, int is_ptr)
+{
+ VOID_STAR at_data;
+
+ /* Since 1 element is being transferred, there is no need to coerse
+ * the array to linear.
+ */
+ if (NULL == (at_data = get_data_addr (at, indices)))
+ return -1;
+
+ return transfer_n_elements (at, at_data, data_to_put, sizeof_type, 1, is_ptr);
+}
+
+static int
+aput_get_array_to_put (SLang_Class_Type *cl, unsigned int num_elements, int allow_array,
+ SLang_Array_Type **at_ptr, char **data_to_put, unsigned int *data_increment)
+{
+ unsigned char data_type;
+ SLang_Array_Type *at;
+
+ *at_ptr = NULL;
+
+ data_type = cl->cl_data_type;
+ if (-1 == SLclass_typecast (data_type, 1, allow_array))
+ return -1;
+
+ if ((data_type != SLANG_ARRAY_TYPE)
+ && (data_type != SLANG_ANY_TYPE)
+ && (SLANG_ARRAY_TYPE == SLang_peek_at_stack ()))
+ {
+ if (-1 == SLang_pop_array (&at, 0))
+ return -1;
+
+ if ((at->num_elements != num_elements)
+#if 0
+ || (at->num_dims != 1)
+#endif
+ )
+ {
+ SLang_verror (SL_TYPE_MISMATCH, "Array size is inappropriate for use with index-array");
+ SLang_free_array (at);
+ return -1;
+ }
+
+ *data_to_put = (char *) at->data;
+ *data_increment = at->sizeof_type;
+ *at_ptr = at;
+ return 0;
+ }
+
+ *data_increment = 0;
+ *data_to_put = (char *) cl->cl_transfer_buf;
+
+ if (-1 == (*cl->cl_apop)(data_type, (VOID_STAR) *data_to_put))
+ return -1;
+
+ return 0;
+}
+
+static int
+aput_from_indices (SLang_Array_Type *at,
+ SLang_Object_Type *index_objs, unsigned int num_indices)
+{
+ int *index_data [SLARRAY_MAX_DIMS];
+ int range_buf [SLARRAY_MAX_DIMS];
+ int range_delta_buf [SLARRAY_MAX_DIMS];
+ int max_dims [SLARRAY_MAX_DIMS];
+ unsigned int i, num_elements;
+ SLang_Array_Type *bt;
+ int map_indices[SLARRAY_MAX_DIMS];
+ int indices [SLARRAY_MAX_DIMS];
+ unsigned int sizeof_type;
+ int is_ptr, is_array, ret;
+ char *data_to_put;
+ unsigned int data_increment;
+ SLang_Class_Type *cl;
+ int is_dim_array [SLARRAY_MAX_DIMS];
+
+ if (-1 == convert_nasty_index_objs (at, index_objs, num_indices,
+ index_data, range_buf, range_delta_buf,
+ max_dims, &num_elements, &is_array,
+ is_dim_array))
+ return -1;
+
+ cl = at->cl;
+
+ if (-1 == aput_get_array_to_put (cl, num_elements, is_array,
+ &bt, &data_to_put, &data_increment))
+ return -1;
+
+ sizeof_type = at->sizeof_type;
+ is_ptr = (at->flags & SLARR_DATA_VALUE_IS_POINTER);
+
+ ret = -1;
+
+ SLMEMSET((char *) map_indices, 0, sizeof(map_indices));
+ if (num_elements) do
+ {
+ for (i = 0; i < num_indices; i++)
+ {
+ int j;
+
+ j = map_indices[i];
+
+ if (0 != range_delta_buf[i])
+ indices[i] = range_buf[i] + j * range_delta_buf[i];
+ else
+ indices[i] = index_data [i][j];
+ }
+
+ if (-1 == _SLarray_aput_transfer_elem (at, indices, (VOID_STAR)data_to_put, sizeof_type, is_ptr))
+ goto return_error;
+
+ data_to_put += data_increment;
+ }
+ while (0 == next_index (map_indices, max_dims, num_indices));
+
+ ret = 0;
+
+ /* drop */
+
+ return_error:
+ if (bt == NULL)
+ {
+ if (is_ptr)
+ (*cl->cl_destroy) (cl->cl_data_type, (VOID_STAR) data_to_put);
+ }
+ else SLang_free_array (bt);
+
+ return ret;
+}
+
+static int
+aput_from_index_array (SLang_Array_Type *at, SLang_Array_Type *ind_at)
+{
+ int *indices, *indices_max;
+ unsigned int sizeof_type;
+ char *data_to_put, *dest_data;
+ unsigned int data_increment;
+ int is_ptr;
+ SLang_Array_Type *bt;
+ SLang_Class_Type *cl;
+ int ret;
+
+ if (-1 == coerse_array_to_linear (at))
+ return -1;
+
+ if (-1 == coerse_array_to_linear (ind_at))
+ return -1;
+
+ if (-1 == check_index_array_ranges (at, ind_at))
+ return -1;
+
+ sizeof_type = at->sizeof_type;
+
+ cl = at->cl;
+
+ /* Note that if bt is returned as non NULL, then the array is a linear
+ * one.
+ */
+ if (-1 == aput_get_array_to_put (cl, ind_at->num_elements, 1,
+ &bt, &data_to_put, &data_increment))
+ return -1;
+
+ /* Since the index array is linear, I can address it directly */
+ indices = (int *) ind_at->data;
+ indices_max = indices + ind_at->num_elements;
+
+ is_ptr = (at->flags & SLARR_DATA_VALUE_IS_POINTER);
+ dest_data = (char *) at->data;
+
+ ret = -1;
+ while (indices < indices_max)
+ {
+ unsigned int offset;
+
+ offset = sizeof_type * (unsigned int)*indices;
+
+ if (-1 == transfer_n_elements (at, (VOID_STAR) (dest_data + offset),
+ (VOID_STAR) data_to_put, sizeof_type, 1,
+ is_ptr))
+ goto return_error;
+
+ indices++;
+ data_to_put += data_increment;
+ }
+
+ ret = 0;
+ /* Drop */
+
+ return_error:
+
+ if (bt == NULL)
+ {
+ if (is_ptr)
+ (*cl->cl_destroy) (cl->cl_data_type, (VOID_STAR)data_to_put);
+ }
+ else SLang_free_array (bt);
+
+ return ret;
+}
+
+/* ARRAY[i, j, k] = generates code: __args i j k ARRAY __aput
+ */
+int _SLarray_aput (void)
+{
+ unsigned int num_indices;
+ SLang_Array_Type *at;
+ SLang_Object_Type index_objs [SLARRAY_MAX_DIMS];
+ int ret;
+ int is_index_array;
+ int (*aput_fun) (unsigned char, unsigned int);
+ int type;
+
+ ret = -1;
+ num_indices = (SLang_Num_Function_Args - 1);
+
+ type = SLang_peek_at_stack ();
+ switch (type)
+ {
+ case -1:
+ return -1;
+
+ case SLANG_ARRAY_TYPE:
+ break;
+
+ default:
+ if (NULL != (aput_fun = _SLclass_get_class (type)->cl_aput))
+ return (*aput_fun) (type, num_indices);
+ break;
+ }
+
+ if (-1 == SLang_pop_array (&at, 0))
+ return -1;
+
+ if (at->flags & SLARR_DATA_VALUE_IS_READ_ONLY)
+ {
+ SLang_verror (SL_READONLY_ERROR, "%s Array is read-only",
+ SLclass_get_datatype_name (at->data_type));
+ SLang_free_array (at);
+ return -1;
+ }
+
+ if (-1 == pop_indices (index_objs, num_indices, &is_index_array))
+ {
+ SLang_free_array (at);
+ return -1;
+ }
+
+ if (is_index_array == 0)
+ ret = aput_from_indices (at, index_objs, num_indices);
+ else
+ ret = aput_from_index_array (at, index_objs[0].v.array_val);
+
+ SLang_free_array (at);
+ free_index_objects (index_objs, num_indices);
+ return ret;
+}
+
+/* This is for 1-d matrices only. It is used by the sort function */
+static int push_element_at_index (SLang_Array_Type *at, int indx)
+{
+ VOID_STAR data;
+
+ if (NULL == (data = get_data_addr (at, &indx)))
+ return -1;
+
+ return push_element_at_addr (at, (VOID_STAR) data, 1);
+}
+
+static SLang_Name_Type *Sort_Function;
+static SLang_Array_Type *Sort_Array;
+
+static int sort_cmp_fun (int *a, int *b)
+{
+ int cmp;
+
+ if (SLang_Error
+ || (-1 == push_element_at_index (Sort_Array, *a))
+ || (-1 == push_element_at_index (Sort_Array, *b))
+ || (-1 == SLexecute_function (Sort_Function))
+ || (-1 == SLang_pop_integer (&cmp)))
+ {
+ /* DO not allow qsort to loop forever. Return something meaningful */
+ if (*a > *b) return 1;
+ if (*a < *b) return -1;
+ return 0;
+ }
+
+ return cmp;
+}
+
+static int builtin_sort_cmp_fun (int *a, int *b)
+{
+ VOID_STAR a_data;
+ VOID_STAR b_data;
+ SLang_Class_Type *cl;
+
+ cl = Sort_Array->cl;
+
+ if ((SLang_Error == 0)
+ && (NULL != (a_data = get_data_addr (Sort_Array, a)))
+ && (NULL != (b_data = get_data_addr (Sort_Array, b))))
+ {
+ int cmp;
+
+ if ((Sort_Array->flags & SLARR_DATA_VALUE_IS_POINTER)
+ && ((*(VOID_STAR *) a_data == NULL) || (*(VOID_STAR *) a_data == NULL)))
+ {
+ SLang_verror (SL_VARIABLE_UNINITIALIZED,
+ "%s array has unitialized element", cl->cl_name);
+ }
+ else if (0 == (*cl->cl_cmp)(Sort_Array->data_type, a_data, b_data, &cmp))
+ return cmp;
+ }
+
+
+ if (*a > *b) return 1;
+ if (*a == *b) return 0;
+ return -1;
+}
+
+static void sort_array_internal (SLang_Array_Type *at_str,
+ SLang_Name_Type *entry,
+ int (*sort_fun)(int *, int *))
+{
+ SLang_Array_Type *ind_at;
+ /* This is a silly hack to make up for braindead compilers and the lack of
+ * uniformity in prototypes for qsort.
+ */
+ void (*qsort_fun) (char *, unsigned int, int, int (*)(int *, int *));
+ int *indx;
+ int i, n;
+ int dims[1];
+
+ if (Sort_Array != NULL)
+ {
+ SLang_verror (SL_NOT_IMPLEMENTED, "array_sort is not recursive");
+ return;
+ }
+
+ n = at_str->num_elements;
+
+ if (at_str->num_dims != 1)
+ {
+ SLang_verror (SL_INVALID_PARM, "sort is restricted to 1 dim arrays");
+ return;
+ }
+
+ dims [0] = n;
+
+ if (NULL == (ind_at = SLang_create_array (SLANG_INT_TYPE, 0, NULL, dims, 1)))
+ return;
+
+ indx = (int *) ind_at->data;
+ for (i = 0; i < n; i++) indx[i] = i;
+
+ if (n > 1)
+ {
+ qsort_fun = (void (*)(char *, unsigned int, int, int (*)(int *,
+ int *)))
+ qsort;
+
+ Sort_Array = at_str;
+ Sort_Function = entry;
+ (*qsort_fun) ((char *) indx, n, sizeof (int), sort_fun);
+ }
+
+ Sort_Array = NULL;
+ (void) SLang_push_array (ind_at, 1);
+}
+
+static void sort_array (void)
+{
+ SLang_Name_Type *entry;
+ SLang_Array_Type *at;
+ int (*sort_fun) (int *, int *);
+
+ if (SLang_Num_Function_Args != 1)
+ {
+ sort_fun = sort_cmp_fun;
+
+ if (NULL == (entry = SLang_pop_function ()))
+ return;
+
+ if (-1 == SLang_pop_array (&at, 1))
+ return;
+ }
+ else
+ {
+ sort_fun = builtin_sort_cmp_fun;
+ if (-1 == SLang_pop_array (&at, 1))
+ return;
+ if (at->cl->cl_cmp == NULL)
+ {
+ SLang_verror (SL_NOT_IMPLEMENTED,
+ "%s does not have a predefined sorting method",
+ at->cl->cl_name);
+ SLang_free_array (at);
+ return;
+ }
+ entry = NULL;
+ }
+
+ sort_array_internal (at, entry, sort_fun);
+ SLang_free_array (at);
+ SLang_free_function (entry);
+}
+
+static void bstring_to_array (SLang_BString_Type *bs)
+{
+ unsigned char *s;
+ unsigned int len;
+
+ if (NULL == (s = SLbstring_get_pointer (bs, &len)))
+ (void) SLang_push_null ();
+ else
+ (void) push_string_as_array (s, len);
+}
+
+static void array_to_bstring (SLang_Array_Type *at)
+{
+ unsigned int nbytes;
+ SLang_BString_Type *bs;
+
+ nbytes = at->num_elements * at->sizeof_type;
+ bs = SLbstring_create ((unsigned char *)at->data, nbytes);
+ (void) SLang_push_bstring (bs);
+ SLbstring_free (bs);
+}
+
+static void init_char_array (void)
+{
+ SLang_Array_Type *at;
+ char *s;
+ unsigned int n, ndim;
+
+ if (SLang_pop_slstring (&s)) return;
+
+ if (-1 == SLang_pop_array (&at, 0))
+ goto free_and_return;
+
+ if (at->data_type != SLANG_CHAR_TYPE)
+ {
+ SLang_doerror("Operation requires character array");
+ goto free_and_return;
+ }
+
+ n = strlen (s);
+ ndim = at->num_elements;
+ if (n > ndim)
+ {
+ SLang_doerror("String too big to init array");
+ goto free_and_return;
+ }
+
+ strncpy((char *) at->data, s, ndim);
+ /* drop */
+
+ free_and_return:
+ SLang_free_array (at);
+ SLang_free_slstring (s);
+}
+
+static void array_info (void)
+{
+ SLang_Array_Type *at, *bt;
+ int num_dims;
+
+ if (-1 == pop_array (&at, 1))
+ return;
+
+ num_dims = (int)at->num_dims;
+
+ if (NULL != (bt = SLang_create_array (SLANG_INT_TYPE, 0, NULL, &num_dims, 1)))
+ {
+ int *bdata;
+ int i;
+ int *a_dims;
+
+ a_dims = at->dims;
+ bdata = (int *) bt->data;
+ for (i = 0; i < num_dims; i++) bdata [i] = a_dims [i];
+
+ if (0 == SLang_push_array (bt, 1))
+ {
+ (void) SLang_push_integer ((int) at->num_dims);
+ (void) _SLang_push_datatype (at->data_type);
+ }
+ }
+
+ SLang_free_array (at);
+}
+
+static VOID_STAR range_get_data_addr (SLang_Array_Type *at, int *dims)
+{
+ static int value;
+ SLarray_Range_Array_Type *r;
+ int d;
+
+ d = *dims;
+ r = (SLarray_Range_Array_Type *)at->data;
+
+ if (d < 0)
+ d += at->dims[0];
+
+ value = r->first_index + d * r->delta;
+ return (VOID_STAR) &value;
+}
+
+static SLang_Array_Type *inline_implicit_int_array (int *xminptr, int *xmaxptr, int *dxptr)
+{
+ int delta;
+ SLang_Array_Type *at;
+ int dims, idims;
+ SLarray_Range_Array_Type *data;
+
+ if (dxptr == NULL) delta = 1;
+ else delta = *dxptr;
+
+ if (delta == 0)
+ {
+ SLang_verror (SL_INVALID_PARM, "range-array increment must be non-zero");
+ return NULL;
+ }
+
+ data = (SLarray_Range_Array_Type *) SLmalloc (sizeof (SLarray_Range_Array_Type));
+ if (data == NULL)
+ return NULL;
+
+ SLMEMSET((char *) data, 0, sizeof (SLarray_Range_Array_Type));
+ data->delta = delta;
+ dims = 0;
+
+ if (xminptr != NULL)
+ data->first_index = *xminptr;
+ else
+ data->first_index = 0;
+
+ if (xmaxptr != NULL)
+ data->last_index = *xmaxptr;
+ else
+ data->last_index = -1;
+
+/* if ((xminptr != NULL) && (xmaxptr != NULL))
+ { */
+ idims = 1 + (data->last_index - data->first_index) / delta;
+ if (idims > 0)
+ dims = idims;
+ /* } */
+
+ if (NULL == (at = SLang_create_array (SLANG_INT_TYPE, 0, (VOID_STAR) data, &dims, 1)))
+ return NULL;
+
+ at->index_fun = range_get_data_addr;
+ at->flags |= SLARR_DATA_VALUE_IS_RANGE;
+
+ return at;
+}
+
+#if SLANG_HAS_FLOAT
+static SLang_Array_Type *inline_implicit_floating_array (unsigned char type,
+ double *xminptr, double *xmaxptr, double *dxptr)
+{
+ int n, i;
+ SLang_Array_Type *at;
+ int dims;
+ double xmin, xmax, dx;
+
+ if ((xminptr == NULL) || (xmaxptr == NULL))
+ {
+ SLang_verror (SL_INVALID_PARM, "range-array has unknown size");
+ return NULL;
+ }
+ xmin = *xminptr;
+ xmax = *xmaxptr;
+ if (dxptr == NULL) dx = 1.0;
+ else dx = *dxptr;
+
+ if (dx == 0.0)
+ {
+ SLang_doerror ("range-array increment must be non-zero");
+ return NULL;
+ }
+
+ /* I have convinced myself that it is better to use semi-open intervals
+ * because of less ambiguities. So, [a:b:c] will represent the set of
+ * values a, a + c, a + 2c ... a + nc
+ * such that a + nc < b. That is, b lies outside the interval.
+ */
+
+ /* Allow for roundoff by adding 0.5 before truncation */
+ n = (int)(1.5 + ((xmax - xmin) / dx));
+ if (n <= 0)
+ n = 0;
+ else
+ {
+ double last = xmin + (n-1) * dx;
+
+ if (dx > 0.0)
+ {
+ if (last >= xmax)
+ n -= 1;
+ }
+ else if (last <= xmax)
+ n -= 1;
+ }
+
+ dims = n;
+ if (NULL == (at = SLang_create_array1 (type, 0, NULL, &dims, 1, 1)))
+ return NULL;
+
+ if (type == SLANG_DOUBLE_TYPE)
+ {
+ double *ptr;
+
+ ptr = (double *) at->data;
+
+ for (i = 0; i < n; i++)
+ ptr[i] = xmin + i * dx;
+ }
+ else
+ {
+ float *ptr;
+
+ ptr = (float *) at->data;
+
+ for (i = 0; i < n; i++)
+ ptr[i] = (float) (xmin + i * dx);
+ }
+ return at;
+}
+#endif
+
+/* FIXME: Priority=medium
+ * This needs to be updated to work with all integer types.
+ */
+int _SLarray_inline_implicit_array (void)
+{
+ int int_vals[3];
+#if SLANG_HAS_FLOAT
+ double double_vals[3];
+#endif
+ int has_vals[3];
+ unsigned int i, count;
+ SLang_Array_Type *at;
+ int precedence;
+ unsigned char type;
+ int is_int;
+
+ count = SLang_Num_Function_Args;
+
+ if (count == 2)
+ has_vals [2] = 0;
+ else if (count != 3)
+ {
+ SLang_doerror ("wrong number of arguments to __implicit_inline_array");
+ return -1;
+ }
+
+#if SLANG_HAS_FLOAT
+ is_int = 1;
+#endif
+
+ type = 0;
+ precedence = 0;
+
+ i = count;
+ while (i--)
+ {
+ int this_type, this_precedence;
+
+ if (-1 == (this_type = SLang_peek_at_stack ()))
+ return -1;
+
+ this_precedence = _SLarith_get_precedence ((unsigned char) this_type);
+ if (precedence < this_precedence)
+ {
+ type = (unsigned char) this_type;
+ precedence = this_precedence;
+ }
+
+ has_vals [i] = 1;
+
+ switch (this_type)
+ {
+ case SLANG_NULL_TYPE:
+ has_vals[i] = 0;
+ (void) SLdo_pop ();
+ break;
+
+#if SLANG_HAS_FLOAT
+ case SLANG_DOUBLE_TYPE:
+ case SLANG_FLOAT_TYPE:
+ if (-1 == SLang_pop_double (double_vals + i, NULL, NULL))
+ return -1;
+ is_int = 0;
+ break;
+#endif
+ default:
+ if (-1 == SLang_pop_integer (int_vals + i))
+ return -1;
+ double_vals[i] = (double) int_vals[i];
+ }
+ }
+
+#if SLANG_HAS_FLOAT
+ if (is_int == 0)
+ at = inline_implicit_floating_array (type,
+ (has_vals[0] ? &double_vals[0] : NULL),
+ (has_vals[1] ? &double_vals[1] : NULL),
+ (has_vals[2] ? &double_vals[2] : NULL));
+ else
+#endif
+ at = inline_implicit_int_array ((has_vals[0] ? &int_vals[0] : NULL),
+ (has_vals[1] ? &int_vals[1] : NULL),
+ (has_vals[2] ? &int_vals[2] : NULL));
+
+ if (at == NULL)
+ return -1;
+
+ return SLang_push_array (at, 1);
+}
+
+int _SLarray_wildcard_array (void)
+{
+ SLang_Array_Type *at;
+
+ if (NULL == (at = inline_implicit_int_array (NULL, NULL, NULL)))
+ return -1;
+
+ return SLang_push_array (at, 1);
+}
+
+static SLang_Array_Type *concat_arrays (unsigned int count)
+{
+ SLang_Array_Type **arrays;
+ SLang_Array_Type *at, *bt;
+ unsigned int i;
+ int num_elements;
+ unsigned char type;
+ char *src_data, *dest_data;
+ int is_ptr;
+ unsigned int sizeof_type;
+ int max_dims, min_dims, max_rows, min_rows;
+
+ arrays = (SLang_Array_Type **)SLmalloc (count * sizeof (SLang_Array_Type *));
+ if (arrays == NULL)
+ {
+ SLdo_pop_n (count);
+ return NULL;
+ }
+ SLMEMSET((char *) arrays, 0, count * sizeof(SLang_Array_Type *));
+
+ at = NULL;
+
+ num_elements = 0;
+ i = count;
+
+ while (i != 0)
+ {
+ i--;
+
+ if (-1 == SLang_pop_array (&bt, 1))
+ goto free_and_return;
+
+ arrays[i] = bt;
+ num_elements += (int)bt->num_elements;
+ }
+
+ type = arrays[0]->data_type;
+ max_dims = min_dims = arrays[0]->num_dims;
+ min_rows = max_rows = arrays[0]->dims[0];
+
+ for (i = 1; i < count; i++)
+ {
+ SLang_Array_Type *ct;
+ int num;
+
+ bt = arrays[i];
+
+ num = bt->num_dims;
+ if (num > max_dims) max_dims = num;
+ if (num < min_dims) min_dims = num;
+
+ num = bt->dims[0];
+ if (num > max_rows) max_rows = num;
+ if (num < min_rows) min_rows = num;
+
+ if (type == bt->data_type)
+ continue;
+
+ if (1 != _SLarray_typecast (bt->data_type, (VOID_STAR) &bt, 1,
+ type, (VOID_STAR) &ct, 1))
+ goto free_and_return;
+
+ SLang_free_array (bt);
+ arrays [i] = ct;
+ }
+
+ if (NULL == (at = SLang_create_array (type, 0, NULL, &num_elements, 1)))
+ goto free_and_return;
+
+ is_ptr = (at->flags & SLARR_DATA_VALUE_IS_POINTER);
+ sizeof_type = at->sizeof_type;
+ dest_data = (char *) at->data;
+
+ for (i = 0; i < count; i++)
+ {
+ bt = arrays[i];
+
+ src_data = (char *) bt->data;
+ num_elements = bt->num_elements;
+
+ if (-1 == transfer_n_elements (bt, (VOID_STAR)dest_data, (VOID_STAR)src_data, sizeof_type,
+ num_elements, is_ptr))
+ {
+ SLang_free_array (at);
+ at = NULL;
+ goto free_and_return;
+ }
+
+ dest_data += num_elements * sizeof_type;
+ }
+
+ /* If the arrays are all 1-d, and all the same size, then reshape to a
+ * 2-d array. This will allow us to do, e.g.
+ * a = [[1,2], [3,4]]
+ * to specifiy a 2-d.
+ * Someday I will generalize this.
+ */
+ if ((max_dims == min_dims) && (max_dims == 1) && (min_rows == max_rows))
+ {
+ at->num_dims = 2;
+ at->dims[0] = count;
+ at->dims[1] = min_rows;
+ }
+
+ free_and_return:
+
+ for (i = 0; i < count; i++)
+ SLang_free_array (arrays[i]);
+ SLfree ((char *) arrays);
+
+ return at;
+}
+
+int _SLarray_inline_array (void)
+{
+ SLang_Object_Type *obj;
+ unsigned char type, this_type;
+ unsigned int count;
+ SLang_Array_Type *at;
+
+ obj = _SLStack_Pointer;
+
+ count = SLang_Num_Function_Args;
+ type = 0;
+
+ while ((count > 0) && (--obj >= _SLRun_Stack))
+ {
+ this_type = obj->data_type;
+
+ if (type == 0)
+ type = this_type;
+
+ if ((type == this_type) || (type == SLANG_ARRAY_TYPE))
+ {
+ count--;
+ continue;
+ }
+
+ switch (this_type)
+ {
+ case SLANG_ARRAY_TYPE:
+ type = SLANG_ARRAY_TYPE;
+ break;
+
+ case SLANG_INT_TYPE:
+ switch (type)
+ {
+#if SLANG_HAS_FLOAT
+ case SLANG_DOUBLE_TYPE:
+ break;
+#endif
+#if SLANG_HAS_COMPLEX
+ case SLANG_COMPLEX_TYPE:
+ break;
+#endif
+ default:
+ goto type_mismatch;
+ }
+ break;
+#if SLANG_HAS_FLOAT
+ case SLANG_DOUBLE_TYPE:
+ switch (type)
+ {
+ case SLANG_INT_TYPE:
+ type = SLANG_DOUBLE_TYPE;
+ break;
+# if SLANG_HAS_COMPLEX
+ case SLANG_COMPLEX_TYPE:
+ break;
+# endif
+ default:
+ goto type_mismatch;
+ }
+ break;
+#endif
+#if SLANG_HAS_COMPLEX
+ case SLANG_COMPLEX_TYPE:
+ switch (type)
+ {
+ case SLANG_INT_TYPE:
+ case SLANG_DOUBLE_TYPE:
+ type = SLANG_COMPLEX_TYPE;
+ break;
+
+ default:
+ goto type_mismatch;
+ }
+ break;
+#endif
+ default:
+ type_mismatch:
+ _SLclass_type_mismatch_error (type, this_type);
+ return -1;
+ }
+ count--;
+ }
+
+ if (count != 0)
+ {
+ SLang_Error = SL_STACK_UNDERFLOW;
+ return -1;
+ }
+
+ count = SLang_Num_Function_Args;
+
+ if (count == 0)
+ {
+ SLang_verror (SL_NOT_IMPLEMENTED, "Empty inline-arrays not supported");
+ return -1;
+ }
+
+ if (type == SLANG_ARRAY_TYPE)
+ {
+ if (NULL == (at = concat_arrays (count)))
+ return -1;
+ }
+ else
+ {
+ SLang_Object_Type index_obj;
+ int icount = (int) count;
+
+ if (NULL == (at = SLang_create_array (type, 0, NULL, &icount, 1)))
+ return -1;
+
+ index_obj.data_type = SLANG_INT_TYPE;
+ while (count != 0)
+ {
+ count--;
+ index_obj.v.int_val = (int) count;
+ if (-1 == aput_from_indices (at, &index_obj, 1))
+ {
+ SLang_free_array (at);
+ SLdo_pop_n (count);
+ return -1;
+ }
+ }
+ }
+
+ return SLang_push_array (at, 1);
+}
+
+static int array_binary_op_result (int op, unsigned char a, unsigned char b,
+ unsigned char *c)
+{
+ (void) op;
+ (void) a;
+ (void) b;
+ *c = SLANG_ARRAY_TYPE;
+ return 1;
+}
+
+static int array_binary_op (int op,
+ unsigned char a_type, VOID_STAR ap, unsigned int na,
+ unsigned char b_type, VOID_STAR bp, unsigned int nb,
+ VOID_STAR cp)
+{
+ SLang_Array_Type *at, *bt, *ct;
+ unsigned int i, num_dims;
+ int (*binary_fun) (int,
+ unsigned char, VOID_STAR, unsigned int,
+ unsigned char, VOID_STAR, unsigned int,
+ VOID_STAR);
+ SLang_Class_Type *a_cl, *b_cl, *c_cl;
+ int no_init;
+
+ if (a_type == SLANG_ARRAY_TYPE)
+ {
+ if (na != 1)
+ {
+ SLang_verror (SL_NOT_IMPLEMENTED, "Binary operation on multiple arrays not implemented");
+ return -1;
+ }
+
+ at = *(SLang_Array_Type **) ap;
+ if (-1 == coerse_array_to_linear (at))
+ return -1;
+ ap = at->data;
+ a_type = at->data_type;
+ na = at->num_elements;
+ }
+ else
+ {
+ at = NULL;
+ }
+
+ if (b_type == SLANG_ARRAY_TYPE)
+ {
+ if (nb != 1)
+ {
+ SLang_verror (SL_NOT_IMPLEMENTED, "Binary operation on multiple arrays not implemented");
+ return -1;
+ }
+
+ bt = *(SLang_Array_Type **) bp;
+ if (-1 == coerse_array_to_linear (bt))
+ return -1;
+ bp = bt->data;
+ b_type = bt->data_type;
+ nb = bt->num_elements;
+ }
+ else
+ {
+ bt = NULL;
+ }
+
+ if ((at != NULL) && (bt != NULL))
+ {
+ num_dims = at->num_dims;
+
+ if (num_dims != bt->num_dims)
+ {
+ SLang_verror (SL_TYPE_MISMATCH, "Arrays must have same dim for binary operation");
+ return -1;
+ }
+
+ for (i = 0; i < num_dims; i++)
+ {
+ if (at->dims[i] != bt->dims[i])
+ {
+ SLang_verror (SL_TYPE_MISMATCH, "Arrays must be the same for binary operation");
+ return -1;
+ }
+ }
+ }
+
+ a_cl = _SLclass_get_class (a_type);
+ b_cl = _SLclass_get_class (b_type);
+
+ if (NULL == (binary_fun = _SLclass_get_binary_fun (op, a_cl, b_cl, &c_cl, 1)))
+ return -1;
+
+ no_init = ((c_cl->cl_class_type == SLANG_CLASS_TYPE_SCALAR)
+ || (c_cl->cl_class_type == SLANG_CLASS_TYPE_VECTOR));
+
+ ct = NULL;
+#if _SLANG_USE_TMP_OPTIMIZATION
+ /* If we are dealing with scalar (or vector) objects, and if the object
+ * appears to be owned by the stack, then use it instead of creating a
+ * new version. This can happen with code such as:
+ * @ x = [1,2,3,4];
+ * @ x = __tmp(x) + 1;
+ */
+ if (no_init)
+ {
+ if ((at != NULL)
+ && (at->num_refs == 1)
+ && (at->data_type == c_cl->cl_data_type))
+ {
+ ct = at;
+ ct->num_refs = 2;
+ }
+ else if ((bt != NULL)
+ && (bt->num_refs == 1)
+ && (bt->data_type == c_cl->cl_data_type))
+ {
+ ct = bt;
+ ct->num_refs = 2;
+ }
+ }
+#endif /* _SLANG_USE_TMP_OPTIMIZATION */
+
+ if (ct == NULL)
+ {
+ if (at != NULL) ct = at; else ct = bt;
+ ct = SLang_create_array1 (c_cl->cl_data_type, 0, NULL, ct->dims, ct->num_dims, no_init);
+ if (ct == NULL)
+ return -1;
+ }
+
+
+ if ((na == 0) || (nb == 0) /* allow empty arrays */
+ || (1 == (*binary_fun) (op, a_type, ap, na, b_type, bp, nb, ct->data)))
+ {
+ *(SLang_Array_Type **) cp = ct;
+ return 1;
+ }
+
+ SLang_free_array (ct);
+ return -1;
+}
+
+static void array_where (void)
+{
+ SLang_Array_Type *at, *bt;
+ char *a_data;
+ int *b_data;
+ unsigned int i, num_elements;
+ int b_num;
+
+ if (-1 == SLang_pop_array (&at, 1))
+ return;
+
+ bt = NULL;
+
+ if (at->data_type != SLANG_CHAR_TYPE)
+ {
+ int zero;
+ SLang_Array_Type *tmp_at;
+
+ tmp_at = at;
+ zero = 0;
+ if (1 != array_binary_op (SLANG_NE,
+ SLANG_ARRAY_TYPE, (VOID_STAR) &at, 1,
+ SLANG_CHAR_TYPE, (VOID_STAR) &zero, 1,
+ (VOID_STAR) &tmp_at))
+ goto return_error;
+
+ SLang_free_array (at);
+ at = tmp_at;
+ if (at->data_type != SLANG_CHAR_TYPE)
+ {
+ SLang_Error = SL_TYPE_MISMATCH;
+ goto return_error;
+ }
+ }
+
+ a_data = (char *) at->data;
+ num_elements = at->num_elements;
+
+ b_num = 0;
+ for (i = 0; i < num_elements; i++)
+ if (a_data[i] != 0) b_num++;
+
+ if (NULL == (bt = SLang_create_array1 (SLANG_INT_TYPE, 0, NULL, &b_num, 1, 1)))
+ goto return_error;
+
+ b_data = (int *) bt->data;
+
+ i = 0;
+ while (b_num)
+ {
+ if (a_data[i] != 0)
+ {
+ *b_data++ = i;
+ b_num--;
+ }
+
+ i++;
+ }
+
+ (void) SLang_push_array (bt, 0);
+ /* drop */
+
+ return_error:
+ SLang_free_array (at);
+ SLang_free_array (bt);
+}
+
+static int do_array_reshape (SLang_Array_Type *at, SLang_Array_Type *ind_at)
+{
+ int *dims;
+ unsigned int i, num_dims;
+ unsigned int num_elements;
+
+ if ((ind_at->data_type != SLANG_INT_TYPE)
+ || (ind_at->num_dims != 1))
+ {
+ SLang_verror (SL_TYPE_MISMATCH, "Expecting 1-d integer array");
+ return -1;
+ }
+
+ num_dims = ind_at->num_elements;
+ dims = (int *) ind_at->data;
+
+ num_elements = 1;
+ for (i = 0; i < num_dims; i++)
+ {
+ int d = dims[i];
+ if (d < 0)
+ {
+ SLang_verror (SL_INVALID_PARM, "reshape: dimension is less then 0");
+ return -1;
+ }
+
+ num_elements = (unsigned int) d * num_elements;
+ }
+
+ if ((num_elements != at->num_elements)
+ || (num_dims > SLARRAY_MAX_DIMS))
+ {
+ SLang_verror (SL_INVALID_PARM, "Unable to reshape array to specified size");
+ return -1;
+ }
+
+ for (i = 0; i < num_dims; i++)
+ at->dims [i] = dims[i];
+
+ while (i < SLARRAY_MAX_DIMS)
+ {
+ at->dims [i] = 1;
+ i++;
+ }
+
+ at->num_dims = num_dims;
+ return 0;
+}
+
+static void array_reshape (SLang_Array_Type *at, SLang_Array_Type *ind_at)
+{
+ (void) do_array_reshape (at, ind_at);
+}
+
+static void _array_reshape (SLang_Array_Type *ind_at)
+{
+ SLang_Array_Type *at;
+ SLang_Array_Type *new_at;
+
+ if (-1 == SLang_pop_array (&at, 1))
+ return;
+
+ /* FIXME: Priority=low: duplicate_array could me modified to look at num_refs */
+
+ /* Now try to avoid the overhead of creating a new array if possible */
+ if (at->num_refs == 1)
+ {
+ /* Great, we are the sole owner of this array. */
+ if ((-1 == do_array_reshape (at, ind_at))
+ || (-1 == SLclass_push_ptr_obj (SLANG_ARRAY_TYPE, (VOID_STAR)at)))
+ SLang_free_array (at);
+ return;
+ }
+
+ new_at = SLang_duplicate_array (at);
+ if (new_at != NULL)
+ {
+ if (0 == do_array_reshape (new_at, ind_at))
+ (void) SLang_push_array (new_at, 0);
+
+ SLang_free_array (new_at);
+ }
+ SLang_free_array (at);
+}
+
+typedef struct
+{
+ SLang_Array_Type *at;
+ unsigned int increment;
+ char *addr;
+}
+Map_Arg_Type;
+/* Usage: array_map (Return-Type, func, args,....); */
+static void array_map (void)
+{
+ Map_Arg_Type *args;
+ unsigned int num_args;
+ unsigned int i, i_control;
+ SLang_Name_Type *nt;
+ unsigned int num_elements;
+ SLang_Array_Type *at;
+ char *addr;
+ unsigned char type;
+
+ at = NULL;
+ args = NULL;
+ nt = NULL;
+
+ if (SLang_Num_Function_Args < 3)
+ {
+ SLang_verror (SL_INVALID_PARM,
+ "Usage: array_map (Return-Type, &func, args...)");
+ SLdo_pop_n (SLang_Num_Function_Args);
+ return;
+ }
+
+ num_args = (unsigned int)SLang_Num_Function_Args - 2;
+ args = (Map_Arg_Type *) SLmalloc (num_args * sizeof (Map_Arg_Type));
+ if (args == NULL)
+ {
+ SLdo_pop_n (SLang_Num_Function_Args);
+ return;
+ }
+ memset ((char *) args, 0, num_args * sizeof (Map_Arg_Type));
+ i = num_args;
+ i_control = 0;
+ while (i > 0)
+ {
+ i--;
+ if (-1 == SLang_pop_array (&args[i].at, 1))
+ {
+ SLdo_pop_n (i + 2);
+ goto return_error;
+ }
+ if (args[i].at->num_elements > 1)
+ i_control = i;
+ }
+
+ if (NULL == (nt = SLang_pop_function ()))
+ {
+ SLdo_pop_n (1);
+ goto return_error;
+ }
+
+ num_elements = args[i_control].at->num_elements;
+
+ if (-1 == _SLang_pop_datatype (&type))
+ goto return_error;
+
+ if (type == SLANG_UNDEFINED_TYPE) /* Void_Type */
+ at = NULL;
+ else
+ {
+ at = args[i_control].at;
+
+ if (NULL == (at = SLang_create_array (type, 0, NULL, at->dims, at->num_dims)))
+ goto return_error;
+ }
+
+
+ for (i = 0; i < num_args; i++)
+ {
+ SLang_Array_Type *ati = args[i].at;
+ /* FIXME: Priority = low: The actual dimensions should be compared. */
+ if (ati->num_elements == num_elements)
+ args[i].increment = ati->sizeof_type;
+ /* memset already guarantees increment to be zero */
+
+ if (ati->num_elements == 0)
+ {
+ SLang_verror (0, "array_map: function argument %d of %d is an empty array",
+ i+1, num_args);
+ goto return_error;
+ }
+
+ args[i].addr = (char *) ati->data;
+ }
+
+ if (at == NULL)
+ addr = NULL;
+ else
+ addr = (char *)at->data;
+
+ for (i = 0; i < num_elements; i++)
+ {
+ unsigned int j;
+
+ if (-1 == SLang_start_arg_list ())
+ goto return_error;
+
+ for (j = 0; j < num_args; j++)
+ {
+ if (-1 == push_element_at_addr (args[j].at,
+ (VOID_STAR) args[j].addr,
+ 1))
+ {
+ SLdo_pop_n (j);
+ goto return_error;
+ }
+
+ args[j].addr += args[j].increment;
+ }
+
+ if (-1 == SLang_end_arg_list ())
+ {
+ SLdo_pop_n (num_args);
+ goto return_error;
+ }
+
+ if (-1 == SLexecute_function (nt))
+ goto return_error;
+
+ if (at == NULL)
+ continue;
+
+ if (-1 == at->cl->cl_apop (type, (VOID_STAR) addr))
+ goto return_error;
+
+ addr += at->sizeof_type;
+ }
+
+ if (at != NULL)
+ (void) SLang_push_array (at, 0);
+
+ /* drop */
+
+ return_error:
+ SLang_free_array (at);
+ SLang_free_function (nt);
+ if (args != NULL)
+ {
+ for (i = 0; i < num_args; i++)
+ SLang_free_array (args[i].at);
+
+ SLfree ((char *) args);
+ }
+}
+
+static SLang_Intrin_Fun_Type Array_Table [] =
+{
+ MAKE_INTRINSIC_0("array_map", array_map, SLANG_VOID_TYPE),
+ MAKE_INTRINSIC_0("array_sort", sort_array, SLANG_VOID_TYPE),
+ MAKE_INTRINSIC_1("array_to_bstring", array_to_bstring, SLANG_VOID_TYPE, SLANG_ARRAY_TYPE),
+ MAKE_INTRINSIC_1("bstring_to_array", bstring_to_array, SLANG_VOID_TYPE, SLANG_BSTRING_TYPE),
+ MAKE_INTRINSIC("init_char_array", init_char_array, SLANG_VOID_TYPE, 0),
+ MAKE_INTRINSIC("array_info", array_info, SLANG_VOID_TYPE, 0),
+ MAKE_INTRINSIC("where", array_where, SLANG_VOID_TYPE, 0),
+ MAKE_INTRINSIC_2("reshape", array_reshape, SLANG_VOID_TYPE, SLANG_ARRAY_TYPE, SLANG_ARRAY_TYPE),
+ MAKE_INTRINSIC_1("_reshape", _array_reshape, SLANG_VOID_TYPE, SLANG_ARRAY_TYPE),
+ SLANG_END_INTRIN_FUN_TABLE
+};
+
+static char *array_string (unsigned char type, VOID_STAR v)
+{
+ SLang_Array_Type *at;
+ char buf[512];
+ unsigned int i, num_dims;
+ int *dims;
+
+ at = *(SLang_Array_Type **) v;
+ type = at->data_type;
+ num_dims = at->num_dims;
+ dims = at->dims;
+
+ sprintf (buf, "%s[%d", SLclass_get_datatype_name (type), at->dims[0]);
+
+ for (i = 1; i < num_dims; i++)
+ sprintf (buf + strlen(buf), ",%d", dims[i]);
+ strcat (buf, "]");
+
+ return SLmake_string (buf);
+}
+
+static void array_destroy (unsigned char type, VOID_STAR v)
+{
+ (void) type;
+ SLang_free_array (*(SLang_Array_Type **) v);
+}
+
+static int array_push (unsigned char type, VOID_STAR v)
+{
+ SLang_Array_Type *at;
+
+ (void) type;
+ at = *(SLang_Array_Type **) v;
+ return SLang_push_array (at, 0);
+}
+
+/* Intrinsic arrays are not stored in a variable. So, the address that
+ * would contain the variable holds the array address.
+ */
+static int array_push_intrinsic (unsigned char type, VOID_STAR v)
+{
+ (void) type;
+ return SLang_push_array ((SLang_Array_Type *) v, 0);
+}
+
+int _SLarray_add_bin_op (unsigned char type)
+{
+ SL_OOBinary_Type *ab;
+ SLang_Class_Type *cl;
+
+ cl = _SLclass_get_class (type);
+ ab = cl->cl_binary_ops;
+
+ while (ab != NULL)
+ {
+ if (ab->data_type == SLANG_ARRAY_TYPE)
+ return 0;
+ ab = ab->next;
+ }
+
+ if ((-1 == SLclass_add_binary_op (SLANG_ARRAY_TYPE, type, array_binary_op, array_binary_op_result))
+ || (-1 == SLclass_add_binary_op (type, SLANG_ARRAY_TYPE, array_binary_op, array_binary_op_result)))
+ return -1;
+
+ return 0;
+}
+
+static SLang_Array_Type *
+do_array_math_op (int op, int unary_type,
+ SLang_Array_Type *at, unsigned int na)
+{
+ unsigned char a_type, b_type;
+ int (*f) (int, unsigned char, VOID_STAR, unsigned int, VOID_STAR);
+ SLang_Array_Type *bt;
+ SLang_Class_Type *b_cl;
+ int no_init;
+
+ if (na != 1)
+ {
+ SLang_verror (SL_NOT_IMPLEMENTED, "Operation restricted to 1 array");
+ return NULL;
+ }
+
+ a_type = at->data_type;
+ if (NULL == (f = _SLclass_get_unary_fun (op, at->cl, &b_cl, unary_type)))
+ return NULL;
+ b_type = b_cl->cl_data_type;
+
+ if (-1 == coerse_array_to_linear (at))
+ return NULL;
+
+ no_init = ((b_cl->cl_class_type == SLANG_CLASS_TYPE_SCALAR)
+ || (b_cl->cl_class_type == SLANG_CLASS_TYPE_VECTOR));
+
+#if _SLANG_USE_TMP_OPTIMIZATION
+ /* If we are dealing with scalar (or vector) objects, and if the object
+ * appears to be owned by the stack, then use it instead of creating a
+ * new version. This can happen with code such as:
+ * @ x = [1,2,3,4];
+ * @ x = UNARY_OP(__tmp(x));
+ */
+ if (no_init
+ && (at->num_refs == 1)
+ && (at->data_type == b_cl->cl_data_type))
+ {
+ bt = at;
+ bt->num_refs = 2;
+ }
+ else
+#endif /* _SLANG_USE_TMP_OPTIMIZATION */
+ if (NULL == (bt = SLang_create_array1 (b_type, 0, NULL, at->dims, at->num_dims, no_init)))
+ return NULL;
+
+ if (1 != (*f)(op, a_type, at->data, at->num_elements, bt->data))
+ {
+ SLang_free_array (bt);
+ return NULL;
+ }
+ return bt;
+}
+
+static int
+array_unary_op_result (int op, unsigned char a, unsigned char *b)
+{
+ (void) op;
+ (void) a;
+ *b = SLANG_ARRAY_TYPE;
+ return 1;
+}
+
+static int
+array_unary_op (int op,
+ unsigned char a, VOID_STAR ap, unsigned int na,
+ VOID_STAR bp)
+{
+ SLang_Array_Type *at;
+
+ (void) a;
+ at = *(SLang_Array_Type **) ap;
+ if (NULL == (at = do_array_math_op (op, _SLANG_BC_UNARY, at, na)))
+ {
+ if (SLang_Error) return -1;
+ return 0;
+ }
+ *(SLang_Array_Type **) bp = at;
+ return 1;
+}
+
+static int
+array_math_op (int op,
+ unsigned char a, VOID_STAR ap, unsigned int na,
+ VOID_STAR bp)
+{
+ SLang_Array_Type *at;
+
+ (void) a;
+ at = *(SLang_Array_Type **) ap;
+ if (NULL == (at = do_array_math_op (op, _SLANG_BC_MATH_UNARY, at, na)))
+ {
+ if (SLang_Error) return -1;
+ return 0;
+ }
+ *(SLang_Array_Type **) bp = at;
+ return 1;
+}
+
+static int
+array_app_op (int op,
+ unsigned char a, VOID_STAR ap, unsigned int na,
+ VOID_STAR bp)
+{
+ SLang_Array_Type *at;
+
+ (void) a;
+ at = *(SLang_Array_Type **) ap;
+ if (NULL == (at = do_array_math_op (op, _SLANG_BC_APP_UNARY, at, na)))
+ {
+ if (SLang_Error) return -1;
+ return 0;
+ }
+ *(SLang_Array_Type **) bp = at;
+ return 1;
+}
+
+int
+_SLarray_typecast (unsigned char a_type, VOID_STAR ap, unsigned int na,
+ unsigned char b_type, VOID_STAR bp,
+ int is_implicit)
+{
+ SLang_Array_Type *at, *bt;
+ SLang_Class_Type *b_cl;
+ int no_init;
+ int (*t) (unsigned char, VOID_STAR, unsigned int, unsigned char, VOID_STAR);
+
+ if (na != 1)
+ {
+ SLang_verror (SL_NOT_IMPLEMENTED, "typecast of multiple arrays not implemented");
+ return -1;
+ }
+
+ at = *(SLang_Array_Type **) ap;
+ a_type = at->data_type;
+
+ if (a_type == b_type)
+ {
+ at->num_refs += 1;
+ *(SLang_Array_Type **) bp = at;
+ return 1;
+ }
+
+ if (NULL == (t = _SLclass_get_typecast (a_type, b_type, is_implicit)))
+ return -1;
+
+ if (-1 == coerse_array_to_linear (at))
+ return -1;
+
+ b_cl = _SLclass_get_class (b_type);
+
+ no_init = ((b_cl->cl_class_type == SLANG_CLASS_TYPE_SCALAR)
+ || (b_cl->cl_class_type == SLANG_CLASS_TYPE_VECTOR));
+
+ if (NULL == (bt = SLang_create_array1 (b_type, 0, NULL, at->dims, at->num_dims, no_init)))
+ return -1;
+
+ if (1 == (*t) (a_type, at->data, at->num_elements, b_type, bt->data))
+ {
+ *(SLang_Array_Type **) bp = bt;
+ return 1;
+ }
+
+ SLang_free_array (bt);
+ return 0;
+}
+
+SLang_Array_Type *SLang_duplicate_array (SLang_Array_Type *at)
+{
+ SLang_Array_Type *bt;
+ char *data, *a_data;
+ unsigned int i, num_elements, sizeof_type;
+ unsigned int size;
+ int (*cl_acopy) (unsigned char, VOID_STAR, VOID_STAR);
+ unsigned char type;
+
+ if (-1 == coerse_array_to_linear (at))
+ return NULL;
+
+ type = at->data_type;
+ num_elements = at->num_elements;
+ sizeof_type = at->sizeof_type;
+ size = num_elements * sizeof_type;
+
+ if (NULL == (data = SLmalloc (size)))
+ return NULL;
+
+ if (NULL == (bt = SLang_create_array (type, 0, (VOID_STAR)data, at->dims, at->num_dims)))
+ {
+ SLfree (data);
+ return NULL;
+ }
+
+ a_data = (char *) at->data;
+ if (0 == (at->flags & SLARR_DATA_VALUE_IS_POINTER))
+ {
+ SLMEMCPY (data, a_data, size);
+ return bt;
+ }
+
+ SLMEMSET (data, 0, size);
+
+ cl_acopy = at->cl->cl_acopy;
+ for (i = 0; i < num_elements; i++)
+ {
+ if (NULL != *(VOID_STAR *) a_data)
+ {
+ if (-1 == (*cl_acopy) (type, (VOID_STAR) a_data, (VOID_STAR) data))
+ {
+ SLang_free_array (bt);
+ return NULL;
+ }
+ }
+
+ data += sizeof_type;
+ a_data += sizeof_type;
+ }
+
+ return bt;
+}
+
+static int array_dereference (unsigned char type, VOID_STAR addr)
+{
+ SLang_Array_Type *at;
+
+ (void) type;
+ at = SLang_duplicate_array (*(SLang_Array_Type **) addr);
+ if (at == NULL) return -1;
+ return SLang_push_array (at, 1);
+}
+
+/* This function gets called via, e.g., @Array_Type (Double_Type, [10,20]);
+ */
+static int
+array_datatype_deref (unsigned char type)
+{
+ SLang_Array_Type *ind_at;
+ SLang_Array_Type *at;
+
+#if 0
+ /* The parser generated code for this as if a function call were to be
+ * made. However, the interpreter simply called the deref object routine
+ * instead of the function call. So, I must simulate the function call.
+ * This needs to be formalized to hide this detail from applications
+ * who wish to do the same. So...
+ * FIXME: Priority=medium
+ */
+ if (0 == _SL_increment_frame_pointer ())
+ (void) _SL_decrement_frame_pointer ();
+#endif
+
+ if (-1 == SLang_pop_array (&ind_at, 1))
+ return -1;
+
+ if ((ind_at->data_type != SLANG_INT_TYPE)
+ || (ind_at->num_dims != 1))
+ {
+ SLang_verror (SL_TYPE_MISMATCH, "Expecting 1-d integer array");
+ goto return_error;
+ }
+
+ if (-1 == _SLang_pop_datatype (&type))
+ goto return_error;
+
+ if (NULL == (at = SLang_create_array (type, 0, NULL,
+ (int *) ind_at->data,
+ ind_at->num_elements)))
+ goto return_error;
+
+ SLang_free_array (ind_at);
+ return SLang_push_array (at, 1);
+
+ return_error:
+ SLang_free_array (ind_at);
+ return -1;
+}
+
+static int array_length (unsigned char type, VOID_STAR v, unsigned int *len)
+{
+ SLang_Array_Type *at;
+
+ (void) type;
+ at = *(SLang_Array_Type **) v;
+ *len = at->num_elements;
+ return 0;
+}
+
+int
+_SLarray_init_slarray (void)
+{
+ SLang_Class_Type *cl;
+
+ if (-1 == SLadd_intrin_fun_table (Array_Table, NULL))
+ return -1;
+
+ if (NULL == (cl = SLclass_allocate_class ("Array_Type")))
+ return -1;
+
+ (void) SLclass_set_string_function (cl, array_string);
+ (void) SLclass_set_destroy_function (cl, array_destroy);
+ (void) SLclass_set_push_function (cl, array_push);
+ cl->cl_push_intrinsic = array_push_intrinsic;
+ cl->cl_dereference = array_dereference;
+ cl->cl_datatype_deref = array_datatype_deref;
+ cl->cl_length = array_length;
+
+ if (-1 == SLclass_register_class (cl, SLANG_ARRAY_TYPE, sizeof (VOID_STAR),
+ SLANG_CLASS_TYPE_PTR))
+ return -1;
+
+ if ((-1 == SLclass_add_binary_op (SLANG_ARRAY_TYPE, SLANG_ARRAY_TYPE, array_binary_op, array_binary_op_result))
+ || (-1 == SLclass_add_unary_op (SLANG_ARRAY_TYPE, array_unary_op, array_unary_op_result))
+ || (-1 == SLclass_add_app_unary_op (SLANG_ARRAY_TYPE, array_app_op, array_unary_op_result))
+ || (-1 == SLclass_add_math_op (SLANG_ARRAY_TYPE, array_math_op, array_unary_op_result))
+ || (-1 == SLclass_add_math_op (SLANG_ARRAY_TYPE, array_math_op, array_unary_op_result)))
+ return -1;
+
+ return 0;
+}
+
+int SLang_pop_array (SLang_Array_Type **at_ptr, int convert_scalar)
+{
+ if (-1 == pop_array (at_ptr, convert_scalar))
+ return -1;
+
+ if (-1 == coerse_array_to_linear (*at_ptr))
+ {
+ SLang_free_array (*at_ptr);
+ return -1;
+ }
+ return 0;
+}
+
+int SLang_pop_array_of_type (SLang_Array_Type **at, unsigned char type)
+{
+ if (-1 == SLclass_typecast (type, 1, 1))
+ return -1;
+
+ return SLang_pop_array (at, 1);
+}
+
+void (*_SLang_Matrix_Multiply)(void);
+
+int _SLarray_matrix_multiply (void)
+{
+ if (_SLang_Matrix_Multiply != NULL)
+ {
+ (*_SLang_Matrix_Multiply)();
+ return 0;
+ }
+ SLang_verror (SL_NOT_IMPLEMENTED, "Matrix multiplication not available");
+ return -1;
+}
+
+struct _SLang_Foreach_Context_Type
+{
+ SLang_Array_Type *at;
+ unsigned int next_element_index;
+};
+
+SLang_Foreach_Context_Type *
+_SLarray_cl_foreach_open (unsigned char type, unsigned int num)
+{
+ SLang_Foreach_Context_Type *c;
+
+ if (num != 0)
+ {
+ SLdo_pop_n (num + 1);
+ SLang_verror (SL_NOT_IMPLEMENTED,
+ "%s does not support 'foreach using' form",
+ SLclass_get_datatype_name (type));
+ return NULL;
+ }
+
+ if (NULL == (c = (SLang_Foreach_Context_Type *) SLmalloc (sizeof (SLang_Foreach_Context_Type))))
+ return NULL;
+
+ memset ((char *) c, 0, sizeof (SLang_Foreach_Context_Type));
+
+ if (-1 == pop_array (&c->at, 1))
+ {
+ SLfree ((char *) c);
+ return NULL;
+ }
+
+ return c;
+}
+
+void _SLarray_cl_foreach_close (unsigned char type, SLang_Foreach_Context_Type *c)
+{
+ (void) type;
+ if (c == NULL) return;
+ SLang_free_array (c->at);
+ SLfree ((char *) c);
+}
+
+int _SLarray_cl_foreach (unsigned char type, SLang_Foreach_Context_Type *c)
+{
+ SLang_Array_Type *at;
+ VOID_STAR data;
+
+ (void) type;
+
+ if (c == NULL)
+ return -1;
+
+ at = c->at;
+ if (at->num_elements == c->next_element_index)
+ return 0;
+
+ /* FIXME: Priority = low. The following assumes linear arrays
+ * or Integer range arrays. Fixing it right requires a method to get the
+ * nth element of a multidimensional array.
+ */
+
+ if (at->flags & SLARR_DATA_VALUE_IS_RANGE)
+ {
+ int d = (int) c->next_element_index;
+ data = range_get_data_addr (at, &d);
+ }
+ else
+ data = (VOID_STAR) ((char *)at->data + (c->next_element_index * at->sizeof_type));
+
+ c->next_element_index += 1;
+
+ if ((at->flags & SLARR_DATA_VALUE_IS_POINTER)
+ && (*(VOID_STAR *) data == NULL))
+ {
+ if (-1 == SLang_push_null ())
+ return -1;
+ }
+ else if (-1 == (*at->cl->cl_apush)(at->data_type, data))
+ return -1;
+
+ /* keep going */
+ return 1;
+}
+
diff --git a/mdk-stage1/slang/slarrfun.c b/mdk-stage1/slang/slarrfun.c
new file mode 100644
index 000000000..bfa6ec5e5
--- /dev/null
+++ b/mdk-stage1/slang/slarrfun.c
@@ -0,0 +1,464 @@
+/* Advanced array manipulation routines for S-Lang */
+/* Copyright (c) 1998, 1999, 2001 John E. Davis
+ * This file is part of the S-Lang library.
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Perl Artistic License.
+ */
+
+#include "slinclud.h"
+
+#include "slang.h"
+#include "_slang.h"
+
+static int next_transposed_index (int *dims, int *max_dims, unsigned int num_dims)
+{
+ int i;
+
+ for (i = 0; i < (int) num_dims; i++)
+ {
+ int dims_i;
+
+ dims_i = dims [i] + 1;
+ if (dims_i != (int) max_dims [i])
+ {
+ dims [i] = dims_i;
+ return 0;
+ }
+ dims [i] = 0;
+ }
+
+ return -1;
+}
+
+static SLang_Array_Type *allocate_transposed_array (SLang_Array_Type *at)
+{
+ unsigned int num_elements;
+ SLang_Array_Type *bt;
+ VOID_STAR b_data;
+
+ num_elements = at->num_elements;
+ b_data = (VOID_STAR) SLmalloc (at->sizeof_type * num_elements);
+ if (b_data == NULL)
+ return NULL;
+
+ bt = SLang_create_array (at->data_type, 0, b_data, at->dims, 2);
+ if (bt == NULL)
+ {
+ SLfree ((char *)b_data);
+ return NULL;
+ }
+
+ bt->dims[1] = at->dims[0];
+ bt->dims[0] = at->dims[1];
+
+ return bt;
+}
+
+#define GENERIC_TYPE float
+#define TRANSPOSE_2D_ARRAY transpose_floats
+#define GENERIC_TYPE_A float
+#define GENERIC_TYPE_B float
+#define GENERIC_TYPE_C float
+#define INNERPROD_FUNCTION innerprod_float_float
+#if SLANG_HAS_COMPLEX
+# define INNERPROD_COMPLEX_A innerprod_complex_float
+# define INNERPROD_A_COMPLEX innerprod_float_complex
+#endif
+#include "slarrfun.inc"
+
+#define GENERIC_TYPE double
+#define TRANSPOSE_2D_ARRAY transpose_doubles
+#define GENERIC_TYPE_A double
+#define GENERIC_TYPE_B double
+#define GENERIC_TYPE_C double
+#define INNERPROD_FUNCTION innerprod_double_double
+#if SLANG_HAS_COMPLEX
+# define INNERPROD_COMPLEX_A innerprod_complex_double
+# define INNERPROD_A_COMPLEX innerprod_double_complex
+#endif
+#include "slarrfun.inc"
+
+#define GENERIC_TYPE_A double
+#define GENERIC_TYPE_B float
+#define GENERIC_TYPE_C double
+#define INNERPROD_FUNCTION innerprod_double_float
+#include "slarrfun.inc"
+
+#define GENERIC_TYPE_A float
+#define GENERIC_TYPE_B double
+#define GENERIC_TYPE_C double
+#define INNERPROD_FUNCTION innerprod_float_double
+#include "slarrfun.inc"
+
+/* Finally pick up the complex_complex multiplication
+ * and do the integers
+ */
+#if SLANG_HAS_COMPLEX
+# define INNERPROD_COMPLEX_COMPLEX innerprod_complex_complex
+#endif
+#define GENERIC_TYPE int
+#define TRANSPOSE_2D_ARRAY transpose_ints
+#include "slarrfun.inc"
+
+#if SIZEOF_LONG != SIZEOF_INT
+# define GENERIC_TYPE long
+# define TRANSPOSE_2D_ARRAY transpose_longs
+# include "slarrfun.inc"
+#else
+# define transpose_longs transpose_ints
+#endif
+
+#if SIZEOF_SHORT != SIZEOF_INT
+# define GENERIC_TYPE short
+# define TRANSPOSE_2D_ARRAY transpose_shorts
+# include "slarrfun.inc"
+#else
+# define transpose_shorts transpose_ints
+#endif
+
+#define GENERIC_TYPE char
+#define TRANSPOSE_2D_ARRAY transpose_chars
+#include "slarrfun.inc"
+
+/* This routine works only with linear arrays */
+static SLang_Array_Type *transpose (SLang_Array_Type *at)
+{
+ int dims [SLARRAY_MAX_DIMS];
+ int *max_dims;
+ unsigned int num_dims;
+ SLang_Array_Type *bt;
+ int i;
+ unsigned int sizeof_type;
+ int is_ptr;
+ char *b_data;
+
+ max_dims = at->dims;
+ num_dims = at->num_dims;
+
+ if ((at->num_elements == 0)
+ || (num_dims == 1))
+ {
+ bt = SLang_duplicate_array (at);
+ if (num_dims == 1) bt->num_dims = 2;
+ goto transpose_dims;
+ }
+
+ /* For numeric arrays skip the overhead below */
+ if (num_dims == 2)
+ {
+ bt = allocate_transposed_array (at);
+ if (bt == NULL) return NULL;
+
+ switch (at->data_type)
+ {
+ case SLANG_INT_TYPE:
+ case SLANG_UINT_TYPE:
+ return transpose_ints (at, bt);
+ case SLANG_DOUBLE_TYPE:
+ return transpose_doubles (at, bt);
+ case SLANG_FLOAT_TYPE:
+ return transpose_floats (at, bt);
+ case SLANG_CHAR_TYPE:
+ case SLANG_UCHAR_TYPE:
+ return transpose_chars (at, bt);
+ case SLANG_LONG_TYPE:
+ case SLANG_ULONG_TYPE:
+ return transpose_longs (at, bt);
+ case SLANG_SHORT_TYPE:
+ case SLANG_USHORT_TYPE:
+ return transpose_shorts (at, bt);
+ }
+ }
+ else
+ {
+ bt = SLang_create_array (at->data_type, 0, NULL, max_dims, num_dims);
+ if (bt == NULL) return NULL;
+ }
+
+ sizeof_type = at->sizeof_type;
+ is_ptr = (at->flags & SLARR_DATA_VALUE_IS_POINTER);
+
+ memset ((char *)dims, 0, sizeof(dims));
+
+ b_data = (char *) bt->data;
+
+ do
+ {
+ if (-1 == _SLarray_aget_transfer_elem (at, dims, (VOID_STAR) b_data,
+ sizeof_type, is_ptr))
+ {
+ SLang_free_array (bt);
+ return NULL;
+ }
+ b_data += sizeof_type;
+ }
+ while (0 == next_transposed_index (dims, max_dims, num_dims));
+
+ transpose_dims:
+
+ num_dims = bt->num_dims;
+ for (i = 0; i < (int) num_dims; i++)
+ bt->dims[i] = max_dims [num_dims - i - 1];
+
+ return bt;
+}
+
+static void array_transpose (SLang_Array_Type *at)
+{
+ if (NULL != (at = transpose (at)))
+ (void) SLang_push_array (at, 1);
+}
+
+static int get_inner_product_parms (SLang_Array_Type *a, int *dp,
+ unsigned int *loops, unsigned int *other)
+{
+ int num_dims;
+ int d;
+
+ d = *dp;
+
+ num_dims = (int)a->num_dims;
+ if (num_dims == 0)
+ {
+ SLang_verror (SL_INVALID_PARM, "Inner-product operation requires an array of at least 1 dimension.");
+ return -1;
+ }
+
+ /* An index of -1 refers to last dimension */
+ if (d == -1)
+ d += num_dims;
+ *dp = d;
+
+ if (a->num_elements == 0)
+ { /* [] # [] ==> [] */
+ *loops = *other = 0;
+ return 0;
+ }
+
+ *loops = a->num_elements / a->dims[d];
+
+ if (d == 0)
+ {
+ *other = *loops; /* a->num_elements / a->dims[0]; */
+ return 0;
+ }
+
+ *other = a->dims[d];
+ return 0;
+}
+
+/* This routines takes two arrays A_i..j and B_j..k and produces a third
+ * via C_i..k = A_i..j B_j..k.
+ *
+ * If A is a vector, and B is a 2-d matrix, then regard A as a 2-d matrix
+ * with 1-column.
+ */
+static void do_inner_product (void)
+{
+ SLang_Array_Type *a, *b, *c;
+ void (*fun)(SLang_Array_Type *, SLang_Array_Type *, SLang_Array_Type *,
+ unsigned int, unsigned int, unsigned int, unsigned int,
+ unsigned int);
+ unsigned char c_type;
+ int dims[SLARRAY_MAX_DIMS];
+ int status;
+ unsigned int a_loops, b_loops, b_inc, a_stride;
+ int ai_dims, i, j;
+ unsigned int num_dims, a_num_dims, b_num_dims;
+ int ai, bi;
+
+ /* The result of a inner_product will be either a float, double, or
+ * a complex number.
+ *
+ * If an integer array is used, it will be promoted to a float.
+ */
+
+ switch (SLang_peek_at_stack1 ())
+ {
+ case SLANG_DOUBLE_TYPE:
+ if (-1 == SLang_pop_array_of_type (&b, SLANG_DOUBLE_TYPE))
+ return;
+ break;
+
+#if SLANG_HAS_COMPLEX
+ case SLANG_COMPLEX_TYPE:
+ if (-1 == SLang_pop_array_of_type (&b, SLANG_COMPLEX_TYPE))
+ return;
+ break;
+#endif
+ case SLANG_FLOAT_TYPE:
+ default:
+ if (-1 == SLang_pop_array_of_type (&b, SLANG_FLOAT_TYPE))
+ return;
+ break;
+ }
+
+ switch (SLang_peek_at_stack1 ())
+ {
+ case SLANG_DOUBLE_TYPE:
+ status = SLang_pop_array_of_type (&a, SLANG_DOUBLE_TYPE);
+ break;
+
+#if SLANG_HAS_COMPLEX
+ case SLANG_COMPLEX_TYPE:
+ status = SLang_pop_array_of_type (&a, SLANG_COMPLEX_TYPE);
+ break;
+#endif
+ case SLANG_FLOAT_TYPE:
+ default:
+ status = SLang_pop_array_of_type (&a, SLANG_FLOAT_TYPE);
+ break;
+ }
+
+ if (status == -1)
+ {
+ SLang_free_array (b);
+ return;
+ }
+
+ ai = -1; /* last index of a */
+ bi = 0; /* first index of b */
+ if ((-1 == get_inner_product_parms (a, &ai, &a_loops, &a_stride))
+ || (-1 == get_inner_product_parms (b, &bi, &b_loops, &b_inc)))
+ {
+ SLang_verror (SL_TYPE_MISMATCH, "Array dimensions are not compatible for inner-product");
+ goto free_and_return;
+ }
+
+ a_num_dims = a->num_dims;
+ b_num_dims = b->num_dims;
+
+ /* Coerse a 1-d vector to 2-d */
+ if ((a_num_dims == 1)
+ && (b_num_dims == 2)
+ && (a->num_elements))
+ {
+ a_num_dims = 2;
+ ai = 1;
+ a_loops = a->num_elements;
+ a_stride = 1;
+ }
+
+ if ((ai_dims = a->dims[ai]) != b->dims[bi])
+ {
+ SLang_verror (SL_TYPE_MISMATCH, "Array dimensions are not compatible for inner-product");
+ goto free_and_return;
+ }
+
+ num_dims = a_num_dims + b_num_dims - 2;
+ if (num_dims > SLARRAY_MAX_DIMS)
+ {
+ SLang_verror (SL_NOT_IMPLEMENTED,
+ "Inner-product result exceed max allowed dimensions");
+ goto free_and_return;
+ }
+
+ if (num_dims)
+ {
+ j = 0;
+ for (i = 0; i < (int)a_num_dims; i++)
+ if (i != ai) dims [j++] = a->dims[i];
+ for (i = 0; i < (int)b_num_dims; i++)
+ if (i != bi) dims [j++] = b->dims[i];
+ }
+ else
+ {
+ /* a scalar */
+ num_dims = 1;
+ dims[0] = 1;
+ }
+
+ c_type = 0; fun = NULL;
+ switch (a->data_type)
+ {
+ case SLANG_FLOAT_TYPE:
+ switch (b->data_type)
+ {
+ case SLANG_FLOAT_TYPE:
+ c_type = SLANG_FLOAT_TYPE;
+ fun = innerprod_float_float;
+ break;
+ case SLANG_DOUBLE_TYPE:
+ c_type = SLANG_DOUBLE_TYPE;
+ fun = innerprod_float_double;
+ break;
+#if SLANG_HAS_COMPLEX
+ case SLANG_COMPLEX_TYPE:
+ c_type = SLANG_COMPLEX_TYPE;
+ fun = innerprod_float_complex;
+ break;
+#endif
+ }
+ break;
+ case SLANG_DOUBLE_TYPE:
+ switch (b->data_type)
+ {
+ case SLANG_FLOAT_TYPE:
+ c_type = SLANG_DOUBLE_TYPE;
+ fun = innerprod_double_float;
+ break;
+ case SLANG_DOUBLE_TYPE:
+ c_type = SLANG_DOUBLE_TYPE;
+ fun = innerprod_double_double;
+ break;
+#if SLANG_HAS_COMPLEX
+ case SLANG_COMPLEX_TYPE:
+ c_type = SLANG_COMPLEX_TYPE;
+ fun = innerprod_double_complex;
+ break;
+#endif
+ }
+ break;
+#if SLANG_HAS_COMPLEX
+ case SLANG_COMPLEX_TYPE:
+ c_type = SLANG_COMPLEX_TYPE;
+ switch (b->data_type)
+ {
+ case SLANG_FLOAT_TYPE:
+ fun = innerprod_complex_float;
+ break;
+ case SLANG_DOUBLE_TYPE:
+ fun = innerprod_complex_double;
+ break;
+ case SLANG_COMPLEX_TYPE:
+ fun = innerprod_complex_complex;
+ break;
+ }
+ break;
+#endif
+ default:
+ break;
+ }
+
+ if (NULL == (c = SLang_create_array (c_type, 0, NULL, dims, num_dims)))
+ goto free_and_return;
+
+ (*fun)(a, b, c, a_loops, a_stride, b_loops, b_inc, ai_dims);
+
+ (void) SLang_push_array (c, 1);
+ /* drop */
+
+ free_and_return:
+ SLang_free_array (a);
+ SLang_free_array (b);
+}
+
+
+
+static SLang_Intrin_Fun_Type Array_Fun_Table [] =
+{
+ MAKE_INTRINSIC_1("transpose", array_transpose, SLANG_VOID_TYPE, SLANG_ARRAY_TYPE),
+ SLANG_END_INTRIN_FUN_TABLE
+};
+
+int SLang_init_array (void)
+{
+ if (-1 == SLadd_intrin_fun_table (Array_Fun_Table, "__SLARRAY__"))
+ return -1;
+#if SLANG_HAS_FLOAT
+ _SLang_Matrix_Multiply = do_inner_product;
+#endif
+ return 0;
+}
+
diff --git a/mdk-stage1/slang/slarrfun.inc b/mdk-stage1/slang/slarrfun.inc
new file mode 100644
index 000000000..348473a6f
--- /dev/null
+++ b/mdk-stage1/slang/slarrfun.inc
@@ -0,0 +1,257 @@
+/* -*- mode: C -*- */
+
+/* Some "inline" functions for generic scalar types */
+
+#ifdef TRANSPOSE_2D_ARRAY
+static SLang_Array_Type *TRANSPOSE_2D_ARRAY (SLang_Array_Type *at, SLang_Array_Type *bt)
+{
+ GENERIC_TYPE *a_data, *b_data;
+ int nr, nc, i;
+
+ nr = at->dims[0];
+ nc = at->dims[1];
+
+ a_data = (GENERIC_TYPE *) at->data;
+ b_data = (GENERIC_TYPE *) bt->data;
+
+ for (i = 0; i < nr; i++)
+ {
+ GENERIC_TYPE *offset = b_data + i;
+ int j;
+ for (j = 0; j < nc; j++)
+ {
+ *offset = *a_data++;
+ offset += nr;
+ }
+ }
+ return bt;
+}
+#undef TRANSPOSE_2D_ARRAY
+#endif
+
+
+#ifdef INNERPROD_FUNCTION
+
+static void INNERPROD_FUNCTION
+ (SLang_Array_Type *at, SLang_Array_Type *bt, SLang_Array_Type *ct,
+ unsigned int a_loops, unsigned int a_stride,
+ unsigned int b_loops, unsigned int b_inc,
+ unsigned int inner_loops)
+{
+ GENERIC_TYPE_A *a;
+ GENERIC_TYPE_B *b;
+ GENERIC_TYPE_C *c;
+
+ c = (GENERIC_TYPE_C *) ct->data;
+ b = (GENERIC_TYPE_B *) bt->data;
+ a = (GENERIC_TYPE_A *) at->data;
+
+ while (a_loops--)
+ {
+ GENERIC_TYPE_B *bb;
+ unsigned int j;
+
+ bb = b;
+
+ for (j = 0; j < inner_loops; j++)
+ {
+ double x = (double) a[j];
+
+ if (x != 0.0)
+ {
+ unsigned int k;
+
+ for (k = 0; k < b_loops; k++)
+ c[k] += x * bb[k];
+ }
+ bb += b_inc;
+ }
+ c += b_loops;
+ a += a_stride;
+ }
+}
+#undef INNERPROD_FUNCTION
+
+#undef GENERIC_TYPE_A
+#undef GENERIC_TYPE_B
+#undef GENERIC_TYPE_C
+#endif
+
+#ifdef INNERPROD_COMPLEX_A
+static void INNERPROD_COMPLEX_A
+ (SLang_Array_Type *at, SLang_Array_Type *bt, SLang_Array_Type *ct,
+ unsigned int a_loops, unsigned int a_stride,
+ unsigned int b_loops, unsigned int b_inc,
+ unsigned int inner_loops)
+{
+ double *a;
+ GENERIC_TYPE *b;
+ double *c;
+
+ c = (double *) ct->data;
+ b = (GENERIC_TYPE *) bt->data;
+ a = (double *) at->data;
+
+ a_stride *= 2;
+
+ while (a_loops--)
+ {
+ GENERIC_TYPE *bb;
+ unsigned int bb_loops;
+
+ bb = b;
+ bb_loops = b_loops;
+
+ while (bb_loops--)
+ {
+ double real_sum;
+ double imag_sum;
+ unsigned int iloops;
+ double *aa;
+ GENERIC_TYPE *bbb;
+
+ aa = a;
+ bbb = bb;
+ iloops = inner_loops;
+
+ real_sum = 0.0;
+ imag_sum = 0.0;
+ while (iloops--)
+ {
+ real_sum += aa[0] * (double)bbb[0];
+ imag_sum += aa[1] * (double)bbb[0];
+ aa += 2;
+ bbb += b_inc;
+ }
+
+ *c++ = real_sum;
+ *c++ = imag_sum;
+ bb++;
+ }
+
+ a += a_stride;
+ }
+}
+
+static void INNERPROD_A_COMPLEX
+ (SLang_Array_Type *at, SLang_Array_Type *bt, SLang_Array_Type *ct,
+ unsigned int a_loops, unsigned int a_stride,
+ unsigned int b_loops, unsigned int b_inc,
+ unsigned int inner_loops)
+{
+ GENERIC_TYPE *a;
+ double *b;
+ double *c;
+
+ c = (double *) ct->data;
+ b = (double *) bt->data;
+ a = (GENERIC_TYPE *) at->data;
+
+ b_inc *= 2;
+
+ while (a_loops--)
+ {
+ double *bb;
+ unsigned int bb_loops;
+
+ bb = b;
+ bb_loops = b_loops;
+
+ while (bb_loops--)
+ {
+ double real_sum;
+ double imag_sum;
+ unsigned int iloops;
+ GENERIC_TYPE *aa;
+ double *bbb;
+
+ aa = a;
+ bbb = bb;
+ iloops = inner_loops;
+
+ real_sum = 0.0;
+ imag_sum = 0.0;
+ while (iloops--)
+ {
+ real_sum += (double)aa[0] * bbb[0];
+ imag_sum += (double)aa[0] * bbb[1];
+ aa += 1;
+ bbb += b_inc;
+ }
+
+ *c++ = real_sum;
+ *c++ = imag_sum;
+ bb += 2;
+ }
+
+ a += a_stride;
+ }
+}
+
+#undef INNERPROD_A_COMPLEX
+#undef INNERPROD_COMPLEX_A
+#endif /* INNERPROD_COMPLEX_A */
+
+
+#ifdef INNERPROD_COMPLEX_COMPLEX
+static void INNERPROD_COMPLEX_COMPLEX
+ (SLang_Array_Type *at, SLang_Array_Type *bt, SLang_Array_Type *ct,
+ unsigned int a_loops, unsigned int a_stride,
+ unsigned int b_loops, unsigned int b_inc,
+ unsigned int inner_loops)
+{
+ double *a;
+ double *b;
+ double *c;
+
+ c = (double *) ct->data;
+ b = (double *) bt->data;
+ a = (double *) at->data;
+
+ a_stride *= 2;
+ b_inc *= 2;
+
+ while (a_loops--)
+ {
+ double *bb;
+ unsigned int bb_loops;
+
+ bb = b;
+ bb_loops = b_loops;
+
+ while (bb_loops--)
+ {
+ double real_sum;
+ double imag_sum;
+ unsigned int iloops;
+ double *aa;
+ double *bbb;
+
+ aa = a;
+ bbb = bb;
+ iloops = inner_loops;
+
+ real_sum = 0.0;
+ imag_sum = 0.0;
+ while (iloops--)
+ {
+ real_sum += aa[0]*bbb[0] - aa[1]*bbb[1];
+ imag_sum += aa[0]*bbb[1] + aa[1]*bbb[0];
+ aa += 2;
+ bbb += b_inc;
+ }
+
+ *c++ = real_sum;
+ *c++ = imag_sum;
+ bb += 2;
+ }
+
+ a += a_stride;
+ }
+}
+#undef INNERPROD_COMPLEX_COMPLEX
+#endif
+
+#ifdef GENERIC_TYPE
+# undef GENERIC_TYPE
+#endif
diff --git a/mdk-stage1/slang/slarrmis.c b/mdk-stage1/slang/slarrmis.c
new file mode 100644
index 000000000..330dcb53f
--- /dev/null
+++ b/mdk-stage1/slang/slarrmis.c
@@ -0,0 +1,38 @@
+/* Misc Array Functions */
+/* Copyright (c) 1997, 1999, 2001 John E. Davis
+ * This file is part of the S-Lang library.
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Perl Artistic License.
+ */
+
+#include "slinclud.h"
+
+#include "slang.h"
+#include "_slang.h"
+
+int SLang_get_array_element (SLang_Array_Type *at, int *indices, VOID_STAR data)
+{
+ int is_ptr;
+
+ if ((at == NULL)
+ || (indices == NULL)
+ || (data == NULL))
+ return -1;
+
+ is_ptr = (at->flags & SLARR_DATA_VALUE_IS_POINTER);
+ if (is_ptr) *(VOID_STAR *) data = NULL;
+ return _SLarray_aget_transfer_elem (at, indices, data, at->sizeof_type, is_ptr);
+}
+
+int SLang_set_array_element (SLang_Array_Type *at, int *indices, VOID_STAR data)
+{
+ if ((at == NULL)
+ || (indices == NULL)
+ || (data == NULL))
+ return -1;
+
+ return _SLarray_aput_transfer_elem (at, indices, data, at->sizeof_type,
+ at->flags & SLARR_DATA_VALUE_IS_POINTER);
+}
+
diff --git a/mdk-stage1/slang/slassoc.c b/mdk-stage1/slang/slassoc.c
new file mode 100644
index 000000000..5997458d2
--- /dev/null
+++ b/mdk-stage1/slang/slassoc.c
@@ -0,0 +1,713 @@
+/* Copyright (c) 1998, 1999, 2001 John E. Davis
+ * This file is part of the S-Lang library.
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Perl Artistic License.
+ */
+#include "slinclud.h"
+
+#define SL_APP_WANTS_FOREACH
+#include "slang.h"
+#include "_slang.h"
+
+#define USE_NEW_ANYTYPE_CODE 1
+
+typedef struct _SLAssoc_Array_Element_Type
+{
+ char *key; /* slstring */
+ struct _SLAssoc_Array_Element_Type *next;
+ SLang_Object_Type value;
+}
+_SLAssoc_Array_Element_Type;
+
+typedef struct
+{
+ _SLAssoc_Array_Element_Type *elements[SLASSOC_HASH_TABLE_SIZE];
+ SLang_Object_Type default_value;
+ unsigned int num_elements;
+#define HAS_DEFAULT_VALUE 1
+ unsigned int flags;
+ unsigned char type;
+}
+SLang_Assoc_Array_Type;
+
+#define USE_CACHED_STRING 1
+
+#if USE_CACHED_STRING
+static char *Cached_String;
+static SLang_Object_Type *Cached_Obj;
+static SLang_Assoc_Array_Type *Cached_Array;
+#endif
+
+static SLang_Assoc_Array_Type *alloc_assoc_array (unsigned char type, int has_default_value)
+{
+ SLang_Assoc_Array_Type *a;
+
+ a = (SLang_Assoc_Array_Type *)SLmalloc (sizeof (SLang_Assoc_Array_Type));
+ if (a == NULL)
+ {
+ if (has_default_value)
+ SLdo_pop_n (1);
+ return NULL;
+ }
+
+ memset ((char *) a, 0, sizeof (SLang_Assoc_Array_Type));
+ a->type = type;
+
+ if (has_default_value)
+ {
+ if (
+#if USE_NEW_ANYTYPE_CODE
+ ((type != SLANG_ANY_TYPE) && (-1 == SLclass_typecast (type, 1, 1)))
+#else
+ (-1 == SLclass_typecast (type, 1, 1))
+#endif
+ || (-1 == SLang_pop (&a->default_value)))
+ {
+ SLfree ((char *) a);
+ return NULL;
+ }
+
+ a->flags |= HAS_DEFAULT_VALUE;
+ }
+ return a;
+}
+
+static void free_element (_SLAssoc_Array_Element_Type *e)
+{
+ if (e == NULL)
+ return;
+
+ SLang_free_object (&e->value);
+ SLang_free_slstring (e->key);
+#if USE_CACHED_STRING
+ if (e->key == Cached_String)
+ Cached_String = NULL;
+#endif
+ SLfree ((char *)e);
+}
+
+static void delete_assoc_array (SLang_Assoc_Array_Type *a)
+{
+ unsigned int i;
+
+ if (a == NULL) return;
+
+ for (i = 0; i < SLASSOC_HASH_TABLE_SIZE; i++)
+ {
+ _SLAssoc_Array_Element_Type *e;
+
+ e = a->elements[i];
+ while (e != NULL)
+ {
+ _SLAssoc_Array_Element_Type *next_e;
+
+ next_e = e->next;
+ free_element (e);
+ e = next_e;
+ }
+ }
+ if (a->flags & HAS_DEFAULT_VALUE)
+ SLang_free_object (&a->default_value);
+
+ SLfree ((char *) a);
+}
+
+_INLINE_
+static SLang_Object_Type *
+find_element (SLang_Assoc_Array_Type *a, char *str, unsigned long hash)
+{
+ unsigned int h;
+ _SLAssoc_Array_Element_Type *e;
+
+ h = (unsigned int) (hash % SLASSOC_HASH_TABLE_SIZE);
+ e = a->elements[h];
+
+ while (e != NULL)
+ {
+ if (str == e->key) /* slstrings can be compared this way */
+ {
+#if USE_CACHED_STRING
+ Cached_String = str;
+ Cached_Obj = &e->value;
+ Cached_Array = a;
+#endif
+ return &e->value;
+ }
+
+ e = e->next;
+ }
+
+ return NULL;
+}
+
+static _SLAssoc_Array_Element_Type *
+create_element (SLang_Assoc_Array_Type *a, char *str, unsigned long hash)
+{
+ unsigned int h;
+ _SLAssoc_Array_Element_Type *e;
+
+ e = (_SLAssoc_Array_Element_Type *) SLmalloc (sizeof (_SLAssoc_Array_Element_Type));
+ if (e == NULL)
+ return NULL;
+
+ memset ((char *) e, 0, sizeof (_SLAssoc_Array_Element_Type));
+ h = (unsigned int) (hash % SLASSOC_HASH_TABLE_SIZE);
+
+ if (NULL == (str = _SLstring_dup_hashed_string (str, hash)))
+ {
+ SLfree ((char *) e);
+ return NULL;
+ }
+
+ e->key = str;
+ e->next = a->elements[h];
+ a->elements[h] = e;
+
+ a->num_elements += 1;
+#if USE_CACHED_STRING
+ Cached_String = str;
+ Cached_Obj = &e->value;
+ Cached_Array = a;
+#endif
+ return e;
+}
+
+static int store_object (SLang_Assoc_Array_Type *a, char *s, SLang_Object_Type *obj)
+{
+ unsigned long hash;
+ SLang_Object_Type *v;
+
+#if USE_CACHED_STRING
+ if ((s == Cached_String) && (a == Cached_Array))
+ {
+ v = Cached_Obj;
+ SLang_free_object (v);
+ }
+ else
+ {
+#endif
+ hash = _SLcompute_string_hash (s);
+ if (NULL != (v = find_element (a, s, hash)))
+ SLang_free_object (v);
+ else
+ {
+ _SLAssoc_Array_Element_Type *e;
+
+ e = create_element (a, s, hash);
+ if (e == NULL)
+ return -1;
+
+ v = &e->value;
+ }
+#if USE_CACHED_STRING
+ }
+#endif
+
+ *v = *obj;
+
+ return 0;
+}
+
+static void assoc_destroy (unsigned char type, VOID_STAR ptr)
+{
+ (void) type;
+ delete_assoc_array ((SLang_Assoc_Array_Type *) ptr);
+}
+
+static int pop_index (unsigned int num_indices,
+ SLang_MMT_Type **mmt,
+ SLang_Assoc_Array_Type **a,
+ char **str)
+{
+ if (NULL == (*mmt = SLang_pop_mmt (SLANG_ASSOC_TYPE)))
+ {
+ *a = NULL;
+ *str = NULL;
+ return -1;
+ }
+
+ if ((num_indices != 1)
+ || (-1 == SLang_pop_slstring (str)))
+ {
+ SLang_verror (SL_NOT_IMPLEMENTED,
+ "Assoc_Type arrays require a single string index");
+ SLang_free_mmt (*mmt);
+ *mmt = NULL;
+ *a = NULL;
+ *str = NULL;
+ return -1;
+ }
+
+ *a = (SLang_Assoc_Array_Type *) SLang_object_from_mmt (*mmt);
+ return 0;
+}
+
+static int assoc_aget (unsigned char type, unsigned int num_indices)
+{
+ SLang_MMT_Type *mmt;
+ char *str;
+ SLang_Assoc_Array_Type *a;
+ SLang_Object_Type *obj;
+ int ret;
+
+ (void) type;
+
+ if (-1 == pop_index (num_indices, &mmt, &a, &str))
+ return -1;
+
+#if USE_CACHED_STRING
+ if ((str == Cached_String) && (a == Cached_Array))
+ obj = Cached_Obj;
+ else
+#endif
+ obj = find_element (a, str, _SLcompute_string_hash (str));
+
+ if ((obj == NULL)
+ && (a->flags & HAS_DEFAULT_VALUE))
+ obj = &a->default_value;
+
+ if (obj == NULL)
+ {
+ SLang_verror (SL_INTRINSIC_ERROR,
+ "No such element in Assoc Array: %s", str);
+ ret = -1;
+ }
+ else
+ {
+#if _SLANG_OPTIMIZE_FOR_SPEED
+ if (SLANG_CLASS_TYPE_SCALAR == _SLclass_Class_Type[obj->data_type])
+ ret = SLang_push (obj);
+#endif
+ else
+ ret = _SLpush_slang_obj (obj);
+ }
+
+ SLang_free_slstring (str);
+ SLang_free_mmt (mmt);
+ return ret;
+}
+
+static int assoc_aput (unsigned char type, unsigned int num_indices)
+{
+ SLang_MMT_Type *mmt;
+ char *str;
+ SLang_Assoc_Array_Type *a;
+ SLang_Object_Type obj;
+ int ret;
+
+ (void) type;
+
+ if (-1 == pop_index (num_indices, &mmt, &a, &str))
+ return -1;
+
+ ret = -1;
+
+ if (0 == SLang_pop (&obj))
+ {
+ if ((obj.data_type != a->type)
+#if USE_NEW_ANYTYPE_CODE
+ && (a->type != SLANG_ANY_TYPE)
+#endif
+ )
+ {
+ (void) SLang_push (&obj);
+ if ((-1 == SLclass_typecast (a->type, 1, 1))
+ || (-1 == SLang_pop (&obj)))
+ goto the_return;
+ }
+
+ if (-1 == store_object (a, str, &obj))
+ SLang_free_object (&obj);
+ else
+ ret = 0;
+ }
+
+ the_return:
+ SLang_free_slstring (str);
+ SLang_free_mmt (mmt);
+ return ret;
+}
+
+static int assoc_anew (unsigned char type, unsigned int num_dims)
+{
+ SLang_MMT_Type *mmt;
+ SLang_Assoc_Array_Type *a;
+ int has_default_value;
+
+ has_default_value = 0;
+ switch (num_dims)
+ {
+ case 0:
+ type = SLANG_ANY_TYPE;
+ break;
+ case 2:
+ (void) SLreverse_stack (2);
+ has_default_value = 1;
+ /* drop */
+ case 1:
+ if (0 == _SLang_pop_datatype (&type))
+ break;
+ num_dims--;
+ /* drop */
+ default:
+ SLdo_pop_n (num_dims);
+ SLang_verror (SL_SYNTAX_ERROR, "Usage: Assoc_Type [DataType_Type]");
+ return -1;
+ }
+
+ a = alloc_assoc_array (type, has_default_value);
+ if (a == NULL)
+ return -1;
+
+ if (NULL == (mmt = SLang_create_mmt (SLANG_ASSOC_TYPE, (VOID_STAR) a)))
+ {
+ delete_assoc_array (a);
+ return -1;
+ }
+
+ if (-1 == SLang_push_mmt (mmt))
+ {
+ SLang_free_mmt (mmt);
+ return -1;
+ }
+
+ return 0;
+}
+
+static void assoc_get_keys (SLang_Assoc_Array_Type *a)
+{
+ SLang_Array_Type *at;
+ int num;
+ unsigned int i, j;
+ char **data;
+
+ /* Note: If support for threads is added, then we need to modify this
+ * algorithm to prevent another thread from modifying the array.
+ * However, that should be handled in inner_interp.
+ */
+ num = a->num_elements;
+
+ if (NULL == (at = SLang_create_array (SLANG_STRING_TYPE, 0, NULL, &num, 1)))
+ return;
+
+ data = (char **)at->data;
+
+ i = 0;
+ for (j = 0; j < SLASSOC_HASH_TABLE_SIZE; j++)
+ {
+ _SLAssoc_Array_Element_Type *e;
+
+ e = a->elements[j];
+ while (e != NULL)
+ {
+ /* Next cannot fail because it is an slstring */
+ data [i] = SLang_create_slstring (e->key);
+ e = e->next;
+ i++;
+ }
+ }
+ (void) SLang_push_array (at, 1);
+}
+
+static int
+transfer_element (SLang_Class_Type *cl, VOID_STAR dest_data,
+ SLang_Object_Type *obj)
+{
+ unsigned int sizeof_type;
+ VOID_STAR src_data;
+
+#if USE_NEW_ANYTYPE_CODE
+ if (cl->cl_data_type == SLANG_ANY_TYPE)
+ {
+ SLang_Any_Type *any;
+
+ if ((-1 == _SLpush_slang_obj (obj))
+ || (-1 == SLang_pop_anytype (&any)))
+ return -1;
+
+ *(SLang_Any_Type **)dest_data = any;
+ return 0;
+ }
+#endif
+ /* Optimize for scalar */
+ if (cl->cl_class_type == SLANG_CLASS_TYPE_SCALAR)
+ {
+ sizeof_type = cl->cl_sizeof_type;
+ memcpy ((char *) dest_data, (char *)&obj->v, sizeof_type);
+ return 0;
+ }
+
+ src_data = _SLclass_get_ptr_to_value (cl, obj);
+
+ if (-1 == (*cl->cl_acopy) (cl->cl_data_type, src_data, dest_data))
+ return -1;
+
+ return 0;
+}
+
+static void assoc_get_values (SLang_Assoc_Array_Type *a)
+{
+ SLang_Array_Type *at;
+ int num;
+ unsigned int i, j;
+ char *dest_data;
+ unsigned char type;
+ SLang_Class_Type *cl;
+ unsigned int sizeof_type;
+
+ /* Note: If support for threads is added, then we need to modify this
+ * algorithm to prevent another thread from modifying the array.
+ * However, that should be handled in inner_interp.
+ */
+ num = a->num_elements;
+ type = a->type;
+
+ cl = _SLclass_get_class (type);
+ sizeof_type = cl->cl_sizeof_type;
+
+ if (NULL == (at = SLang_create_array (type, 0, NULL, &num, 1)))
+ return;
+
+ dest_data = (char *)at->data;
+
+ i = 0;
+ for (j = 0; j < SLASSOC_HASH_TABLE_SIZE; j++)
+ {
+ _SLAssoc_Array_Element_Type *e;
+
+ e = a->elements[j];
+ while (e != NULL)
+ {
+ if (-1 == transfer_element (cl, (VOID_STAR) dest_data, &e->value))
+ {
+ SLang_free_array (at);
+ return;
+ }
+
+ dest_data += sizeof_type;
+ e = e->next;
+ i++;
+ }
+ }
+ (void) SLang_push_array (at, 1);
+}
+
+static int assoc_key_exists (SLang_Assoc_Array_Type *a, char *key)
+{
+ return (NULL != find_element (a, key, _SLcompute_string_hash (key)));
+}
+
+static void assoc_delete_key (SLang_Assoc_Array_Type *a, char *key)
+{
+ unsigned int h;
+ _SLAssoc_Array_Element_Type *v, *v0;
+
+ h = (unsigned int) (_SLcompute_string_hash (key) % SLASSOC_HASH_TABLE_SIZE);
+
+ v0 = NULL;
+ v = a->elements[h];
+ while (v != NULL)
+ {
+ if (v->key == key)
+ {
+ if (v0 != NULL)
+ v0->next = v->next;
+ else
+ a->elements[h] = v->next;
+
+ free_element (v);
+ a->num_elements -= 1;
+ return;
+ }
+ v0 = v;
+ v = v->next;
+ }
+
+ /* No such element. Let it pass with no error. */
+}
+
+#define A SLANG_ASSOC_TYPE
+#define S SLANG_STRING_TYPE
+static SLang_Intrin_Fun_Type Assoc_Table [] =
+{
+ MAKE_INTRINSIC_1("assoc_get_keys", assoc_get_keys, SLANG_VOID_TYPE, A),
+ MAKE_INTRINSIC_1("assoc_get_values", assoc_get_values, SLANG_VOID_TYPE, A),
+ MAKE_INTRINSIC_2("assoc_key_exists", assoc_key_exists, SLANG_INT_TYPE, A, S),
+ MAKE_INTRINSIC_2("assoc_delete_key", assoc_delete_key, SLANG_VOID_TYPE, A, S),
+
+ SLANG_END_INTRIN_FUN_TABLE
+};
+#undef A
+#undef S
+
+static int assoc_length (unsigned char type, VOID_STAR v, unsigned int *len)
+{
+ SLang_Assoc_Array_Type *a;
+
+ (void) type;
+ a = (SLang_Assoc_Array_Type *) SLang_object_from_mmt (*(SLang_MMT_Type **)v);
+ *len = a->num_elements;
+ return 0;
+}
+
+struct _SLang_Foreach_Context_Type
+{
+ SLang_MMT_Type *mmt;
+ SLang_Assoc_Array_Type *a;
+ unsigned int this_hash_index;
+ unsigned int next_same_hash_index;
+#define CTX_WRITE_KEYS 1
+#define CTX_WRITE_VALUES 2
+ unsigned char flags;
+};
+
+static SLang_Foreach_Context_Type *
+cl_foreach_open (unsigned char type, unsigned int num)
+{
+ SLang_Foreach_Context_Type *c;
+ unsigned char flags;
+ SLang_MMT_Type *mmt;
+
+ (void) type;
+
+ if (NULL == (mmt = SLang_pop_mmt (SLANG_ASSOC_TYPE)))
+ return NULL;
+
+ flags = 0;
+
+ while (num--)
+ {
+ char *s;
+
+ if (-1 == SLang_pop_slstring (&s))
+ {
+ SLang_free_mmt (mmt);
+ return NULL;
+ }
+
+ if (0 == strcmp (s, "keys"))
+ flags |= CTX_WRITE_KEYS;
+ else if (0 == strcmp (s, "values"))
+ flags |= CTX_WRITE_VALUES;
+ else
+ {
+ SLang_verror (SL_NOT_IMPLEMENTED,
+ "using '%s' not supported by SLassoc_Type",
+ s);
+ SLang_free_slstring (s);
+ SLang_free_mmt (mmt);
+ return NULL;
+ }
+
+ SLang_free_slstring (s);
+ }
+
+ if (NULL == (c = (SLang_Foreach_Context_Type *) SLmalloc (sizeof (SLang_Foreach_Context_Type))))
+ {
+ SLang_free_mmt (mmt);
+ return NULL;
+ }
+
+ memset ((char *) c, 0, sizeof (SLang_Foreach_Context_Type));
+
+ if (flags == 0) flags = CTX_WRITE_VALUES|CTX_WRITE_KEYS;
+
+ c->flags = flags;
+ c->mmt = mmt;
+ c->a = (SLang_Assoc_Array_Type *) SLang_object_from_mmt (mmt);
+
+ return c;
+}
+
+static void cl_foreach_close (unsigned char type, SLang_Foreach_Context_Type *c)
+{
+ (void) type;
+ if (c == NULL) return;
+ SLang_free_mmt (c->mmt);
+ SLfree ((char *) c);
+}
+
+static int cl_foreach (unsigned char type, SLang_Foreach_Context_Type *c)
+{
+ SLang_Assoc_Array_Type *a;
+ _SLAssoc_Array_Element_Type *e;
+ unsigned int i, j;
+
+ (void) type;
+
+ if (c == NULL)
+ return -1;
+
+ a = c->a;
+
+ i = c->this_hash_index;
+ if (i >= SLASSOC_HASH_TABLE_SIZE)
+ return 0;
+
+ e = a->elements[i];
+
+ j = c->next_same_hash_index;
+ c->next_same_hash_index = j + 1;
+
+ while ((j > 0) && (e != NULL))
+ {
+ j--;
+ e = e->next;
+ }
+
+ if (e == NULL)
+ {
+ do
+ {
+ i++;
+ if (i >= SLASSOC_HASH_TABLE_SIZE)
+ return 0; /* no more */
+ }
+ while (a->elements [i] == NULL);
+
+ e = a->elements[i];
+ c->this_hash_index = i;
+ c->next_same_hash_index = 1;
+ }
+
+ if ((c->flags & CTX_WRITE_KEYS)
+ && (-1 == SLang_push_string (e->key)))
+ return -1;
+
+ if ((c->flags & CTX_WRITE_VALUES)
+ && (-1 == _SLpush_slang_obj (&e->value)))
+ return -1;
+
+ /* keep going */
+ return 1;
+}
+
+int SLang_init_slassoc (void)
+{
+ SLang_Class_Type *cl;
+
+ if (SLclass_is_class_defined (SLANG_ASSOC_TYPE))
+ return 0;
+
+ if (NULL == (cl = SLclass_allocate_class ("Assoc_Type")))
+ return -1;
+
+ (void) SLclass_set_destroy_function (cl, assoc_destroy);
+ (void) SLclass_set_aput_function (cl, assoc_aput);
+ (void) SLclass_set_aget_function (cl, assoc_aget);
+ (void) SLclass_set_anew_function (cl, assoc_anew);
+ cl->cl_length = assoc_length;
+ cl->cl_foreach_open = cl_foreach_open;
+ cl->cl_foreach_close = cl_foreach_close;
+ cl->cl_foreach = cl_foreach;
+
+ if (-1 == SLclass_register_class (cl, SLANG_ASSOC_TYPE, sizeof (SLang_Assoc_Array_Type), SLANG_CLASS_TYPE_MMT))
+ return -1;
+
+ if (-1 == SLadd_intrin_fun_table (Assoc_Table, "__SLASSOC__"))
+ return -1;
+
+ return 0;
+}
+
diff --git a/mdk-stage1/slang/slbstr.c b/mdk-stage1/slang/slbstr.c
new file mode 100644
index 000000000..b4b8c4c51
--- /dev/null
+++ b/mdk-stage1/slang/slbstr.c
@@ -0,0 +1,615 @@
+/* Copyright (c) 1998, 1999, 2001 John E. Davis
+ * This file is part of the S-Lang library.
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Perl Artistic License.
+ */
+#include "slinclud.h"
+
+#include "slang.h"
+#include "_slang.h"
+
+struct _SLang_BString_Type
+{
+ unsigned int num_refs;
+ unsigned int len;
+ int ptr_type;
+#define IS_SLSTRING 1
+#define IS_MALLOCED 2
+#define IS_NOT_TO_BE_FREED 3
+ union
+ {
+ unsigned char bytes[1];
+ unsigned char *ptr;
+ }
+ v;
+};
+
+#define BS_GET_POINTER(b) ((b)->ptr_type ? (b)->v.ptr : (b)->v.bytes)
+
+static SLang_BString_Type *create_bstring_of_type (char *bytes, unsigned int len, int type)
+{
+ SLang_BString_Type *b;
+ unsigned int size;
+
+ size = sizeof(SLang_BString_Type);
+ if (type == 0)
+ size += len;
+
+ if (NULL == (b = (SLang_BString_Type *)SLmalloc (size)))
+ return NULL;
+
+ b->len = len;
+ b->num_refs = 1;
+ b->ptr_type = type;
+
+ switch (type)
+ {
+ case 0:
+ if (bytes != NULL) memcpy ((char *) b->v.bytes, bytes, len);
+ /* Now \0 terminate it because we want to also use it as a C string
+ * whenever possible. Note that sizeof(SLang_BString_Type) includes
+ * space for 1 character and we allocated len extra bytes. Thus, it is
+ * ok to add a \0 to the end.
+ */
+ b->v.bytes[len] = 0;
+ break;
+
+ case IS_SLSTRING:
+ if (NULL == (b->v.ptr = (unsigned char *)SLang_create_nslstring (bytes, len)))
+ {
+ SLfree ((char *) b);
+ return NULL;
+ }
+ break;
+
+ case IS_MALLOCED:
+ case IS_NOT_TO_BE_FREED:
+ b->v.ptr = (unsigned char *)bytes;
+ bytes [len] = 0; /* NULL terminate */
+ break;
+ }
+
+ return b;
+}
+
+SLang_BString_Type *
+SLbstring_create (unsigned char *bytes, unsigned int len)
+{
+ return create_bstring_of_type ((char *)bytes, len, 0);
+}
+
+/* Note that ptr must be len + 1 bytes long for \0 termination */
+SLang_BString_Type *
+SLbstring_create_malloced (unsigned char *ptr, unsigned int len, int free_on_error)
+{
+ SLang_BString_Type *b;
+
+ if (ptr == NULL)
+ return NULL;
+
+ if (NULL == (b = create_bstring_of_type ((char *)ptr, len, IS_MALLOCED)))
+ {
+ if (free_on_error)
+ SLfree ((char *) ptr);
+ }
+ return b;
+}
+
+SLang_BString_Type *SLbstring_create_slstring (char *s)
+{
+ if (s == NULL)
+ return NULL;
+
+ return create_bstring_of_type (s, strlen (s), IS_SLSTRING);
+}
+
+SLang_BString_Type *SLbstring_dup (SLang_BString_Type *b)
+{
+ if (b != NULL)
+ b->num_refs += 1;
+
+ return b;
+}
+
+unsigned char *SLbstring_get_pointer (SLang_BString_Type *b, unsigned int *len)
+{
+ if (b == NULL)
+ {
+ *len = 0;
+ return NULL;
+ }
+ *len = b->len;
+ return BS_GET_POINTER(b);
+}
+
+void SLbstring_free (SLang_BString_Type *b)
+{
+ if (b == NULL)
+ return;
+
+ if (b->num_refs > 1)
+ {
+ b->num_refs -= 1;
+ return;
+ }
+
+ switch (b->ptr_type)
+ {
+ case 0:
+ case IS_NOT_TO_BE_FREED:
+ default:
+ break;
+
+ case IS_SLSTRING:
+ SLang_free_slstring ((char *)b->v.ptr);
+ break;
+
+ case IS_MALLOCED:
+ SLfree ((char *)b->v.ptr);
+ break;
+ }
+
+ SLfree ((char *) b);
+}
+
+int SLang_pop_bstring (SLang_BString_Type **b)
+{
+ return SLclass_pop_ptr_obj (SLANG_BSTRING_TYPE, (VOID_STAR *)b);
+}
+
+int SLang_push_bstring (SLang_BString_Type *b)
+{
+ if (b == NULL)
+ return SLang_push_null ();
+
+ b->num_refs += 1;
+
+ if (0 == SLclass_push_ptr_obj (SLANG_BSTRING_TYPE, (VOID_STAR)b))
+ return 0;
+
+ b->num_refs -= 1;
+ return -1;
+}
+
+static int
+bstring_bstring_bin_op_result (int op, unsigned char a, unsigned char b,
+ unsigned char *c)
+{
+ (void) a;
+ (void) b;
+ switch (op)
+ {
+ default:
+ return 0;
+
+ case SLANG_PLUS:
+ *c = SLANG_BSTRING_TYPE;
+ break;
+
+ case SLANG_GT:
+ case SLANG_GE:
+ case SLANG_LT:
+ case SLANG_LE:
+ case SLANG_EQ:
+ case SLANG_NE:
+ *c = SLANG_CHAR_TYPE;
+ break;
+ }
+ return 1;
+}
+
+static int compare_bstrings (SLang_BString_Type *a, SLang_BString_Type *b)
+{
+ unsigned int len;
+ int ret;
+
+ len = a->len;
+ if (b->len < len) len = b->len;
+
+ ret = memcmp ((char *)BS_GET_POINTER(b), (char *)BS_GET_POINTER(a), len);
+ if (ret != 0)
+ return ret;
+
+ if (a->len > b->len)
+ return 1;
+ if (a->len == b->len)
+ return 0;
+
+ return -1;
+}
+
+static SLang_BString_Type *
+concat_bstrings (SLang_BString_Type *a, SLang_BString_Type *b)
+{
+ unsigned int len;
+ SLang_BString_Type *c;
+ char *bytes;
+
+ len = a->len + b->len;
+
+ if (NULL == (c = SLbstring_create (NULL, len)))
+ return NULL;
+
+ bytes = (char *)BS_GET_POINTER(c);
+
+ memcpy (bytes, (char *)BS_GET_POINTER(a), a->len);
+ memcpy (bytes + a->len, (char *)BS_GET_POINTER(b), b->len);
+
+ return c;
+}
+
+static void free_n_bstrings (SLang_BString_Type **a, unsigned int n)
+{
+ unsigned int i;
+
+ if (a == NULL) return;
+
+ for (i = 0; i < n; i++)
+ {
+ SLbstring_free (a[i]);
+ a[i] = NULL;
+ }
+}
+
+static int
+bstring_bstring_bin_op (int op,
+ unsigned char a_type, VOID_STAR ap, unsigned int na,
+ unsigned char b_type, VOID_STAR bp, unsigned int nb,
+ VOID_STAR cp)
+{
+ char *ic;
+ SLang_BString_Type **a, **b, **c;
+ unsigned int n, n_max;
+ unsigned int da, db;
+
+ (void) a_type;
+ (void) b_type;
+
+ if (na == 1) da = 0; else da = 1;
+ if (nb == 1) db = 0; else db = 1;
+
+ if (na > nb) n_max = na; else n_max = nb;
+
+ a = (SLang_BString_Type **) ap;
+ b = (SLang_BString_Type **) bp;
+ for (n = 0; n < n_max; n++)
+ {
+ if ((*a == NULL) || (*b == NULL))
+ {
+ SLang_verror (SL_VARIABLE_UNINITIALIZED,
+ "Binary string element[%u] not initialized for binary operation", n);
+ return -1;
+ }
+ a += da; b += db;
+ }
+
+ a = (SLang_BString_Type **) ap;
+ b = (SLang_BString_Type **) bp;
+ ic = (char *) cp;
+ c = NULL;
+
+ switch (op)
+ {
+ case SLANG_PLUS:
+ /* Concat */
+ c = (SLang_BString_Type **) cp;
+ for (n = 0; n < n_max; n++)
+ {
+ if (NULL == (c[n] = concat_bstrings (*a, *b)))
+ goto return_error;
+
+ a += da; b += db;
+ }
+ break;
+
+ case SLANG_NE:
+ for (n = 0; n < n_max; n++)
+ {
+ ic [n] = (0 != compare_bstrings (*a, *b));
+ a += da;
+ b += db;
+ }
+ break;
+ case SLANG_GT:
+ for (n = 0; n < n_max; n++)
+ {
+ ic [n] = (compare_bstrings (*a, *b) > 0);
+ a += da;
+ b += db;
+ }
+ break;
+ case SLANG_GE:
+ for (n = 0; n < n_max; n++)
+ {
+ ic [n] = (compare_bstrings (*a, *b) >= 0);
+ a += da;
+ b += db;
+ }
+ break;
+ case SLANG_LT:
+ for (n = 0; n < n_max; n++)
+ {
+ ic [n] = (compare_bstrings (*a, *b) < 0);
+ a += da;
+ b += db;
+ }
+ break;
+ case SLANG_LE:
+ for (n = 0; n < n_max; n++)
+ {
+ ic [n] = (compare_bstrings (*a, *b) <= 0);
+ a += da;
+ b += db;
+ }
+ break;
+ case SLANG_EQ:
+ for (n = 0; n < n_max; n++)
+ {
+ ic [n] = (compare_bstrings (*a, *b) == 0);
+ a += da;
+ b += db;
+ }
+ break;
+ }
+ return 1;
+
+ return_error:
+ if (c != NULL)
+ {
+ free_n_bstrings (c, n);
+ while (n < n_max)
+ {
+ c[n] = NULL;
+ n++;
+ }
+ }
+ return -1;
+}
+
+/* If preserve_ptr, then use a[i] as the bstring data. See how this function
+ * is called by the binary op routines for why.
+ */
+static SLang_BString_Type **
+make_n_bstrings (SLang_BString_Type **b, char **a, unsigned int n, int ptr_type)
+{
+ unsigned int i;
+ int malloc_flag;
+
+ malloc_flag = 0;
+ if (b == NULL)
+ {
+ b = (SLang_BString_Type **) SLmalloc ((n + 1) * sizeof (SLang_BString_Type *));
+ if (b == NULL)
+ return NULL;
+ malloc_flag = 1;
+ }
+
+ for (i = 0; i < n; i++)
+ {
+ char *s = a[i];
+
+ if (s == NULL)
+ {
+ b[i] = NULL;
+ continue;
+ }
+
+ if (NULL == (b[i] = create_bstring_of_type (s, strlen(s), ptr_type)))
+ {
+ free_n_bstrings (b, i);
+ if (malloc_flag) SLfree ((char *) b);
+ return NULL;
+ }
+ }
+
+ return b;
+}
+
+static int
+bstring_string_bin_op (int op,
+ unsigned char a_type, VOID_STAR ap, unsigned int na,
+ unsigned char b_type, VOID_STAR bp, unsigned int nb,
+ VOID_STAR cp)
+{
+ SLang_BString_Type **b;
+ int ret;
+
+ if (NULL == (b = make_n_bstrings (NULL, (char **)bp, nb, IS_NOT_TO_BE_FREED)))
+ return -1;
+
+ b_type = SLANG_BSTRING_TYPE;
+ ret = bstring_bstring_bin_op (op,
+ a_type, ap, na,
+ b_type, (VOID_STAR) b, nb,
+ cp);
+ free_n_bstrings (b, nb);
+ SLfree ((char *) b);
+ return ret;
+}
+
+static int
+string_bstring_bin_op (int op,
+ unsigned char a_type, VOID_STAR ap, unsigned int na,
+ unsigned char b_type, VOID_STAR bp, unsigned int nb,
+ VOID_STAR cp)
+{
+ SLang_BString_Type **a;
+ int ret;
+
+ if (NULL == (a = make_n_bstrings (NULL, (char **)ap, na, IS_NOT_TO_BE_FREED)))
+ return -1;
+
+ a_type = SLANG_BSTRING_TYPE;
+ ret = bstring_bstring_bin_op (op,
+ a_type, (VOID_STAR) a, na,
+ b_type, bp, nb,
+ cp);
+ free_n_bstrings (a, na);
+ SLfree ((char *) a);
+
+ return ret;
+}
+
+static void bstring_destroy (unsigned char unused, VOID_STAR s)
+{
+ (void) unused;
+ SLbstring_free (*(SLang_BString_Type **) s);
+}
+
+static int bstring_push (unsigned char unused, VOID_STAR sptr)
+{
+ (void) unused;
+
+ return SLang_push_bstring (*(SLang_BString_Type **) sptr);
+}
+
+static int string_to_bstring (unsigned char a_type, VOID_STAR ap, unsigned int na,
+ unsigned char b_type, VOID_STAR bp)
+{
+ char **s;
+ SLang_BString_Type **b;
+
+ (void) a_type;
+ (void) b_type;
+
+ s = (char **) ap;
+ b = (SLang_BString_Type **) bp;
+
+ if (NULL == make_n_bstrings (b, s, na, IS_SLSTRING))
+ return -1;
+
+ return 1;
+}
+
+static int bstring_to_string (unsigned char a_type, VOID_STAR ap, unsigned int na,
+ unsigned char b_type, VOID_STAR bp)
+{
+ char **s;
+ unsigned int i;
+ SLang_BString_Type **a;
+
+ (void) a_type;
+ (void) b_type;
+
+ s = (char **) bp;
+ a = (SLang_BString_Type **) ap;
+
+ for (i = 0; i < na; i++)
+ {
+ SLang_BString_Type *ai = a[i];
+
+ if (ai == NULL)
+ {
+ s[i] = NULL;
+ continue;
+ }
+
+ if (NULL == (s[i] = SLang_create_slstring ((char *)BS_GET_POINTER(ai))))
+ {
+ while (i != 0)
+ {
+ i--;
+ SLang_free_slstring (s[i]);
+ s[i] = NULL;
+ }
+ return -1;
+ }
+ }
+
+ return 1;
+}
+
+static char *bstring_string (unsigned char type, VOID_STAR v)
+{
+ SLang_BString_Type *s;
+ unsigned char buf[128];
+ unsigned char *bytes, *bytes_max;
+ unsigned char *b, *bmax;
+
+ (void) type;
+
+ s = *(SLang_BString_Type **) v;
+ bytes = BS_GET_POINTER(s);
+ bytes_max = bytes + s->len;
+
+ b = buf;
+ bmax = buf + (sizeof (buf) - 4);
+
+ while (bytes < bytes_max)
+ {
+ unsigned char ch = *bytes;
+
+ if ((ch < 32) || (ch >= 127) || (ch == '\\'))
+ {
+ if (b + 4 > bmax)
+ break;
+
+ sprintf ((char *) b, "\\%03o", ch);
+ b += 4;
+ }
+ else
+ {
+ if (b == bmax)
+ break;
+
+ *b++ = ch;
+ }
+
+ bytes++;
+ }
+
+ if (bytes < bytes_max)
+ {
+ *b++ = '.';
+ *b++ = '.';
+ *b++ = '.';
+ }
+ *b = 0;
+
+ return SLmake_string ((char *)buf);
+}
+
+static unsigned int bstrlen_cmd (SLang_BString_Type *b)
+{
+ return b->len;
+}
+
+static SLang_Intrin_Fun_Type BString_Table [] = /*{{{*/
+{
+ MAKE_INTRINSIC_1("bstrlen", bstrlen_cmd, SLANG_UINT_TYPE, SLANG_BSTRING_TYPE),
+ MAKE_INTRINSIC_0("pack", _SLpack, SLANG_VOID_TYPE),
+ MAKE_INTRINSIC_2("unpack", _SLunpack, SLANG_VOID_TYPE, SLANG_STRING_TYPE, SLANG_BSTRING_TYPE),
+ MAKE_INTRINSIC_1("pad_pack_format", _SLpack_pad_format, SLANG_VOID_TYPE, SLANG_STRING_TYPE),
+ MAKE_INTRINSIC_1("sizeof_pack", _SLpack_compute_size, SLANG_UINT_TYPE, SLANG_STRING_TYPE),
+ SLANG_END_INTRIN_FUN_TABLE
+};
+
+int _SLang_init_bstring (void)
+{
+ SLang_Class_Type *cl;
+
+ if (NULL == (cl = SLclass_allocate_class ("BString_Type")))
+ return -1;
+ (void) SLclass_set_destroy_function (cl, bstring_destroy);
+ (void) SLclass_set_push_function (cl, bstring_push);
+ (void) SLclass_set_string_function (cl, bstring_string);
+
+ if (-1 == SLclass_register_class (cl, SLANG_BSTRING_TYPE, sizeof (char *),
+ SLANG_CLASS_TYPE_PTR))
+ return -1;
+
+ if ((-1 == SLclass_add_typecast (SLANG_BSTRING_TYPE, SLANG_STRING_TYPE, bstring_to_string, 1))
+ || (-1 == SLclass_add_typecast (SLANG_STRING_TYPE, SLANG_BSTRING_TYPE, string_to_bstring, 1))
+ || (-1 == SLclass_add_binary_op (SLANG_BSTRING_TYPE, SLANG_BSTRING_TYPE, bstring_bstring_bin_op, bstring_bstring_bin_op_result))
+ || (-1 == SLclass_add_binary_op (SLANG_STRING_TYPE, SLANG_BSTRING_TYPE, string_bstring_bin_op, bstring_bstring_bin_op_result))
+ || (-1 == SLclass_add_binary_op (SLANG_BSTRING_TYPE, SLANG_STRING_TYPE, bstring_string_bin_op, bstring_bstring_bin_op_result)))
+
+ return -1;
+
+ if (-1 == SLadd_intrin_fun_table (BString_Table, NULL))
+ return -1;
+
+ return 0;
+}
+
diff --git a/mdk-stage1/slang/slclass.c b/mdk-stage1/slang/slclass.c
new file mode 100644
index 000000000..733888cb8
--- /dev/null
+++ b/mdk-stage1/slang/slclass.c
@@ -0,0 +1,1391 @@
+/* User defined objects */
+/* Copyright (c) 1992, 1999, 2001 John E. Davis
+ * This file is part of the S-Lang library.
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Perl Artistic License.
+ */
+#include "slinclud.h"
+
+#include "slang.h"
+#include "_slang.h"
+
+#if _SLANG_OPTIMIZE_FOR_SPEED
+unsigned char _SLclass_Class_Type [256];
+#endif
+
+static SLang_Class_Type *Registered_Types[256];
+SLang_Class_Type *_SLclass_get_class (unsigned char type)
+{
+ SLang_Class_Type *cl;
+
+ cl = Registered_Types [type];
+ if (cl == NULL)
+ SLang_exit_error ("Application error: Type %d not registered", (int) type);
+
+ return cl;
+}
+
+int SLclass_is_class_defined (unsigned char type)
+{
+ return (NULL != Registered_Types[type]);
+}
+
+VOID_STAR _SLclass_get_ptr_to_value (SLang_Class_Type *cl,
+ SLang_Object_Type *obj)
+{
+ VOID_STAR p;
+
+ switch (cl->cl_class_type)
+ {
+ case SLANG_CLASS_TYPE_MMT:
+ case SLANG_CLASS_TYPE_PTR:
+ case SLANG_CLASS_TYPE_SCALAR:
+ p = (VOID_STAR) &obj->v;
+ break;
+
+ case SLANG_CLASS_TYPE_VECTOR:
+ p = obj->v.ptr_val;
+ break;
+
+ default:
+ p = NULL;
+ }
+ return p;
+}
+
+char *SLclass_get_datatype_name (unsigned char stype)
+{
+ SLang_Class_Type *cl;
+
+ cl = _SLclass_get_class (stype);
+ return cl->cl_name;
+}
+
+static int method_undefined_error (unsigned char type, char *method, char *name)
+{
+ if (name == NULL) name = SLclass_get_datatype_name (type);
+
+ SLang_verror (SL_TYPE_MISMATCH, "%s method not defined for %s",
+ method, name);
+ return -1;
+}
+
+static int
+scalar_vector_bin_op_result (int op, unsigned char a, unsigned char b,
+ unsigned char *c)
+{
+ (void) a; (void) b;
+ switch (op)
+ {
+ case SLANG_NE:
+ case SLANG_EQ:
+ *c = SLANG_INT_TYPE;
+ return 1;
+ }
+ return 0;
+}
+
+static int
+scalar_vector_bin_op (int op,
+ unsigned char a_type, VOID_STAR ap, unsigned int na,
+ unsigned char b_type, VOID_STAR bp, unsigned int nb,
+ VOID_STAR cp)
+{
+ int *c;
+ char *a, *b;
+ unsigned int da, db;
+ unsigned int n, n_max;
+ unsigned int data_type_len;
+ SLang_Class_Type *cl;
+
+ (void) b_type;
+ cl = _SLclass_get_class (a_type);
+
+ data_type_len = cl->cl_sizeof_type;
+
+ a = (char *) ap;
+ b = (char *) bp;
+ c = (int *) cp;
+
+ if (na == 1) da = 0; else da = data_type_len;
+ if (nb == 1) db = 0; else db = data_type_len;
+ if (na > nb) n_max = na; else n_max = nb;
+
+ switch (op)
+ {
+ default:
+ return 0;
+
+ case SLANG_NE:
+ for (n = 0; n < n_max; n++)
+ {
+ c[n] = (0 != SLMEMCMP(a, b, data_type_len));
+ a += da; b += db;
+ }
+ break;
+
+ case SLANG_EQ:
+ for (n = 0; n < n_max; n++)
+ {
+ c[n] = (0 == SLMEMCMP(a, b, data_type_len));
+ a += da; b += db;
+ }
+ break;
+ }
+ return 1;
+}
+
+static int scalar_fread (unsigned char type, FILE *fp, VOID_STAR ptr,
+ unsigned int desired, unsigned int *actual)
+{
+ unsigned int n;
+
+ n = fread ((char *) ptr, _SLclass_get_class (type)->cl_sizeof_type,
+ desired, fp);
+ *actual = n;
+ return 0;
+}
+
+static int scalar_fwrite (unsigned char type, FILE *fp, VOID_STAR ptr,
+ unsigned int desired, unsigned int *actual)
+{
+ unsigned int n;
+
+ n = fwrite ((char *) ptr, _SLclass_get_class (type)->cl_sizeof_type,
+ desired, fp);
+ *actual = n;
+ return 0;
+}
+
+static int vector_apush (unsigned char type, VOID_STAR ptr)
+{
+ SLang_Class_Type *cl;
+
+ cl = _SLclass_get_class (type);
+ return (*cl->cl_push)(type, (VOID_STAR) &ptr);
+}
+
+static int vector_apop (unsigned char type, VOID_STAR ptr)
+{
+ SLang_Class_Type *cl;
+
+ cl = _SLclass_get_class (type);
+ return (*cl->cl_pop)(type, (VOID_STAR) &ptr);
+}
+
+static int default_push_mmt (unsigned char type_unused, VOID_STAR ptr)
+{
+ SLang_MMT_Type *ref;
+
+ (void) type_unused;
+ ref = *(SLang_MMT_Type **) ptr;
+ return SLang_push_mmt (ref);
+}
+
+static void default_destroy_simple (unsigned char type_unused, VOID_STAR ptr_unused)
+{
+ (void) type_unused;
+ (void) ptr_unused;
+}
+
+static void default_destroy_user (unsigned char type, VOID_STAR ptr)
+{
+ (void) type;
+ SLang_free_mmt (*(SLang_MMT_Type **) ptr);
+}
+
+static int default_pop (unsigned char type, VOID_STAR ptr)
+{
+ return SLclass_pop_ptr_obj (type, (VOID_STAR *) ptr);
+}
+
+static int default_datatype_deref (unsigned char type)
+{
+ return method_undefined_error (type, "datatype_deref", NULL);
+}
+
+static int default_acopy (unsigned char type, VOID_STAR from, VOID_STAR to)
+{
+ SLang_Class_Type *cl;
+
+ cl = _SLclass_get_class (type);
+ if (-1 == (*cl->cl_apush) (type, from))
+ return -1;
+ return (*cl->cl_apop) (type, to);
+}
+
+static int default_dereference_object (unsigned char type, VOID_STAR ptr)
+{
+ (void) ptr;
+ return method_undefined_error (type, "dereference", NULL);
+}
+
+static char *default_string (unsigned char stype, VOID_STAR v)
+{
+ char buf [256];
+ char *s;
+#if SLANG_HAS_COMPLEX
+ double *cplx;
+#endif
+ s = buf;
+
+ switch (stype)
+ {
+ case SLANG_STRING_TYPE:
+ s = *(char **) v;
+ break;
+
+ case SLANG_NULL_TYPE:
+ s = "NULL";
+ break;
+
+ case SLANG_DATATYPE_TYPE:
+ s = SLclass_get_datatype_name ((unsigned char) *(int *)v);
+ break;
+
+#if SLANG_HAS_COMPLEX
+ case SLANG_COMPLEX_TYPE:
+ cplx = *(double **) v;
+ if (cplx[1] < 0)
+ sprintf (s, "(%g - %gi)", cplx [0], -cplx [1]);
+ else
+ sprintf (s, "(%g + %gi)", cplx [0], cplx [1]);
+ break;
+#endif
+ default:
+ s = SLclass_get_datatype_name (stype);
+ }
+
+ return SLmake_string (s);
+}
+
+static int
+use_cmp_bin_op_result (int op, unsigned char a, unsigned char b,
+ unsigned char *c)
+{
+ if (a != b)
+ return 0;
+ switch (op)
+ {
+ case SLANG_NE:
+ case SLANG_EQ:
+ case SLANG_LT:
+ case SLANG_LE:
+ case SLANG_GT:
+ case SLANG_GE:
+ *c = SLANG_INT_TYPE;
+ return 1;
+ }
+ return 0;
+}
+
+static int
+use_cmp_bin_op (int op,
+ unsigned char a_type, VOID_STAR ap, unsigned int na,
+ unsigned char b_type, VOID_STAR bp, unsigned int nb,
+ VOID_STAR cp)
+{
+ int *c;
+ char *a, *b;
+ unsigned int da, db;
+ unsigned int n, n_max;
+ unsigned int data_type_len;
+ SLang_Class_Type *cl;
+ int (*cmp)(unsigned char, VOID_STAR, VOID_STAR, int *);
+
+ (void) b_type;
+ cl = _SLclass_get_class (a_type);
+ cmp = cl->cl_cmp;
+ data_type_len = cl->cl_sizeof_type;
+
+ a = (char *) ap;
+ b = (char *) bp;
+ c = (int *) cp;
+
+ if (na == 1) da = 0; else da = data_type_len;
+ if (nb == 1) db = 0; else db = data_type_len;
+ if (na > nb) n_max = na; else n_max = nb;
+
+ switch (op)
+ {
+ int result;
+
+ default:
+ return 0;
+
+ case SLANG_NE:
+ for (n = 0; n < n_max; n++)
+ {
+ if (-1 == (*cmp) (a_type, (VOID_STAR)a, (VOID_STAR)b, &result))
+ return -1;
+ c[n] = (result != 0);
+ a += da; b += db;
+ }
+ break;
+
+ case SLANG_EQ:
+ for (n = 0; n < n_max; n++)
+ {
+ if (-1 == (*cmp) (a_type, (VOID_STAR)a, (VOID_STAR)b, &result))
+ return -1;
+ c[n] = (result == 0);
+ a += da; b += db;
+ }
+ break;
+
+ case SLANG_GT:
+ for (n = 0; n < n_max; n++)
+ {
+ if (-1 == (*cmp) (a_type, (VOID_STAR)a, (VOID_STAR)b, &result))
+ return -1;
+ c[n] = (result > 0);
+ a += da; b += db;
+ }
+ break;
+ case SLANG_GE:
+ for (n = 0; n < n_max; n++)
+ {
+ if (-1 == (*cmp) (a_type, (VOID_STAR)a, (VOID_STAR)b, &result))
+ return -1;
+ c[n] = (result >= 0);
+ a += da; b += db;
+ }
+ break;
+ case SLANG_LT:
+ for (n = 0; n < n_max; n++)
+ {
+ if (-1 == (*cmp) (a_type, (VOID_STAR)a, (VOID_STAR)b, &result))
+ return -1;
+ c[n] = (result < 0);
+ a += da; b += db;
+ }
+ break;
+ case SLANG_LE:
+ for (n = 0; n < n_max; n++)
+ {
+ if (-1 == (*cmp) (a_type, (VOID_STAR)a, (VOID_STAR)b, &result))
+ return -1;
+ c[n] = (result <= 0);
+ a += da; b += db;
+ }
+ break;
+ }
+ return 1;
+}
+
+
+int SLclass_get_class_id (SLang_Class_Type *cl)
+{
+ if (cl == NULL)
+ return -1;
+ return (int) cl->cl_data_type;
+}
+
+SLang_Class_Type *SLclass_allocate_class (char *name)
+{
+ SLang_Class_Type *cl;
+ unsigned int i;
+
+ for (i = 0; i < 256; i++)
+ {
+ cl = Registered_Types [i];
+ if ((cl != NULL)
+ && (0 == strcmp (cl->cl_name, name)))
+ {
+ SLang_verror (SL_DUPLICATE_DEFINITION, "Type name %s already exists", name);
+ return NULL;
+ }
+ }
+
+ cl = (SLang_Class_Type *) SLmalloc (sizeof (SLang_Class_Type));
+ if (cl == NULL) return NULL;
+
+ SLMEMSET ((char *) cl, 0, sizeof (SLang_Class_Type));
+
+ if (NULL == (cl->cl_name = SLang_create_slstring (name)))
+ {
+ SLfree ((char *) cl);
+ return NULL;
+ }
+
+ return cl;
+}
+
+static int DataType_Ids [256];
+
+int _SLang_push_datatype (unsigned char data_type)
+{
+ /* This data type could be a copy of another type, e.g., short and
+ * int if they are the same size (Int16 == Short). So, make sure
+ * we push the original and not the copy.
+ */
+ data_type = _SLclass_get_class (data_type)->cl_data_type;
+ return SLclass_push_int_obj (SLANG_DATATYPE_TYPE, (int) data_type);
+}
+
+static int datatype_deref (unsigned char type, VOID_STAR ptr)
+{
+ SLang_Class_Type *cl;
+ int status;
+
+ /* The parser generated code for this as if a function call were to be
+ * made. However, we are calling the deref object routine
+ * instead of the function call. So, I must simulate the function call.
+ */
+ if (-1 == _SL_increment_frame_pointer ())
+ return -1;
+
+ type = (unsigned char) *(int *) ptr;
+ cl = _SLclass_get_class (type);
+ status = (*cl->cl_datatype_deref) (type);
+
+ (void) _SL_decrement_frame_pointer ();
+ return status;
+}
+
+static int datatype_push (unsigned char type_unused, VOID_STAR ptr)
+{
+ (void) type_unused;
+ return _SLang_push_datatype (*(int *) ptr);
+}
+
+int _SLang_pop_datatype (unsigned char *type)
+{
+ int i;
+
+ if (-1 == SLclass_pop_int_obj (SLANG_DATATYPE_TYPE, &i))
+ return -1;
+
+ *type = (unsigned char) i;
+ return 0;
+}
+
+static int datatype_pop (unsigned char type, VOID_STAR ptr)
+{
+ if (-1 == _SLang_pop_datatype (&type))
+ return -1;
+
+ *(int *) ptr = type;
+ return 0;
+}
+
+int _SLclass_init (void)
+{
+ SLang_Class_Type *cl;
+
+ /* First initialize the container classes. This is so binary operations
+ * added later will work with them.
+ */
+ if (-1 == _SLarray_init_slarray ())
+ return -1;
+
+ /* DataType_Type */
+ if (NULL == (cl = SLclass_allocate_class ("DataType_Type")))
+ return -1;
+ cl->cl_pop = datatype_pop;
+ cl->cl_push = datatype_push;
+ cl->cl_dereference = datatype_deref;
+ if (-1 == SLclass_register_class (cl, SLANG_DATATYPE_TYPE, sizeof(int),
+ SLANG_CLASS_TYPE_SCALAR))
+ return -1;
+
+ return 0;
+}
+
+static int register_new_datatype (char *name, unsigned char type)
+{
+ DataType_Ids [type] = type;
+ return SLadd_intrinsic_variable (name, (VOID_STAR) (DataType_Ids + type),
+ SLANG_DATATYPE_TYPE, 1);
+}
+
+int SLclass_create_synonym (char *name, unsigned char type)
+{
+ if (NULL == _SLclass_get_class (type))
+ return -1;
+
+ return register_new_datatype (name, type);
+}
+
+int _SLclass_copy_class (unsigned char to, unsigned char from)
+{
+ SLang_Class_Type *cl = _SLclass_get_class (from);
+
+ if (Registered_Types[to] != NULL)
+ SLang_exit_error ("Application error: Class already exists");
+
+ Registered_Types[to] = cl;
+
+#if _SLANG_OPTIMIZE_FOR_SPEED
+ if (to != SLANG_UNDEFINED_TYPE)
+ _SLclass_Class_Type [to] = cl->cl_class_type;
+#endif
+ return 0;
+}
+
+int SLclass_register_class (SLang_Class_Type *cl, unsigned char type, unsigned int type_size, unsigned char class_type)
+{
+ char *name;
+ unsigned int i;
+ int can_binop = 1; /* scalar_vector_bin_op should work
+ * for all data types.
+ */
+
+ if (type == SLANG_VOID_TYPE) for (i = 0; i < 256; i++)
+ {
+ if ((Registered_Types[i] == NULL)
+ && (i != SLANG_VOID_TYPE))
+ {
+ type = (unsigned char) i;
+ break;
+ }
+ }
+
+ if ((NULL != Registered_Types [type])
+ || (type == SLANG_VOID_TYPE))
+ {
+ SLang_verror (SL_APPLICATION_ERROR, "Class type %d already in use", (int) type);
+ return -1;
+ }
+
+ cl->cl_data_type = type;
+ cl->cl_class_type = class_type;
+ name = cl->cl_name;
+
+ switch (class_type)
+ {
+ case SLANG_CLASS_TYPE_MMT:
+ if (cl->cl_push == NULL) cl->cl_push = default_push_mmt;
+ if (cl->cl_destroy == NULL)
+ return method_undefined_error (type, "destroy", name);
+ cl->cl_user_destroy_fun = cl->cl_destroy;
+ cl->cl_destroy = default_destroy_user;
+ type_size = sizeof (VOID_STAR);
+ break;
+
+ case SLANG_CLASS_TYPE_SCALAR:
+ if (cl->cl_destroy == NULL) cl->cl_destroy = default_destroy_simple;
+ if ((type_size == 0)
+ || (type_size > sizeof (_SL_Object_Union_Type)))
+ {
+ SLang_verror (SL_INVALID_PARM,
+ "Type size for %s not appropriate for SCALAR type",
+ name);
+ return -1;
+ }
+ if (cl->cl_pop == NULL)
+ return method_undefined_error (type, "pop", name);
+ if (cl->cl_fread == NULL) cl->cl_fread = scalar_fread;
+ if (cl->cl_fwrite == NULL) cl->cl_fwrite = scalar_fwrite;
+
+ can_binop = 1;
+ break;
+
+ case SLANG_CLASS_TYPE_PTR:
+ if (cl->cl_destroy == NULL)
+ return method_undefined_error (type, "destroy", name);
+ type_size = sizeof (VOID_STAR);
+ break;
+
+ case SLANG_CLASS_TYPE_VECTOR:
+ if (cl->cl_destroy == NULL)
+ return method_undefined_error (type, "destroy", name);
+ if (cl->cl_pop == NULL)
+ return method_undefined_error (type, "pop", name);
+ cl->cl_apop = vector_apop;
+ cl->cl_apush = vector_apush;
+ cl->cl_adestroy = default_destroy_simple;
+ if (cl->cl_fread == NULL) cl->cl_fread = scalar_fread;
+ if (cl->cl_fwrite == NULL) cl->cl_fwrite = scalar_fwrite;
+ can_binop = 1;
+ break;
+
+ default:
+ SLang_verror (SL_INVALID_PARM, "%s: unknown class type (%d)", name, class_type);
+ return -1;
+ }
+
+#if _SLANG_OPTIMIZE_FOR_SPEED
+ if (type != SLANG_UNDEFINED_TYPE)
+ _SLclass_Class_Type [type] = class_type;
+#endif
+
+ if (type_size == 0)
+ {
+ SLang_verror (SL_INVALID_PARM, "type size must be non-zero for %s", name);
+ return -1;
+ }
+
+ if (cl->cl_string == NULL) cl->cl_string = default_string;
+ if (cl->cl_acopy == NULL) cl->cl_acopy = default_acopy;
+ if (cl->cl_datatype_deref == NULL) cl->cl_datatype_deref = default_datatype_deref;
+
+ if (cl->cl_pop == NULL) cl->cl_pop = default_pop;
+
+ if (cl->cl_push == NULL)
+ return method_undefined_error (type, "push", name);
+
+ if (cl->cl_byte_code_destroy == NULL)
+ cl->cl_byte_code_destroy = cl->cl_destroy;
+ if (cl->cl_push_literal == NULL)
+ cl->cl_push_literal = cl->cl_push;
+
+ if (cl->cl_dereference == NULL)
+ cl->cl_dereference = default_dereference_object;
+
+ if (cl->cl_apop == NULL) cl->cl_apop = cl->cl_pop;
+ if (cl->cl_apush == NULL) cl->cl_apush = cl->cl_push;
+ if (cl->cl_adestroy == NULL) cl->cl_adestroy = cl->cl_destroy;
+ if (cl->cl_push_intrinsic == NULL) cl->cl_push_intrinsic = cl->cl_push;
+
+ if ((cl->cl_foreach == NULL)
+ || (cl->cl_foreach_open == NULL)
+ || (cl->cl_foreach_close == NULL))
+ {
+ cl->cl_foreach = _SLarray_cl_foreach;
+ cl->cl_foreach_open = _SLarray_cl_foreach_open;
+ cl->cl_foreach_close = _SLarray_cl_foreach_close;
+ }
+
+ cl->cl_sizeof_type = type_size;
+
+ if (NULL == (cl->cl_transfer_buf = (VOID_STAR) SLmalloc (type_size)))
+ return -1;
+
+ Registered_Types[type] = cl;
+
+ if (-1 == register_new_datatype (name, type))
+ return -1;
+
+ if (cl->cl_cmp != NULL)
+ {
+ if (-1 == SLclass_add_binary_op (type, type, use_cmp_bin_op, use_cmp_bin_op_result))
+ return -1;
+ }
+ else if (can_binop
+ && (-1 == SLclass_add_binary_op (type, type, scalar_vector_bin_op, scalar_vector_bin_op_result)))
+ return -1;
+
+ cl->cl_anytype_typecast = _SLanytype_typecast;
+
+ return 0;
+}
+
+int SLclass_add_math_op (unsigned char type,
+ int (*handler)(int,
+ unsigned char, VOID_STAR, unsigned int,
+ VOID_STAR),
+ int (*result) (int, unsigned char, unsigned char *))
+{
+ SLang_Class_Type *cl = _SLclass_get_class (type);
+
+ cl->cl_math_op = handler;
+ cl->cl_math_op_result_type = result;
+ return 0;
+}
+
+int SLclass_add_binary_op (unsigned char a, unsigned char b,
+ int (*f) (int,
+ unsigned char, VOID_STAR, unsigned int,
+ unsigned char, VOID_STAR, unsigned int,
+ VOID_STAR),
+ int (*r) (int, unsigned char, unsigned char, unsigned char *))
+{
+ SLang_Class_Type *cl;
+ SL_OOBinary_Type *ab;
+
+ if ((f == NULL) || (r == NULL))
+ {
+ SLang_verror (SL_INVALID_PARM, "SLclass_add_binary_op");
+ return -1;
+ }
+
+ cl = _SLclass_get_class (a);
+ (void) _SLclass_get_class (b);
+
+ if (NULL == (ab = (SL_OOBinary_Type *) SLmalloc (sizeof(SL_OOBinary_Type))))
+ return -1;
+
+ ab->data_type = b;
+ ab->binary_function = f;
+ ab->binary_result = r;
+ ab->next = cl->cl_binary_ops;
+ cl->cl_binary_ops = ab;
+
+ if ((a != SLANG_ARRAY_TYPE)
+ && (b != SLANG_ARRAY_TYPE))
+ {
+ if ((-1 == _SLarray_add_bin_op (a))
+ || (-1 == _SLarray_add_bin_op (b)))
+ return -1;
+ }
+
+ return 0;
+}
+
+int SLclass_add_unary_op (unsigned char type,
+ int (*f)(int,
+ unsigned char, VOID_STAR, unsigned int,
+ VOID_STAR),
+ int (*r)(int, unsigned char, unsigned char *))
+{
+ SLang_Class_Type *cl;
+
+ cl = _SLclass_get_class (type);
+ if ((f == NULL) || (r == NULL))
+ {
+ SLang_verror (SL_INVALID_PARM, "SLclass_add_unary_op");
+ return -1;
+ }
+
+ cl->cl_unary_op = f;
+ cl->cl_unary_op_result_type = r;
+
+ return 0;
+}
+
+int SLclass_add_app_unary_op (unsigned char type,
+ int (*f)(int,
+ unsigned char, VOID_STAR, unsigned int,
+ VOID_STAR),
+ int (*r)(int, unsigned char, unsigned char *))
+{
+ SLang_Class_Type *cl;
+
+ cl = _SLclass_get_class (type);
+ if ((f == NULL) || (r == NULL))
+ {
+ SLang_verror (SL_INVALID_PARM, "SLclass_add_app_unary_op");
+ return -1;
+ }
+
+ cl->cl_app_unary_op = f;
+ cl->cl_app_unary_op_result_type = r;
+
+ return 0;
+}
+
+int SLclass_set_pop_function (SLang_Class_Type *cl, int (*f)(unsigned char, VOID_STAR))
+{
+ if (cl == NULL) return -1;
+ cl->cl_pop = f;
+
+ return 0;
+}
+
+int SLclass_set_push_function (SLang_Class_Type *cl, int (*f)(unsigned char, VOID_STAR))
+{
+ if (cl == NULL) return -1;
+ cl->cl_push = f;
+
+ return 0;
+}
+
+int SLclass_set_string_function (SLang_Class_Type *cl, char *(*f)(unsigned char, VOID_STAR))
+{
+ if (cl == NULL) return -1;
+
+ cl->cl_string = f;
+ return 0;
+}
+
+int SLclass_set_destroy_function (SLang_Class_Type *cl, void (*f)(unsigned char, VOID_STAR))
+{
+ if (cl == NULL) return -1;
+
+ cl->cl_destroy = f;
+ return 0;
+}
+
+int SLclass_set_sget_function (SLang_Class_Type *cl, int (*f)(unsigned char, char *))
+{
+ if (cl == NULL) return -1;
+ cl->cl_sget = f;
+ return 0;
+}
+
+int SLclass_set_sput_function (SLang_Class_Type *cl, int (*f)(unsigned char, char *))
+{
+ if (cl == NULL) return -1;
+ cl->cl_sput = f;
+ return 0;
+}
+
+int SLclass_set_aget_function (SLang_Class_Type *cl, int (*f)(unsigned char, unsigned int))
+{
+ if (cl == NULL) return -1;
+ cl->cl_aget = f;
+ return 0;
+}
+
+int SLclass_set_aput_function (SLang_Class_Type *cl, int (*f)(unsigned char, unsigned int))
+{
+ if (cl == NULL) return -1;
+ cl->cl_aput = f;
+ return 0;
+}
+
+int SLclass_set_anew_function (SLang_Class_Type *cl, int (*f)(unsigned char, unsigned int))
+{
+ if (cl == NULL) return -1;
+ cl->cl_anew = f;
+ return 0;
+}
+
+/* Misc */
+void _SLclass_type_mismatch_error (unsigned char a, unsigned char b)
+{
+ SLang_verror (SL_TYPE_MISMATCH, "Expecting %s, found %s",
+ SLclass_get_datatype_name (a),
+ SLclass_get_datatype_name (b));
+}
+
+/* */
+
+static int null_binary_fun (int op,
+ unsigned char a, VOID_STAR ap, unsigned int na,
+ unsigned char b, VOID_STAR bp, unsigned int nb,
+ VOID_STAR cp)
+{
+ int *ic;
+ unsigned int i;
+ int c;
+
+ (void) ap; (void) bp;
+
+ switch (op)
+ {
+ case SLANG_EQ:
+ c = (a == b);
+ break;
+
+ case SLANG_NE:
+ c = (a != b);
+ break;
+
+ default:
+ return 0;
+ }
+
+ if (na > nb) nb = na;
+ ic = (int *) cp;
+ for (i = 0; i < nb; i++)
+ ic[i] = c;
+
+ return 1;
+}
+
+static char *get_binary_op_string (int op)
+{
+ static char *ops[SLANG_MOD] =
+ {
+ "+", "=", "*", "/", "==", "!=", ">", ">=", "<", "<=", "^",
+ "or", "and", "&", "|", "xor", "shl", "shr", "mod"
+ };
+
+ if ((op > SLANG_MOD) || (op <= 0))
+ return "??";
+ return ops[op - 1];
+}
+
+int (*_SLclass_get_binary_fun (int op,
+ SLang_Class_Type *a_cl, SLang_Class_Type *b_cl,
+ SLang_Class_Type **c_cl, int do_error))
+(int,
+ unsigned char, VOID_STAR, unsigned int,
+ unsigned char, VOID_STAR, unsigned int,
+ VOID_STAR)
+{
+ SL_OOBinary_Type *bt;
+ unsigned char a, b, c;
+
+ a = a_cl->cl_data_type;
+ b = b_cl->cl_data_type;
+
+ if ((a == SLANG_NULL_TYPE) || (b == SLANG_NULL_TYPE))
+ {
+ *c_cl = _SLclass_get_class (SLANG_INT_TYPE);
+ return null_binary_fun;
+ }
+
+ bt = a_cl->cl_binary_ops;
+
+ while (bt != NULL)
+ {
+ if (bt->data_type == b)
+ {
+ if (1 != (*bt->binary_result)(op, a, b, &c))
+ break;
+
+ if (c == a) *c_cl = a_cl;
+ else if (c == b) *c_cl = b_cl;
+ else *c_cl = _SLclass_get_class (c);
+
+ return bt->binary_function;
+ }
+
+ bt = bt->next;
+ }
+
+ if (do_error)
+ SLang_verror (SL_TYPE_MISMATCH, "%s %s %s is not possible",
+ a_cl->cl_name, get_binary_op_string (op), b_cl->cl_name);
+
+ *c_cl = NULL;
+ return NULL;
+}
+
+int (*_SLclass_get_unary_fun (int op,
+ SLang_Class_Type *a_cl,
+ SLang_Class_Type **b_cl,
+ int utype))
+(int, unsigned char, VOID_STAR, unsigned int, VOID_STAR)
+{
+ int (*f)(int, unsigned char, VOID_STAR, unsigned int, VOID_STAR);
+ int (*r)(int, unsigned char, unsigned char *);
+ unsigned char a;
+ unsigned char b;
+
+ switch (utype)
+ {
+ case _SLANG_BC_UNARY:
+ f = a_cl->cl_unary_op;
+ r = a_cl->cl_unary_op_result_type;
+ break;
+
+ case _SLANG_BC_MATH_UNARY:
+ f = a_cl->cl_math_op;
+ r = a_cl->cl_math_op_result_type;
+ break;
+
+ case _SLANG_BC_APP_UNARY:
+ f = a_cl->cl_app_unary_op;
+ r = a_cl->cl_app_unary_op_result_type;
+ break;
+
+ default:
+ f = NULL;
+ r = NULL;
+ }
+
+ a = a_cl->cl_data_type;
+ if ((f != NULL) && (r != NULL) && (1 == (*r) (op, a, &b)))
+ {
+ if (a == b)
+ *b_cl = a_cl;
+ else
+ *b_cl = _SLclass_get_class (b);
+ return f;
+ }
+
+ SLang_verror (SL_TYPE_MISMATCH, "undefined unary operation/function on %s",
+ a_cl->cl_name);
+
+ *b_cl = NULL;
+
+ return NULL;
+}
+
+int
+SLclass_typecast (unsigned char to_type, int is_implicit, int allow_array)
+{
+ unsigned char from_type;
+ SLang_Class_Type *cl_to, *cl_from;
+ SLang_Object_Type obj;
+ VOID_STAR ap;
+ VOID_STAR bp;
+ int status;
+
+ if (-1 == SLang_pop (&obj))
+ return -1;
+
+ from_type = obj.data_type;
+ if (from_type == to_type)
+ {
+ SLang_push (&obj);
+ return 0;
+ }
+
+ cl_from = _SLclass_get_class (from_type);
+
+ /* Since the typecast functions are designed to work on arrays,
+ * get the pointer to the value instead of just &obj.v.
+ */
+ ap = _SLclass_get_ptr_to_value (cl_from, &obj);
+
+ if ((from_type == SLANG_ARRAY_TYPE)
+ && (allow_array || (to_type != SLANG_ANY_TYPE)))
+ {
+ if (allow_array == 0)
+ goto return_error;
+
+ cl_to = _SLclass_get_class (SLANG_ARRAY_TYPE);
+ bp = cl_to->cl_transfer_buf;
+ status = _SLarray_typecast (from_type, ap, 1, to_type, bp, is_implicit);
+ }
+ else
+ {
+ int (*t) (unsigned char, VOID_STAR, unsigned int, unsigned char, VOID_STAR);
+
+ if (NULL == (t = _SLclass_get_typecast (from_type, to_type, is_implicit)))
+ {
+ SLang_free_object (&obj);
+ return -1;
+ }
+
+ cl_to = _SLclass_get_class (to_type);
+ bp = cl_to->cl_transfer_buf;
+ status = (*t) (from_type, ap, 1, to_type, bp);
+ }
+
+ if (1 == status)
+ {
+ if (-1 == (*cl_to->cl_apush)(to_type, bp))
+ {
+ (*cl_to->cl_adestroy) (to_type, bp);
+ SLang_free_object (&obj);
+ return -1;
+ }
+
+ /* cl_apush will push a copy, so destry this one */
+ (*cl_to->cl_adestroy) (to_type, bp);
+ SLang_free_object (&obj);
+ return 0;
+ }
+
+ return_error:
+
+ SLang_verror (SL_TYPE_MISMATCH, "Unable to typecast %s to %s",
+ cl_from->cl_name,
+ SLclass_get_datatype_name (to_type));
+ SLang_free_object (&obj);
+ return -1;
+}
+
+int (*_SLclass_get_typecast (unsigned char from, unsigned char to, int is_implicit))
+(unsigned char, VOID_STAR, unsigned int,
+ unsigned char, VOID_STAR)
+{
+ SL_Typecast_Type *t;
+ SLang_Class_Type *cl_from;
+
+ cl_from = _SLclass_get_class (from);
+
+ t = cl_from->cl_typecast_funs;
+ while (t != NULL)
+ {
+ if (t->data_type != to)
+ {
+ t = t->next;
+ continue;
+ }
+
+ if (is_implicit && (t->allow_implicit == 0))
+ break;
+
+ return t->typecast;
+ }
+
+ if (to == SLANG_ANY_TYPE)
+ return _SLanytype_typecast;
+
+ if ((is_implicit == 0)
+ && (cl_from->cl_void_typecast != NULL))
+ return cl_from->cl_void_typecast;
+
+ SLang_verror (SL_TYPE_MISMATCH, "Unable to typecast %s to %s",
+ cl_from->cl_name,
+ SLclass_get_datatype_name (to));
+
+ return NULL;
+}
+
+int
+SLclass_add_typecast (unsigned char from, unsigned char to,
+ int (*f)_PROTO((unsigned char, VOID_STAR, unsigned int,
+ unsigned char, VOID_STAR)),
+ int allow_implicit)
+{
+ SL_Typecast_Type *t;
+ SLang_Class_Type *cl;
+
+ cl = _SLclass_get_class (from);
+ if (to == SLANG_VOID_TYPE)
+ {
+ cl->cl_void_typecast = f;
+ return 0;
+ }
+
+ (void) _SLclass_get_class (to);
+
+ if (NULL == (t = (SL_Typecast_Type *) SLmalloc (sizeof (SL_Typecast_Type))))
+ return -1;
+
+ SLMEMSET((char *) t, 0, sizeof(SL_Typecast_Type));
+ t->data_type = to;
+ t->next = cl->cl_typecast_funs;
+ t->typecast = f;
+ t->allow_implicit = allow_implicit;
+
+ cl->cl_typecast_funs = t;
+
+ return 0;
+}
+
+SLang_MMT_Type *SLang_pop_mmt (unsigned char type) /*{{{*/
+{
+ SLang_MMT_Type *mmt;
+
+ if (-1 == SLclass_pop_ptr_obj (type, (VOID_STAR *) &mmt))
+ mmt = NULL;
+ return mmt;
+
+#if 0
+ SLang_Object_Type obj;
+ SLang_Class_Type *cl;
+
+ if (_SLang_pop_object_of_type (type, &obj))
+ return NULL;
+
+ cl = _SLclass_get_class (type);
+ if ((cl->cl_class_type == SLANG_CLASS_TYPE_MMT)
+ && (obj.data_type == type))
+ {
+ return obj.v.ref;
+ }
+
+ _SLclass_type_mismatch_error (type, obj.data_type);
+ SLang_free_object (&obj);
+ return NULL;
+#endif
+}
+
+/*}}}*/
+
+int SLang_push_mmt (SLang_MMT_Type *ref) /*{{{*/
+{
+ if (ref == NULL)
+ return SLang_push_null ();
+
+ ref->count += 1;
+
+ if (0 == SLclass_push_ptr_obj (ref->data_type, (VOID_STAR) ref))
+ return 0;
+
+ ref->count -= 1;
+ return -1;
+}
+
+/*}}}*/
+
+void SLang_inc_mmt (SLang_MMT_Type *ref)
+{
+ if (ref != NULL)
+ ref->count += 1;
+}
+
+VOID_STAR SLang_object_from_mmt (SLang_MMT_Type *ref)
+{
+ if (ref == NULL)
+ return NULL;
+
+ return ref->user_data;
+}
+
+SLang_MMT_Type *SLang_create_mmt (unsigned char t, VOID_STAR p)
+{
+ SLang_MMT_Type *ref;
+
+ (void) _SLclass_get_class (t); /* check to see if it is registered */
+
+ if (NULL == (ref = (SLang_MMT_Type *) SLmalloc (sizeof (SLang_MMT_Type))))
+ return NULL;
+
+ SLMEMSET ((char *) ref, 0, sizeof (SLang_MMT_Type));
+
+ ref->data_type = t;
+ ref->user_data = p;
+ /* FIXME!! To be consistent with other types, the reference count should
+ * be set to 1 here. However, doing so will require other code changes
+ * involving the use of MMTs. For instance, SLang_free_mmt would have
+ * to be called after every push of the MMT.
+ */
+ return ref;
+}
+
+void SLang_free_mmt (SLang_MMT_Type *ref)
+{
+ unsigned char type;
+ SLang_Class_Type *cl;
+
+ if (ref == NULL)
+ return;
+
+ /* This can be zero if SLang_create_mmt is called followed
+ * by this routine before anything gets a chance to attach itself
+ * to it.
+ */
+ if (ref->count > 1)
+ {
+ ref->count -= 1;
+ return;
+ }
+
+ type = ref->data_type;
+ cl = _SLclass_get_class (type);
+ (*cl->cl_user_destroy_fun) (type, ref->user_data);
+ SLfree ((char *)ref);
+}
+
+int SLang_push_value (unsigned char type, VOID_STAR v)
+{
+ SLang_Class_Type *cl;
+
+ cl = _SLclass_get_class (type);
+ return (*cl->cl_apush)(type, v);
+}
+
+int SLang_pop_value (unsigned char type, VOID_STAR v)
+{
+ SLang_Class_Type *cl;
+
+ cl = _SLclass_get_class (type);
+ return (*cl->cl_apop)(type, v);
+}
+
+void SLang_free_value (unsigned char type, VOID_STAR v)
+{
+ SLang_Class_Type *cl;
+
+ cl = _SLclass_get_class (type);
+ (*cl->cl_adestroy) (type, v);
+}
+
+/* These routines are very low-level and are designed for application data
+ * types to access the stack from their push/pop methods. The int and
+ * pointer versions are in slang.c
+ */
+#if SLANG_HAS_FLOAT
+int SLclass_push_double_obj (unsigned char type, double x)
+{
+ SLang_Object_Type obj;
+ obj.data_type = type;
+ obj.v.double_val = x;
+ return SLang_push (&obj);
+}
+int SLclass_push_float_obj (unsigned char type, float x)
+{
+ SLang_Object_Type obj;
+ obj.data_type = type;
+ obj.v.float_val = x;
+ return SLang_push (&obj);
+}
+
+#endif
+
+int SLclass_push_long_obj (unsigned char type, long x)
+{
+ SLang_Object_Type obj;
+ obj.data_type = type;
+ obj.v.long_val = x;
+ return SLang_push (&obj);
+}
+
+int SLclass_push_short_obj (unsigned char type, short x)
+{
+ SLang_Object_Type obj;
+ obj.data_type = type;
+ obj.v.short_val = x;
+ return SLang_push (&obj);
+}
+
+int SLclass_push_char_obj (unsigned char type, char x)
+{
+ SLang_Object_Type obj;
+ obj.data_type = type;
+ obj.v.char_val = x;
+ return SLang_push (&obj);
+}
+
+#if SLANG_HAS_FLOAT
+int SLclass_pop_double_obj (unsigned char type, double *x)
+{
+ SLang_Object_Type obj;
+
+ if (-1 == _SLang_pop_object_of_type (type, &obj, 0))
+ return -1;
+
+ *x = obj.v.double_val;
+ return 0;
+}
+
+int SLclass_pop_float_obj (unsigned char type, float *x)
+{
+ SLang_Object_Type obj;
+
+ if (-1 == _SLang_pop_object_of_type (type, &obj, 0))
+ return -1;
+
+ *x = obj.v.float_val;
+ return 0;
+}
+#endif
+
+int SLclass_pop_long_obj (unsigned char type, long *x)
+{
+ SLang_Object_Type obj;
+
+ if (-1 == _SLang_pop_object_of_type (type, &obj, 0))
+ return -1;
+
+ *x = obj.v.long_val;
+ return 0;
+}
+
+int SLclass_pop_int_obj (unsigned char type, int *x)
+{
+ SLang_Object_Type obj;
+
+ if (-1 == _SLang_pop_object_of_type (type, &obj, 0))
+ return -1;
+
+ *x = obj.v.int_val;
+ return 0;
+}
+
+int SLclass_pop_short_obj (unsigned char type, short *x)
+{
+ SLang_Object_Type obj;
+
+ if (-1 == _SLang_pop_object_of_type (type, &obj, 0))
+ return -1;
+
+ *x = obj.v.short_val;
+ return 0;
+}
+
+int SLclass_pop_char_obj (unsigned char type, char *x)
+{
+ SLang_Object_Type obj;
+
+ if (-1 == _SLang_pop_object_of_type (type, &obj, 0))
+ return -1;
+
+ *x = obj.v.char_val;
+ return 0;
+}
+
+int SLclass_pop_ptr_obj (unsigned char type, VOID_STAR *s)
+{
+ SLang_Object_Type obj;
+
+ if (-1 == _SLang_pop_object_of_type (type, &obj, 0))
+ {
+ *s = (VOID_STAR) NULL;
+ return -1;
+ }
+ *s = obj.v.ptr_val;
+ return 0;
+}
+
diff --git a/mdk-stage1/slang/slcmd.c b/mdk-stage1/slang/slcmd.c
new file mode 100644
index 000000000..4a00a90fc
--- /dev/null
+++ b/mdk-stage1/slang/slcmd.c
@@ -0,0 +1,351 @@
+/* cmd line facility for slang */
+/* Copyright (c) 1992, 1999, 2001 John E. Davis
+ * This file is part of the S-Lang library.
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Perl Artistic License.
+ */
+#include "slinclud.h"
+
+#if SLANG_HAS_FLOAT
+# include <math.h>
+#endif
+
+#include "slang.h"
+#include "_slang.h"
+
+#ifndef HAVE_STDLIB_H
+/* Oh dear. Where is the prototype for atof? If not in stdlib, then
+ * I do not know where. Not in math.h onsome systems either.
+ */
+extern double atof ();
+#endif
+
+static SLcmd_Cmd_Type *SLcmd_find_command (char *s, SLcmd_Cmd_Type *cmd)
+{
+ char *cmdstr;
+ char chs = *s++, ch;
+
+ while ((cmd->cmdfun != NULL)
+ && (NULL != (cmdstr = cmd->cmd))
+ && (0 != (ch = *cmdstr++)))
+ {
+ if ((ch == chs) && !strcmp (s, cmdstr)) return cmd;
+ cmd++;
+ }
+ return NULL;
+}
+
+static int extract_token (char **strptr, char *buf)
+{
+ char *s, *b;
+ char ch, quote;
+
+ *buf = 0;
+
+ s = *strptr;
+ while (((ch = *s) != 0)
+ && ((ch == ' ') || (ch == '\t') || (ch == '\n')))
+ s++;
+
+ *strptr = s;
+
+ if (ch == 0) return 0;
+ if (ch == '%') return 0;
+
+ b = buf;
+
+ *b++ = ch;
+ s++;
+
+ if ((ch == '\'') || (ch == '"'))
+ {
+ quote = ch;
+ while ((ch = *s) != 0)
+ {
+ s++;
+ *b++ = ch;
+ if (ch == quote)
+ break;
+
+ if (ch == '\\')
+ {
+ if (0 == (ch = *s))
+ break;
+ *b++ = ch;
+ s++;
+ }
+ }
+ *strptr = s;
+ *b = 0;
+ return 1;
+ }
+
+ while (((ch = *s) != 0)
+ && (ch != ' ')
+ && (ch != '\t')
+ && (ch != '\n')
+ && (ch != '%'))
+ *b++ = *s++;
+
+ *strptr = s;
+ *b = 0;
+ return 1;
+}
+
+static int allocate_arg_space (SLcmd_Cmd_Table_Type *table, int argc, unsigned int *space_ptr)
+{
+ unsigned int space = *space_ptr;
+ char *p;
+
+ if (argc + 1 < (int) space)
+ return 0;
+
+ if (space > 128)
+ {
+ if (space > 1024) space += 1024;
+ else space += 128;
+ }
+ else space += 32;
+
+ if (NULL == (p = SLrealloc ((char *)table->string_args, space * sizeof (char *))))
+ return -1;
+ table->string_args = (char **)p;
+ table->string_args [argc] = NULL;
+
+ if (NULL == (p = SLrealloc ((char *)table->int_args, space * sizeof (int))))
+ return -1;
+ table->int_args = (int *)p;
+
+ if (NULL == (p = SLrealloc ((char *)table->double_args, space * sizeof (double))))
+ return -1;
+ table->double_args = (double *)p;
+
+ if (NULL == (p = SLrealloc ((char *)table->arg_type, space * sizeof (unsigned char))))
+ return -1;
+ table->arg_type = (unsigned char *)p;
+
+ *space_ptr = space;
+ return 0;
+}
+
+int SLcmd_execute_string (char *str, SLcmd_Cmd_Table_Type *table)
+{
+ char *s, *b = NULL, *arg_type, *last_str, *cmd_name;
+ SLcmd_Cmd_Type *cmd;
+ char *buf;
+ int token_present;
+ int i;
+ int status;
+ unsigned int len;
+ int argc;
+ unsigned int space;
+
+ table->argc = 0;
+ table->string_args = NULL;
+ table->int_args = NULL;
+ table->double_args = NULL;
+ table->arg_type = NULL;
+
+ buf = SLmake_string (str);
+ if (buf == NULL)
+ return -1;
+
+ status = extract_token (&str, buf);
+ if (status <= 0)
+ {
+ SLfree (buf);
+ return status;
+ }
+
+ if (((len = strlen (buf)) >= 32)
+ || (NULL == (cmd = SLcmd_find_command (buf, table->table))))
+ {
+ SLang_verror (SL_UNDEFINED_NAME,"%s: invalid command", buf);
+ SLfree (buf);
+ return -1;
+ }
+
+ if (NULL == (cmd_name = SLmake_string (buf)))
+ {
+ SLfree (buf);
+ return -1;
+ }
+
+ space = 0;
+ argc = 0;
+ if (-1 == allocate_arg_space (table, argc, &space))
+ {
+ SLfree (buf);
+ return -1;
+ }
+ table->arg_type[argc] = SLANG_STRING_TYPE;
+ table->string_args[argc++] = cmd_name;
+
+ arg_type = cmd->arg_type;
+ status = -1;
+ while (*arg_type)
+ {
+ int guess_type = 0;
+
+ last_str = str;
+
+ if (-1 == allocate_arg_space (table, argc, &space))
+ goto error;
+
+ if (-1 == (token_present = extract_token (&str, buf)))
+ goto error;
+
+ table->string_args[argc] = NULL;
+
+ if (token_present)
+ {
+ b = buf;
+ len = strlen (b);
+
+ if ((*b == '"') && (len > 1))
+ {
+ b++;
+ len -= 2;
+ b[len] = 0;
+ guess_type = SLANG_STRING_TYPE;
+ SLexpand_escaped_string (buf, b, b + len);
+ len = strlen (buf);
+ }
+ else if ((*b == '\'') && (len > 1))
+ {
+ char ch;
+ b++;
+ len -= 2;
+ b[len] = 0;
+ guess_type = SLANG_INT_TYPE;
+ ch = *b;
+ if (ch == '\\')
+ (void) _SLexpand_escaped_char (b, &ch);
+ sprintf (buf, "%d", (unsigned char) ch);
+ len = strlen (buf);
+ }
+ else guess_type = SLang_guess_type (buf);
+ }
+
+ switch (*arg_type++)
+ {
+ /* variable argument number */
+ case 'v':
+ if (token_present == 0) break;
+ case 'V':
+ if (token_present == 0)
+ {
+ SLang_verror (SL_INVALID_PARM, "%s: Expecting argument", cmd_name);
+ goto error;
+ }
+
+ while (*last_str == ' ') last_str++;
+ len = strlen (last_str);
+ str = last_str + len;
+
+ s = SLmake_nstring (last_str, len);
+ if (s == NULL) goto error;
+
+ table->arg_type[argc] = SLANG_STRING_TYPE;
+ table->string_args[argc++] = s;
+ break;
+
+ case 's':
+ if (token_present == 0) break;
+ case 'S':
+ if (token_present == 0)
+ {
+ SLang_verror (SL_TYPE_MISMATCH, "%s: Expecting string argument", cmd_name);
+ goto error;
+ }
+
+ s = SLmake_nstring (buf, len);
+ if (s == NULL) goto error;
+ table->arg_type[argc] = SLANG_STRING_TYPE;
+ table->string_args[argc++] = s;
+ break;
+
+ /* integer argument */
+ case 'i':
+ if (token_present == 0) break;
+ case 'I':
+ if ((token_present == 0) || (SLANG_INT_TYPE != guess_type))
+ {
+ SLang_verror (SL_TYPE_MISMATCH, "%s: Expecting integer argument", cmd_name);
+ goto error;
+ }
+
+ table->arg_type[argc] = SLANG_INT_TYPE;
+ table->int_args[argc++] = SLatoi((unsigned char *) buf);
+ break;
+
+ /* floating point arg */
+#if SLANG_HAS_FLOAT
+ case 'f':
+ if (token_present == 0) break;
+ case 'F':
+ if ((token_present == 0) || (SLANG_STRING_TYPE == guess_type))
+ {
+ SLang_verror (SL_TYPE_MISMATCH, "%s: Expecting double argument", cmd_name);
+ goto error;
+ }
+ table->arg_type[argc] = SLANG_DOUBLE_TYPE;
+ table->double_args[argc++] = atof(buf);
+ break;
+#endif
+ /* Generic type */
+ case 'g':
+ if (token_present == 0) break;
+ case 'G':
+ if (token_present == 0)
+ {
+ SLang_verror (SL_TYPE_MISMATCH, "%s: Expecting argument", cmd_name);
+ goto error;
+ }
+
+ switch (guess_type)
+ {
+ case SLANG_INT_TYPE:
+ table->arg_type[argc] = SLANG_INT_TYPE;
+ table->int_args[argc++] = SLatoi((unsigned char *) buf);
+ break;
+
+ case SLANG_STRING_TYPE:
+ s = SLmake_nstring (buf, len);
+ if (s == NULL) goto error;
+
+ table->arg_type[argc] = SLANG_STRING_TYPE;
+ table->string_args[argc++] = s;
+ break;
+#if SLANG_HAS_FLOAT
+ case SLANG_DOUBLE_TYPE:
+ table->arg_type[argc] = SLANG_DOUBLE_TYPE;
+ table->double_args[argc++] = atof(buf);
+#endif
+ }
+ break;
+ }
+ }
+
+ /* call function */
+ status = (*cmd->cmdfun)(argc, table);
+
+ error:
+ if (table->string_args != NULL) for (i = 0; i < argc; i++)
+ {
+ if (NULL != table->string_args[i])
+ {
+ SLfree (table->string_args[i]);
+ table->string_args[i] = NULL;
+ }
+ }
+ SLfree ((char *)table->string_args); table->string_args = NULL;
+ SLfree ((char *)table->double_args); table->double_args = NULL;
+ SLfree ((char *)table->int_args); table->int_args = NULL;
+ SLfree ((char *)table->arg_type); table->arg_type = NULL;
+
+ SLfree (buf);
+ return status;
+}
+
diff --git a/mdk-stage1/slang/slcmplex.c b/mdk-stage1/slang/slcmplex.c
new file mode 100644
index 000000000..b210dfc04
--- /dev/null
+++ b/mdk-stage1/slang/slcmplex.c
@@ -0,0 +1,1142 @@
+/* Complex Data Type definition for S-Lang */
+/* Copyright (c) 1997, 1999, 2001 John E. Davis
+ * This file is part of the S-Lang library.
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Perl Artistic License.
+ */
+
+#include "slinclud.h"
+
+#include "slang.h"
+#include "_slang.h"
+
+/* The rest of the file is enclosed in this #if */
+#if SLANG_HAS_COMPLEX
+
+#if SLANG_HAS_FLOAT
+# include <math.h>
+#endif
+
+#ifdef PI
+# undef PI
+#endif
+#define PI 3.14159265358979323846
+
+int SLang_pop_complex (double *r, double *i)
+{
+ double *c;
+
+ switch (SLang_peek_at_stack ())
+ {
+ case SLANG_COMPLEX_TYPE:
+ if (-1 == SLclass_pop_ptr_obj (SLANG_COMPLEX_TYPE, (VOID_STAR *)&c))
+ return -1;
+ *r = c[0];
+ *i = c[1];
+ SLfree ((char *) c);
+ break;
+
+ default:
+ *i = 0.0;
+ if (-1 == SLang_pop_double (r, NULL, NULL))
+ return -1;
+ break;
+
+ case -1:
+ return -1;
+ }
+ return 0;
+}
+
+int SLang_push_complex (double r, double i)
+{
+ double *c;
+
+ c = (double *) SLmalloc (2 * sizeof (double));
+ if (c == NULL)
+ return -1;
+
+ c[0] = r;
+ c[1] = i;
+
+ if (-1 == SLclass_push_ptr_obj (SLANG_COMPLEX_TYPE, (VOID_STAR) c))
+ {
+ SLfree ((char *) c);
+ return -1;
+ }
+ return 0;
+}
+
+double *SLcomplex_times (double *c, double *a, double *b)
+{
+ double a_real, b_real, a_imag, b_imag;
+
+ a_real = a[0];
+ b_real = b[0];
+ a_imag = a[1];
+ b_imag = b[1];
+
+ c[0] = a_real * b_real - a_imag * b_imag;
+ c[1] = a_imag * b_real + a_real * b_imag;
+
+ return c;
+}
+
+double *SLcomplex_divide (double *c, double *a, double *b)
+{
+ double a_real, b_real, a_imag, b_imag;
+ double ratio, invden;
+
+ a_real = a[0];
+ b_real = b[0];
+ a_imag = a[1];
+ b_imag = b[1];
+
+ /* Do it this way to avoid overflow in the denom */
+ if (fabs(b_real) > fabs(b_imag))
+ {
+ ratio = b_imag / b_real;
+ invden = 1.0 / (b_real + b_imag * ratio);
+ c[0] = (a_real + ratio * a_imag) * invden;
+ c[1] = (a_imag - a_real * ratio) * invden;
+ }
+ else
+ {
+ ratio = b_real / b_imag;
+ invden = 1.0 / (b_real * ratio + b_imag);
+ c[0] = (a_real * ratio + a_imag) * invden;
+ c[1] = (a_imag * ratio - a_real) * invden;
+ }
+ return c;
+}
+
+/* a^b = exp (b log a); */
+double *SLcomplex_pow (double *c, double *a, double *b)
+{
+ return SLcomplex_exp (c, SLcomplex_times (c, b, SLcomplex_log (c, a)));
+}
+
+static double *complex_dpow (double *c, double *a, double b)
+{
+ SLcomplex_log (c, a);
+ c[0] *= b;
+ c[1] *= b;
+ return SLcomplex_exp (c, c);
+}
+
+static double *dcomplex_pow (double *c, double a, double *b)
+{
+ a = log (a);
+ c[0] = a * b[0];
+ c[1] = a * b[1];
+ return SLcomplex_exp (c, c);
+}
+
+double SLcomplex_abs (double *z)
+{
+ return SLmath_hypot (z[0], z[1]);
+}
+
+/* It appears that FORTRAN assumes that the branch cut for the log function
+ * is along the -x axis. So, use this for atan2:
+ */
+static double my_atan2 (double y, double x)
+{
+ double val;
+
+ val = atan (y/x);
+
+ if (x >= 0)
+ return val; /* I, IV */
+
+ if (y <= 0) /* III */
+ return val - PI;
+
+ return PI + val; /* II */
+}
+
+static void polar_form (double *r, double *theta, double *z)
+{
+ double x, y;
+
+ *r = SLcomplex_abs (z);
+
+ x = z[0];
+ y = z[1];
+
+ if (x == 0.0)
+ {
+ if (y >= 0)
+ *theta = 0.5 * PI;
+ else
+ *theta = 1.5 * PI;
+ }
+ else *theta = my_atan2 (y, x);
+}
+
+double *SLcomplex_sin (double *sinz, double *z)
+{
+ double x, y;
+
+ x = z[0]; y = z[1];
+ sinz[0] = sin (x) * cosh (y);
+ sinz[1] = cos (x) * sinh (y);
+ return sinz;
+}
+
+double *SLcomplex_cos (double *cosz, double *z)
+{
+ double x, y;
+
+ x = z[0]; y = z[1];
+ cosz[0] = cos (x) * cosh (y);
+ cosz[1] = -sin (x) * sinh (y);
+ return cosz;
+}
+
+double *SLcomplex_exp (double *expz, double *z)
+{
+ double r, i;
+
+ r = exp (z[0]);
+ i = z[1];
+ expz[0] = r * cos (i);
+ expz[1] = r * sin (i);
+ return expz;
+}
+
+double *SLcomplex_log (double *logz, double *z)
+{
+ double r, theta;
+
+ polar_form (&r, &theta, z); /* log R.e^(ix) = log R + ix */
+ logz[0] = log(r);
+ logz[1] = theta;
+ return logz;
+}
+
+double *SLcomplex_log10 (double *log10z, double *z)
+{
+ double l10 = log (10.0);
+ (void) SLcomplex_log (log10z, z);
+ log10z[0] = log10z[0] / l10;
+ log10z[1] = log10z[1] / l10;
+ return log10z;
+}
+
+double *SLcomplex_sqrt (double *sqrtz, double *z)
+{
+ double r, x, y;
+
+ x = z[0];
+ y = z[1];
+
+ r = SLmath_hypot (x, y);
+
+ if (r == 0.0)
+ {
+ sqrtz [0] = sqrtz [1] = 0.0;
+ return sqrtz;
+ }
+
+ if (x >= 0.0)
+ {
+ x = sqrt (0.5 * (r + x));
+ y = 0.5 * y / x;
+ }
+ else
+ {
+ r = sqrt (0.5 * (r - x));
+ x = 0.5 * y / r;
+ y = r;
+
+ if (x < 0.0)
+ {
+ x = -x;
+ y = -y;
+ }
+ }
+
+ sqrtz[0] = x;
+ sqrtz[1] = y;
+
+ return sqrtz;
+}
+
+double *SLcomplex_tan (double *tanz, double *z)
+{
+ double x, y, invden;
+
+ x = 2 * z[0];
+ y = 2 * z[1];
+ invden = 1.0 / (cos (x) + cosh (y));
+ tanz[0] = invden * sin (x);
+ tanz[1] = invden * sinh (y);
+ return tanz;
+}
+
+/* Utility Function */
+static void compute_alpha_beta (double *z, double *alpha, double *beta)
+{
+ double x, y, a, b;
+
+ x = z[0];
+ y = z[1];
+ a = 0.5 * SLmath_hypot (x + 1, y);
+ b = 0.5 * SLmath_hypot (x - 1, y);
+
+ *alpha = a + b;
+ *beta = a - b;
+}
+
+double *SLcomplex_asin (double *asinz, double *z)
+{
+ double alpha, beta;
+
+ compute_alpha_beta (z, &alpha, &beta);
+ asinz[0] = asin (beta);
+ asinz[1] = log (alpha + sqrt (alpha * alpha - 1));
+ return asinz;
+}
+
+double *SLcomplex_acos (double *acosz, double *z)
+{
+ double alpha, beta;
+
+ compute_alpha_beta (z, &alpha, &beta);
+ acosz[0] = acos (beta);
+ acosz[1] = -log (alpha + sqrt (alpha * alpha - 1));
+ return acosz;
+}
+
+double *SLcomplex_atan (double *atanz, double *z)
+{
+ double x, y;
+ double z1[2], z2[2];
+
+ x = z[0]; y = z[1];
+ z1[0] = x;
+ z1[1] = 1 + y;
+ z2[0] = -x;
+ z2[1] = 1 - y;
+
+ SLcomplex_log (z1, SLcomplex_divide (z2, z1, z2));
+ atanz[0] = -0.5 * z1[1];
+ atanz[1] = 0.5 * z1[0];
+
+ return atanz;
+}
+
+double *SLcomplex_sinh (double *sinhz, double *z)
+{
+ double x, y;
+ x = z[0]; y = z[1];
+ sinhz[0] = sinh (x) * cos (y);
+ sinhz[1] = cosh (x) * sin (y);
+ return sinhz;
+}
+
+double *SLcomplex_cosh (double *coshz, double *z)
+{
+ double x, y;
+ x = z[0]; y = z[1];
+ coshz[0] = cosh (x) * cos (y);
+ coshz[1] = sinh (x) * sin (y);
+ return coshz;
+}
+
+double *SLcomplex_tanh (double *tanhz, double *z)
+{
+ double x, y, invden;
+ x = 2 * z[0];
+ y = 2 * z[1];
+ invden = 1.0 / (cosh (x) + cos (y));
+ tanhz[0] = invden * sinh (x);
+ tanhz[1] = invden * sin (y);
+ return tanhz;
+}
+#if 0
+static double *not_implemented (char *fun, double *p)
+{
+ SLang_verror (SL_NOT_IMPLEMENTED, "%s for complex numbers has not been implemented",
+ fun);
+ *p = -1.0;
+ return p;
+}
+#endif
+/* Use: asinh(z) = -i asin(iz) */
+double *SLcomplex_asinh (double *asinhz, double *z)
+{
+ double iz[2];
+
+ iz[0] = -z[1];
+ iz[1] = z[0];
+
+ (void) SLcomplex_asin (iz, iz);
+ asinhz[0] = iz[1];
+ asinhz[1] = -iz[0];
+
+ return asinhz;
+}
+
+/* Use: acosh (z) = i acos(z) */
+double *SLcomplex_acosh (double *acoshz, double *z)
+{
+ double iz[2];
+
+ (void) SLcomplex_acos (iz, z);
+ acoshz[0] = -iz[1];
+ acoshz[1] = iz[0];
+
+ return acoshz;
+}
+
+/* Use: atanh(z) = -i atan(iz) */
+double *SLcomplex_atanh (double *atanhz, double *z)
+{
+ double iz[2];
+
+ iz[0] = -z[1];
+ iz[1] = z[0];
+
+ (void) SLcomplex_atan (iz, iz);
+ atanhz[0] = iz[1];
+ atanhz[1] = -iz[0];
+
+ return atanhz;
+}
+
+static int complex_binary_result (int op, unsigned char a, unsigned char b,
+ unsigned char *c)
+{
+ (void) a; (void) b;
+
+ switch (op)
+ {
+ default:
+ case SLANG_POW:
+ case SLANG_PLUS:
+ case SLANG_MINUS:
+ case SLANG_TIMES:
+ case SLANG_DIVIDE:
+ *c = SLANG_COMPLEX_TYPE;
+ break;
+
+ case SLANG_EQ:
+ case SLANG_NE:
+ *c = SLANG_CHAR_TYPE;
+ break;
+ }
+ return 1;
+}
+
+static int complex_complex_binary (int op,
+ unsigned char a_type, VOID_STAR ap, unsigned int na,
+ unsigned char b_type, VOID_STAR bp, unsigned int nb,
+ VOID_STAR cp)
+{
+ char *ic;
+ double *a, *b, *c;
+ unsigned int n, n_max;
+ unsigned int da, db;
+
+ (void) a_type;
+ (void) b_type;
+
+ a = (double *) ap;
+ b = (double *) bp;
+ c = (double *) cp;
+ ic = (char *) cp;
+
+ if (na == 1) da = 0; else da = 2;
+ if (nb == 1) db = 0; else db = 2;
+
+ if (na > nb) n_max = na; else n_max = nb;
+ n_max = 2 * n_max;
+
+ switch (op)
+ {
+ default:
+ return 0;
+
+ case SLANG_PLUS:
+ for (n = 0; n < n_max; n += 2)
+ {
+ c[n] = a[0] + b[0];
+ c[n + 1] = a[1] + b[1];
+ a += da; b += db;
+ }
+ break;
+
+ case SLANG_MINUS:
+ for (n = 0; n < n_max; n += 2)
+ {
+ c[n] = a[0] - b[0];
+ c[n + 1] = a[1] - b[1];
+ a += da; b += db;
+ }
+ break;
+
+ case SLANG_TIMES:
+ for (n = 0; n < n_max; n += 2)
+ {
+ SLcomplex_times (c + n, a, b);
+ a += da; b += db;
+ }
+ break;
+
+ case SLANG_DIVIDE: /* / */
+ for (n = 0; n < n_max; n += 2)
+ {
+ if ((b[0] == 0.0) && (b[1] == 0.0))
+ {
+ SLang_Error = SL_DIVIDE_ERROR;
+ return -1;
+ }
+ SLcomplex_divide (c + n, a, b);
+ a += da; b += db;
+ }
+ break;
+
+ case SLANG_EQ: /* == */
+ for (n = 0; n < n_max; n += 2)
+ {
+ ic[n/2] = ((a[0] == b[0]) && (a[1] == b[1]));
+ a += da; b += db;
+ }
+ break;
+
+ case SLANG_NE: /* != */
+ for (n = 0; n < n_max; n += 2)
+ {
+ ic[n/2] = ((a[0] != b[0]) || (a[1] != b[1]));
+ a += da; b += db;
+ }
+ break;
+
+ case SLANG_POW:
+ for (n = 0; n < n_max; n += 2)
+ {
+ SLcomplex_pow (c + n, a, b);
+ a += da; b += db;
+ }
+ break;
+
+ }
+
+ return 1;
+}
+
+static int complex_double_binary (int op,
+ unsigned char a_type, VOID_STAR ap, unsigned int na,
+ unsigned char b_type, VOID_STAR bp, unsigned int nb,
+ VOID_STAR cp)
+{
+ char *ic;
+ double *a, *b, *c;
+ unsigned int n, n_max;
+ unsigned int da, db;
+
+ (void) a_type;
+ (void) b_type;
+
+ a = (double *) ap;
+ b = (double *) bp;
+ c = (double *) cp;
+ ic = (char *) cp;
+
+ if (na == 1) da = 0; else da = 2;
+ if (nb == 1) db = 0; else db = 1;
+
+ if (na > nb) n_max = na; else n_max = nb;
+ n_max = 2 * n_max;
+
+ switch (op)
+ {
+ default:
+ return 0;
+
+ case SLANG_PLUS:
+ for (n = 0; n < n_max; n += 2)
+ {
+ c[n] = a[0] + b[0];
+ c[n + 1] = a[1];
+ a += da; b += db;
+ }
+ break;
+
+ case SLANG_MINUS:
+ for (n = 0; n < n_max; n += 2)
+ {
+ c[n] = a[0] - b[0];
+ c[n + 1] = a[1];
+ a += da; b += db;
+ }
+ break;
+
+ case SLANG_TIMES:
+ for (n = 0; n < n_max; n += 2)
+ {
+ double b0 = b[0];
+ c[n] = a[0] * b0;
+ c[n + 1] = a[1] * b0;
+ a += da; b += db;
+ }
+ break;
+
+ case SLANG_DIVIDE: /* / */
+ for (n = 0; n < n_max; n += 2)
+ {
+ double b0 = b[0];
+ if (b0 == 0.0)
+ {
+ SLang_Error = SL_DIVIDE_ERROR;
+ return -1;
+ }
+ c[n] = a[0] / b0;
+ c[n + 1] = a[1] / b0;
+ a += da; b += db;
+ }
+ break;
+
+ case SLANG_EQ: /* == */
+ for (n = 0; n < n_max; n += 2)
+ {
+ ic[n/2] = ((a[0] == b[0]) && (a[1] == 0.0));
+ a += da; b += db;
+ }
+ break;
+
+ case SLANG_NE: /* != */
+ for (n = 0; n < n_max; n += 2)
+ {
+ ic[n/2] = ((a[0] != b[0]) || (a[1] != 0.0));
+ a += da; b += db;
+ }
+ break;
+
+ case SLANG_POW:
+ for (n = 0; n < n_max; n += 2)
+ {
+ complex_dpow (c + n, a, b[0]);
+ a += da; b += db;
+ }
+ break;
+ }
+
+ return 1;
+}
+
+static int double_complex_binary (int op,
+ unsigned char a_type, VOID_STAR ap, unsigned int na,
+ unsigned char b_type, VOID_STAR bp, unsigned int nb,
+ VOID_STAR cp)
+{
+ char *ic;
+ double *a, *b, *c;
+ unsigned int n, n_max;
+ unsigned int da, db;
+
+ (void) a_type;
+ (void) b_type;
+
+ a = (double *) ap;
+ b = (double *) bp;
+ c = (double *) cp;
+ ic = (char *) cp;
+
+ if (na == 1) da = 0; else da = 1;
+ if (nb == 1) db = 0; else db = 2;
+
+ if (na > nb) n_max = na; else n_max = nb;
+ n_max = 2 * n_max;
+
+ switch (op)
+ {
+ default:
+ return 0;
+
+ case SLANG_PLUS:
+ for (n = 0; n < n_max; n += 2)
+ {
+ c[n] = a[0] + b[0];
+ c[n + 1] = b[1];
+ a += da; b += db;
+ }
+ break;
+
+ case SLANG_MINUS:
+ for (n = 0; n < n_max; n += 2)
+ {
+ c[n] = a[0] - b[0];
+ c[n + 1] = -b[1];
+ a += da; b += db;
+ }
+ break;
+
+ case SLANG_TIMES:
+ for (n = 0; n < n_max; n += 2)
+ {
+ double a0 = a[0];
+ c[n] = a0 * b[0];
+ c[n + 1] = a0 * b[1];
+ a += da; b += db;
+ }
+ break;
+
+ case SLANG_DIVIDE: /* / */
+ for (n = 0; n < n_max; n += 2)
+ {
+ double z[2];
+ if ((b[0] == 0.0) && (b[1] == 0.0))
+ {
+ SLang_Error = SL_DIVIDE_ERROR;
+ return -1;
+ }
+ z[0] = a[0];
+ z[1] = 0.0;
+ SLcomplex_divide (c + n, z, b);
+ a += da; b += db;
+ }
+ break;
+
+ case SLANG_EQ: /* == */
+ for (n = 0; n < n_max; n += 2)
+ {
+ ic[n/2] = ((a[0] == b[0]) && (0.0 == b[1]));
+ a += da; b += db;
+ }
+ break;
+
+ case SLANG_NE: /* != */
+ for (n = 0; n < n_max; n += 2)
+ {
+ ic[n/2] = ((a[0] != b[0]) || (0.0 != b[1]));
+ a += da; b += db;
+ }
+ break;
+
+ case SLANG_POW:
+ for (n = 0; n < n_max; n += 2)
+ {
+ dcomplex_pow (c + n, a[0], b);
+ a += da; b += db;
+ }
+ break;
+ }
+
+ return 1;
+}
+
+static int complex_generic_binary (int op,
+ unsigned char a_type, VOID_STAR ap, unsigned int na,
+ unsigned char b_type, VOID_STAR bp, unsigned int nb,
+ VOID_STAR cp)
+{
+ char *ic;
+ char *b;
+ double *a, *c;
+ unsigned int n, n_max;
+ unsigned int da, db;
+ unsigned int sizeof_b;
+ SLang_To_Double_Fun_Type to_double;
+
+ if (NULL == (to_double = SLarith_get_to_double_fun (b_type, &sizeof_b)))
+ return 0;
+
+ (void) a_type;
+
+ a = (double *) ap;
+ b = (char *) bp;
+ c = (double *) cp;
+ ic = (char *) cp;
+
+ if (na == 1) da = 0; else da = 2;
+ if (nb == 1) db = 0; else db = sizeof_b;
+
+ if (na > nb) n_max = na; else n_max = nb;
+ n_max = 2 * n_max;
+
+ switch (op)
+ {
+ default:
+ return 0;
+
+ case SLANG_POW:
+ for (n = 0; n < n_max; n += 2)
+ {
+ complex_dpow (c + n, a, to_double((VOID_STAR)b));
+ a += da; b += db;
+ }
+ break;
+
+ case SLANG_PLUS:
+ for (n = 0; n < n_max; n += 2)
+ {
+ c[n] = a[0] + to_double((VOID_STAR)b);
+ c[n + 1] = a[1];
+ a += da; b += db;
+ }
+ break;
+
+ case SLANG_MINUS:
+ for (n = 0; n < n_max; n += 2)
+ {
+ c[n] = a[0] - to_double((VOID_STAR)b);
+ c[n + 1] = a[1];
+ a += da; b += db;
+ }
+ break;
+
+ case SLANG_TIMES:
+ for (n = 0; n < n_max; n += 2)
+ {
+ double b0 = to_double((VOID_STAR)b);
+ c[n] = a[0] * b0;
+ c[n + 1] = a[1] * b0;
+ a += da; b += db;
+ }
+ break;
+
+ case SLANG_DIVIDE: /* / */
+ for (n = 0; n < n_max; n += 2)
+ {
+ double b0 = to_double((VOID_STAR)b);
+ if (b0 == 0)
+ {
+ SLang_Error = SL_DIVIDE_ERROR;
+ return -1;
+ }
+ c[n] = a[0] / b0;
+ c[n + 1] = a[1] / b0;
+ a += da; b += db;
+ }
+ break;
+
+ case SLANG_EQ: /* == */
+ for (n = 0; n < n_max; n += 2)
+ {
+ ic[n/2] = ((a[0] == to_double((VOID_STAR)b)) && (a[1] == 0.0));
+ a += da; b += db;
+ }
+ break;
+
+ case SLANG_NE: /* != */
+ for (n = 0; n < n_max; n += 2)
+ {
+ ic[n/2] = ((a[0] != to_double((VOID_STAR)b)) || (a[1] != 0.0));
+ a += da; b += db;
+ }
+ break;
+ }
+
+ return 1;
+}
+
+static int generic_complex_binary (int op,
+ unsigned char a_type, VOID_STAR ap, unsigned int na,
+ unsigned char b_type, VOID_STAR bp, unsigned int nb,
+ VOID_STAR cp)
+{
+ double *b, *c;
+ char *a, *ic;
+ unsigned int n, n_max;
+ unsigned int da, db;
+ unsigned int sizeof_a;
+ SLang_To_Double_Fun_Type to_double;
+
+ if (NULL == (to_double = SLarith_get_to_double_fun (a_type, &sizeof_a)))
+ return 0;
+
+ (void) b_type;
+
+ a = (char *) ap;
+ b = (double *) bp;
+ c = (double *) cp;
+ ic = (char *) cp;
+
+ if (na == 1) da = 0; else da = sizeof_a;
+ if (nb == 1) db = 0; else db = 2;
+
+ if (na > nb) n_max = na; else n_max = nb;
+ n_max = 2 * n_max;
+
+ switch (op)
+ {
+ default:
+ return 0;
+ case SLANG_POW:
+ for (n = 0; n < n_max; n += 2)
+ {
+ dcomplex_pow (c + n, to_double((VOID_STAR)a), b);
+ a += da; b += db;
+ }
+ break;
+
+ case SLANG_PLUS:
+ for (n = 0; n < n_max; n += 2)
+ {
+ c[n] = to_double((VOID_STAR)a) + b[0];
+ c[n + 1] = b[1];
+ a += da; b += db;
+ }
+ break;
+
+ case SLANG_MINUS:
+ for (n = 0; n < n_max; n += 2)
+ {
+ c[n] = to_double((VOID_STAR)a) - b[0];
+ c[n + 1] = -b[1];
+ a += da; b += db;
+ }
+ break;
+
+ case SLANG_TIMES:
+ for (n = 0; n < n_max; n += 2)
+ {
+ double a0 = to_double((VOID_STAR)a);
+ c[n] = a0 * b[0];
+ c[n + 1] = a0 * b[1];
+ a += da; b += db;
+ }
+ break;
+
+ case SLANG_DIVIDE: /* / */
+ for (n = 0; n < n_max; n += 2)
+ {
+ double z[2];
+ if ((b[0] == 0.0) && (b[1] == 0.0))
+ {
+ SLang_Error = SL_DIVIDE_ERROR;
+ return -1;
+ }
+ z[0] = to_double((VOID_STAR)a);
+ z[1] = 0.0;
+ SLcomplex_divide (c + n, z, b);
+ a += da; b += db;
+ }
+ break;
+
+ case SLANG_EQ: /* == */
+ for (n = 0; n < n_max; n += 2)
+ {
+ ic[n/2] = ((to_double((VOID_STAR)a) == b[0]) && (0.0 == b[1]));
+ a += da; b += db;
+ }
+ break;
+
+ case SLANG_NE: /* != */
+ for (n = 0; n < n_max; n += 2)
+ {
+ ic[n/2] = ((to_double((VOID_STAR)a) != b[0]) || (0.0 != b[1]));
+ a += da; b += db;
+ }
+ break;
+ }
+
+ return 1;
+}
+
+static int complex_unary_result (int op, unsigned char a, unsigned char *b)
+{
+ (void) a;
+
+ switch (op)
+ {
+ default:
+ return 0;
+
+ case SLANG_PLUSPLUS:
+ case SLANG_MINUSMINUS:
+ case SLANG_CHS:
+ case SLANG_MUL2:
+ *b = SLANG_COMPLEX_TYPE;
+ break;
+
+ case SLANG_SQR: /* |Real|^2 + |Imag|^2 ==> double */
+ case SLANG_ABS: /* |z| ==> double */
+ *b = SLANG_DOUBLE_TYPE;
+ break;
+
+ case SLANG_SIGN:
+ *b = SLANG_INT_TYPE;
+ break;
+ }
+ return 1;
+}
+
+static int complex_unary (int op,
+ unsigned char a_type, VOID_STAR ap, unsigned int na,
+ VOID_STAR bp)
+{
+ unsigned int n;
+ double *a, *b;
+ int *ic;
+
+ (void) a_type;
+
+ a = (double *) ap;
+ b = (double *) bp;
+ ic = (int *) bp;
+
+ na = 2 * na;
+
+ switch (op)
+ {
+ default:
+ return 0;
+
+ case SLANG_PLUSPLUS:
+ for (n = 0; n < na; n += 2) b[n] = (a[n] + 1);
+ break;
+ case SLANG_MINUSMINUS:
+ for (n = 0; n < na; n += 2) b[n] = (a[n] - 1);
+ break;
+ case SLANG_CHS:
+ for (n = 0; n < na; n += 2)
+ {
+ b[n] = -(a[n]);
+ b[n + 1] = -(a[n + 1]);
+ }
+ break;
+ case SLANG_SQR: /* |Real|^2 + |Imag|^2 ==> double */
+ for (n = 0; n < na; n += 2)
+ b[n/2] = (a[n] * a[n] + a[n + 1] * a[n + 1]);
+ break;
+
+ case SLANG_MUL2:
+ for (n = 0; n < na; n += 2)
+ {
+ b[n] = (2 * a[n]);
+ b[n + 1] = (2 * a[n + 1]);
+ }
+ break;
+
+ case SLANG_ABS: /* |z| ==> double */
+ for (n = 0; n < na; n += 2)
+ b[n/2] = SLcomplex_abs (a + n);
+ break;
+
+ case SLANG_SIGN:
+ /* Another creative extension. Lets return an integer which indicates
+ * whether the complex number is in the upperhalf plane or not.
+ */
+ for (n = 0; n < na; n += 2)
+ {
+ if (a[n + 1] < 0.0) ic[n/2] = -1;
+ else if (a[n + 1] > 0.0) ic[n/2] = 1;
+ else ic[n/2] = 0;
+ }
+ break;
+ }
+
+ return 1;
+}
+
+static int
+complex_typecast (unsigned char from_type, VOID_STAR from, unsigned int num,
+ unsigned char to_type, VOID_STAR to)
+{
+ double *z;
+ double *d;
+ char *i;
+ unsigned int n;
+ unsigned int sizeof_i;
+ SLang_To_Double_Fun_Type to_double;
+
+ (void) to_type;
+
+ z = (double *) to;
+
+ switch (from_type)
+ {
+ default:
+ if (NULL == (to_double = SLarith_get_to_double_fun (from_type, &sizeof_i)))
+ return 0;
+ i = (char *) from;
+ for (n = 0; n < num; n++)
+ {
+ *z++ = to_double ((VOID_STAR) i);
+ *z++ = 0.0;
+
+ i += sizeof_i;
+ }
+ break;
+
+ case SLANG_DOUBLE_TYPE:
+ d = (double *) from;
+ for (n = 0; n < num; n++)
+ {
+ *z++ = d[n];
+ *z++ = 0.0;
+ }
+ break;
+ }
+
+ return 1;
+}
+
+static void complex_destroy (unsigned char type, VOID_STAR ptr)
+{
+ (void) type;
+ SLfree ((char *)*(double **) ptr);
+}
+
+static int complex_push (unsigned char type, VOID_STAR ptr)
+{
+ double *z;
+
+ (void) type;
+ z = *(double **) ptr;
+ return SLang_push_complex (z[0], z[1]);
+}
+
+static int complex_pop (unsigned char type, VOID_STAR ptr)
+{
+ double *z;
+
+ (void) type;
+ z = *(double **) ptr;
+ return SLang_pop_complex (&z[0], &z[1]);
+}
+
+int _SLinit_slcomplex (void)
+{
+ SLang_Class_Type *cl;
+ unsigned char *types;
+
+ if (NULL == (cl = SLclass_allocate_class ("Complex_Type")))
+ return -1;
+
+ (void) SLclass_set_destroy_function (cl, complex_destroy);
+ (void) SLclass_set_push_function (cl, complex_push);
+ (void) SLclass_set_pop_function (cl, complex_pop);
+
+ if (-1 == SLclass_register_class (cl, SLANG_COMPLEX_TYPE, 2 * sizeof (double),
+ SLANG_CLASS_TYPE_VECTOR))
+ return -1;
+
+ types = _SLarith_Arith_Types;
+ while (*types != SLANG_DOUBLE_TYPE)
+ {
+ unsigned char t = *types++;
+
+ if ((-1 == SLclass_add_binary_op (t, SLANG_COMPLEX_TYPE, generic_complex_binary, complex_binary_result))
+ || (-1 == SLclass_add_binary_op (SLANG_COMPLEX_TYPE, t, complex_generic_binary, complex_binary_result))
+ || (-1 == (SLclass_add_typecast (t, SLANG_COMPLEX_TYPE, complex_typecast, 1))))
+ return -1;
+ }
+
+ if ((-1 == (SLclass_add_binary_op (SLANG_COMPLEX_TYPE, SLANG_COMPLEX_TYPE, complex_complex_binary, complex_binary_result)))
+ || (-1 == (SLclass_add_binary_op (SLANG_COMPLEX_TYPE, SLANG_DOUBLE_TYPE, complex_double_binary, complex_binary_result)))
+ || (-1 == (SLclass_add_binary_op (SLANG_DOUBLE_TYPE, SLANG_COMPLEX_TYPE, double_complex_binary, complex_binary_result)))
+ || (-1 == (SLclass_add_unary_op (SLANG_COMPLEX_TYPE, complex_unary, complex_unary_result)))
+ || (-1 == (SLclass_add_typecast (SLANG_DOUBLE_TYPE, SLANG_COMPLEX_TYPE, complex_typecast, 1))))
+ return -1;
+
+ return 0;
+}
+
+#endif /* if SLANG_HAS_COMPLEX */
+
diff --git a/mdk-stage1/slang/slcompat.c b/mdk-stage1/slang/slcompat.c
new file mode 100644
index 000000000..5aa122483
--- /dev/null
+++ b/mdk-stage1/slang/slcompat.c
@@ -0,0 +1,34 @@
+/* These functions are provided for backward compatibility and are obsolete.
+ * Copyright (c) 1992, 1999, 2001 John E. Davis
+ * This file is part of the S-Lang library.
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Perl Artistic License.
+ */
+
+#include "slinclud.h"
+
+#include "slang.h"
+#include "_slang.h"
+
+/* Compatibility */
+int SLang_init_slunix (void)
+{
+ if ((-1 == SLang_init_posix_dir ())
+ || (-1 == SLang_init_posix_process ())
+ || (-1 == SLdefine_for_ifdef ("__SLUNIX__")))
+ return -1;
+
+ return 0;
+}
+
+int SLang_init_slfile (void)
+{
+ if ((-1 == SLang_init_stdio ())
+ || (-1 == SLang_init_posix_dir ())
+ || (-1 == SLdefine_for_ifdef("__SLFILE__")))
+ return -1;
+
+ return 0;
+}
+
diff --git a/mdk-stage1/slang/slcurses.c b/mdk-stage1/slang/slcurses.c
new file mode 100644
index 000000000..f1212afc8
--- /dev/null
+++ b/mdk-stage1/slang/slcurses.c
@@ -0,0 +1,972 @@
+/* Copyright (c) 1998, 1999, 2001 John E. Davis
+ * This file is part of the S-Lang library.
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Perl Artistic License.
+ */
+#include "slinclud.h"
+
+#include <signal.h>
+#include <errno.h>
+
+#include "slang.h"
+#include "_slang.h"
+#include "slcurses.h"
+
+/* This file is meant to implement a primitive curses implementation in
+ * terms of SLsmg calls. The fact is that the interfaces are sufficiently
+ * different that a 100% emulation is not possible.
+ */
+
+SLcurses_Window_Type *SLcurses_Stdscr;
+int SLcurses_Esc_Delay = 150; /* 0.15 seconds */
+SLtt_Char_Type SLcurses_Acs_Map [128];
+int SLcurses_Is_Endwin = 1;
+int SLcurses_Num_Colors = 8;
+
+static void blank_line (SLsmg_Char_Type *b, unsigned int len, SLsmg_Char_Type color)
+{
+ SLsmg_Char_Type *bmax;
+
+ bmax = b + len;
+ color = SLSMG_BUILD_CHAR(' ', color);
+
+ while (b < bmax) *b++ = color;
+}
+
+static int va_mvprintw (SLcurses_Window_Type *w, int r, int c, int do_move,
+ char *fmt, va_list ap)
+{
+ char buf[1024];
+
+ if (do_move) SLcurses_wmove (w, r, c);
+
+ (void) _SLvsnprintf (buf, sizeof(buf), fmt, ap);
+
+ SLcurses_waddnstr (w, buf, -1);
+ return 0;
+}
+
+int SLcurses_mvprintw (int r, int c, char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ va_mvprintw (SLcurses_Stdscr, r, c, 1, fmt, ap);
+ va_end(ap);
+
+ return 0;
+}
+
+int SLcurses_mvwprintw (SLcurses_Window_Type *w, int r, int c, char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ va_mvprintw (w, r, c, 1, fmt, ap);
+ va_end(ap);
+
+ return 0;
+}
+
+int SLcurses_wprintw (SLcurses_Window_Type *w, char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ va_mvprintw (w, 0, 0, 0, fmt, ap);
+ va_end(ap);
+
+ return 0;
+}
+
+int SLcurses_printw (char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ va_mvprintw (SLcurses_Stdscr, 0, 0, 0, fmt, ap);
+ va_end(ap);
+
+ return 0;
+}
+
+int SLcurses_nil (void)
+{
+ return 0;
+}
+
+int SLcurses_has_colors(void)
+{
+ return SLtt_Use_Ansi_Colors;
+}
+
+int SLcurses_nodelay (SLcurses_Window_Type *w, int onoff)
+{
+ w->delay_off = (onoff ? 0 : -1);
+ return 0;
+}
+
+int SLcurses_wgetch (SLcurses_Window_Type *w)
+{
+ if (w == NULL)
+ return ERR;
+
+ SLcurses_wrefresh (w);
+
+ if ((w->delay_off == -1) ||
+ SLang_input_pending (w->delay_off))
+ {
+ if (w->use_keypad)
+ {
+ int ch = SLang_getkey ();
+ if (ch == '\033')
+ {
+ if (0 == SLang_input_pending (ESCDELAY / 100))
+ return ch;
+ }
+ else if (ch == 0xFFFF) return ERR;
+ SLang_ungetkey (ch);
+ return SLkp_getkey ();
+ }
+ return SLang_getkey ();
+ }
+
+ return ERR;
+}
+
+int SLcurses_getch (void)
+{
+ return SLcurses_wgetch (SLcurses_Stdscr);
+}
+
+/* This is a super hack. That fact is that SLsmg and curses
+ * are incompatible.
+ */
+static unsigned char Color_Objects[256];
+
+static unsigned int map_attr_to_object (SLtt_Char_Type attr)
+{
+ unsigned int obj;
+ SLtt_Char_Type at;
+
+ obj = (attr >> 8) & 0xFF;
+
+ if (SLtt_Use_Ansi_Colors)
+ {
+ if (Color_Objects[obj] != 0) return obj;
+
+ at = SLtt_get_color_object (obj & 0xF);
+
+ if (attr & A_BOLD) at |= SLTT_BOLD_MASK;
+ if (attr & A_UNDERLINE) at |= SLTT_ULINE_MASK;
+ if (attr & A_REVERSE) at |= SLTT_REV_MASK;
+
+ SLtt_set_color_object (obj, at);
+
+ Color_Objects[obj] = 1;
+ }
+ else obj = obj & 0xF0;
+
+ return obj;
+
+}
+
+int SLcurses_start_color (void)
+{
+ int f, b;
+ int obj;
+
+ if (SLtt_Use_Ansi_Colors == 0) return -1;
+
+ obj = 0;
+ for (f = 0; f < 16; f++)
+ {
+ for (b = 0; b < 16; b++)
+ {
+ obj++;
+ SLtt_set_color_fgbg (obj, f, b);
+ }
+ }
+ return 0;
+}
+
+#ifdef SIGINT
+static void sigint_handler (int sig)
+{
+ SLang_reset_tty ();
+ SLsmg_reset_smg ();
+ exit (sig);
+}
+#endif
+
+/* Values are assumed to be 0, 1, 2. This fact is exploited */
+static int TTY_State;
+
+static int init_tty (int suspend_ok)
+{
+ if (-1 == SLang_init_tty (-1, 1, 0))
+ return -1;
+
+#ifdef REAL_UNIX_SYSTEM
+ if (suspend_ok) SLtty_set_suspend_state (1);
+#endif
+ return 0;
+}
+
+int SLcurses_raw (void)
+{
+ TTY_State = 1;
+ return init_tty (0);
+}
+
+int SLcurses_cbreak (void)
+{
+ TTY_State = 2;
+ return init_tty (1);
+}
+
+#if defined(SIGTSTP) && defined(SIGSTOP)
+static void sigtstp_handler (int sig)
+{
+ sig = errno;
+
+ SLsmg_suspend_smg ();
+
+ if (TTY_State)
+ SLang_reset_tty ();
+
+ kill(getpid(),SIGSTOP);
+
+ SLsmg_resume_smg ();
+
+ if (TTY_State) init_tty (TTY_State - 1);
+
+ signal (SIGTSTP, sigtstp_handler);
+ errno = sig;
+}
+#endif
+
+SLcurses_Window_Type *SLcurses_initscr (void)
+{
+ SLcurses_Is_Endwin = 0;
+ SLsmg_Newline_Behavior = SLSMG_NEWLINE_MOVES;
+ SLtt_get_terminfo ();
+
+#if !defined(IBMPC_SYSTEM) && !defined(VMS)
+ if (-1 == (SLcurses_Num_Colors = SLtt_tgetnum ("Co")))
+#endif
+ SLcurses_Num_Colors = 8;
+
+ if ((-1 == SLkp_init ())
+ || (-1 == SLcurses_cbreak ())
+ || (NULL == (SLcurses_Stdscr = SLcurses_newwin (0, 0, 0, 0)))
+ || (-1 == SLsmg_init_smg ()))
+ {
+ SLang_doerror (NULL);
+ SLang_exit_error ("SLcurses_initscr: init failed\n");
+ return NULL;
+ }
+
+#ifdef SIGINT
+ signal (SIGINT, sigint_handler);
+#endif
+
+#if defined(SIGTSTP) && defined(SIGSTOP)
+ signal (SIGTSTP, sigtstp_handler);
+#endif
+
+ SLtt_set_mono (A_BOLD >> 8, NULL, SLTT_BOLD_MASK);
+ SLtt_set_mono (A_UNDERLINE >> 8, NULL, SLTT_ULINE_MASK);
+ SLtt_set_mono (A_REVERSE >> 8, NULL, SLTT_REV_MASK);
+ /* SLtt_set_mono (A_BLINK >> 8, NULL, SLTT_BLINK_MASK); */
+ SLtt_set_mono ((A_BOLD|A_UNDERLINE) >> 8, NULL, SLTT_ULINE_MASK|SLTT_BOLD_MASK);
+ SLtt_set_mono ((A_REVERSE|A_UNDERLINE) >> 8, NULL, SLTT_ULINE_MASK|SLTT_REV_MASK);
+
+ if (SLtt_Has_Alt_Charset)
+ {
+ SLcurses_Acs_Map[SLSMG_ULCORN_CHAR] = SLSMG_ULCORN_CHAR | A_ALTCHARSET;
+ SLcurses_Acs_Map[SLSMG_URCORN_CHAR] = SLSMG_URCORN_CHAR | A_ALTCHARSET;
+ SLcurses_Acs_Map[SLSMG_LLCORN_CHAR] = SLSMG_LLCORN_CHAR | A_ALTCHARSET;
+ SLcurses_Acs_Map[SLSMG_LRCORN_CHAR] = SLSMG_LRCORN_CHAR | A_ALTCHARSET;
+ SLcurses_Acs_Map[SLSMG_UTEE_CHAR] = SLSMG_UTEE_CHAR | A_ALTCHARSET;
+ SLcurses_Acs_Map[SLSMG_DTEE_CHAR] = SLSMG_DTEE_CHAR | A_ALTCHARSET;
+ SLcurses_Acs_Map[SLSMG_LTEE_CHAR] = SLSMG_LTEE_CHAR | A_ALTCHARSET;
+ SLcurses_Acs_Map[SLSMG_RTEE_CHAR] = SLSMG_RTEE_CHAR | A_ALTCHARSET;
+ SLcurses_Acs_Map[SLSMG_VLINE_CHAR] = SLSMG_VLINE_CHAR | A_ALTCHARSET;
+ SLcurses_Acs_Map[SLSMG_HLINE_CHAR] = SLSMG_HLINE_CHAR | A_ALTCHARSET;
+ SLcurses_Acs_Map[SLSMG_PLUS_CHAR] = SLSMG_PLUS_CHAR | A_ALTCHARSET;
+ SLcurses_Acs_Map[SLSMG_CKBRD_CHAR] = SLSMG_CKBRD_CHAR | A_ALTCHARSET;
+ }
+ else
+ {
+ /* ugly defaults to use on terminals which don't support graphics */
+ SLcurses_Acs_Map[SLSMG_ULCORN_CHAR] = '+';
+ SLcurses_Acs_Map[SLSMG_URCORN_CHAR] = '+';
+ SLcurses_Acs_Map[SLSMG_LLCORN_CHAR] = '+';
+ SLcurses_Acs_Map[SLSMG_LRCORN_CHAR] = '+';
+ SLcurses_Acs_Map[SLSMG_UTEE_CHAR] = '+';
+ SLcurses_Acs_Map[SLSMG_DTEE_CHAR] = '+';
+ SLcurses_Acs_Map[SLSMG_LTEE_CHAR] = '+';
+ SLcurses_Acs_Map[SLSMG_RTEE_CHAR] = '+';
+ SLcurses_Acs_Map[SLSMG_VLINE_CHAR] = '|';
+ SLcurses_Acs_Map[SLSMG_HLINE_CHAR] = '-';
+ SLcurses_Acs_Map[SLSMG_PLUS_CHAR] = '+';
+ SLcurses_Acs_Map[SLSMG_CKBRD_CHAR] = '#';
+ }
+
+ return SLcurses_Stdscr;
+}
+
+int SLcurses_wattrset (SLcurses_Window_Type *w, SLtt_Char_Type ch)
+{
+ unsigned int obj;
+
+ obj = map_attr_to_object (ch);
+ w->color = obj;
+ w->attr = ch;
+ return 0;
+}
+
+int SLcurses_wattroff (SLcurses_Window_Type *w, SLtt_Char_Type ch)
+{
+ if (SLtt_Use_Ansi_Colors)
+ return SLcurses_wattrset (w, 0);
+
+ w->attr &= ~ch;
+ return SLcurses_wattrset (w, w->attr);
+}
+
+int SLcurses_wattron (SLcurses_Window_Type *w, SLtt_Char_Type ch)
+{
+ if (SLtt_Use_Ansi_Colors)
+ return SLcurses_wattrset (w, ch);
+
+ w->attr |= ch;
+ return SLcurses_wattrset (w, w->attr);
+}
+
+int SLcurses_delwin (SLcurses_Window_Type *w)
+{
+ if (w == NULL) return 0;
+ if (w->lines != NULL)
+ {
+ SLsmg_Char_Type **lines = w->lines;
+ if (w->is_subwin == 0)
+ {
+ unsigned int r, rmax;
+
+ rmax = w->nrows;
+ for (r = 0; r < rmax; r++)
+ {
+ SLfree ((char *)lines[r]);
+ }
+ }
+
+ SLfree ((char *)lines);
+ }
+
+ SLfree ((char *)w);
+ if (w == SLcurses_Stdscr)
+ SLcurses_Stdscr = NULL;
+ return 0;
+}
+
+SLcurses_Window_Type *SLcurses_newwin (unsigned int nrows, unsigned int ncols,
+ unsigned int r, unsigned int c)
+{
+ SLcurses_Window_Type *win;
+ SLsmg_Char_Type **lines;
+
+ if (r >= (unsigned int) SLtt_Screen_Rows)
+ return NULL;
+ if (c >= (unsigned int) SLtt_Screen_Cols)
+ return NULL;
+
+ if (NULL == (win = (SLcurses_Window_Type *) SLmalloc (sizeof (SLcurses_Window_Type))))
+ return NULL;
+
+ SLMEMSET ((char *) win, 0, sizeof (SLcurses_Window_Type));
+
+ if (nrows == 0)
+ nrows = (unsigned int) SLtt_Screen_Rows - r;
+ if (ncols == 0)
+ ncols = (unsigned int) SLtt_Screen_Cols - c;
+
+ lines = (SLsmg_Char_Type **) SLmalloc (nrows * sizeof (SLsmg_Char_Type *));
+ if (lines == NULL)
+ {
+ SLcurses_delwin (win);
+ return NULL;
+ }
+
+ SLMEMSET ((char *) lines, 0, nrows * sizeof (SLsmg_Char_Type *));
+
+ win->lines = lines;
+ win->scroll_max = win->nrows = nrows;
+ win->ncols = ncols;
+ win->_begy = r;
+ win->_begx = c;
+ win->_maxx = (c + ncols) - 1;
+ win->_maxy = (r + nrows) - 1;
+ win->modified = 1;
+ win->delay_off = -1;
+
+ for (r = 0; r < nrows; r++)
+ {
+ SLsmg_Char_Type *b;
+
+ b = (SLsmg_Char_Type *) SLmalloc (ncols * sizeof (SLsmg_Char_Type));
+ if (b == NULL)
+ {
+ SLcurses_delwin (win);
+ return NULL;
+ }
+ lines [r] = b;
+ blank_line (b, ncols, 0);
+ }
+
+ return win;
+}
+
+int SLcurses_wmove (SLcurses_Window_Type *win, unsigned int r, unsigned int c)
+{
+ if (win == NULL) return -1;
+ win->_cury = r;
+ win->_curx = c;
+ win->modified = 1;
+ return 0;
+}
+
+static int do_newline (SLcurses_Window_Type *w)
+{
+ w->_curx = 0;
+ w->_cury += 1;
+ if (w->_cury >= w->scroll_max)
+ {
+ w->_cury = w->scroll_max - 1;
+ if (w->scroll_ok)
+ SLcurses_wscrl (w, 1);
+ }
+
+ return 0;
+}
+
+int SLcurses_waddch (SLcurses_Window_Type *win, SLtt_Char_Type attr)
+{
+ SLsmg_Char_Type *b, ch;
+ SLsmg_Char_Type color;
+
+ if (win == NULL) return -1;
+
+ if (win->_cury >= win->nrows)
+ {
+ /* Curses seems to move current postion to top of window. */
+ win->_cury = win->_curx = 0;
+ return -1;
+ }
+
+ win->modified = 1;
+
+ ch = SLSMG_EXTRACT_CHAR(attr);
+
+ if (attr == ch)
+ color = win->color;
+ else
+ {
+ /* hack to pick up the default color for graphics chars */
+ if (((attr & A_COLOR) == 0) && ((attr & A_ALTCHARSET) != 0))
+ {
+ /* FIXME: priority=medium: Use SLSMG_?? instead of << */
+ attr |= win->color << 8;
+ }
+ color = map_attr_to_object (attr);
+ }
+
+ if (ch < ' ')
+ {
+ if (ch == '\n')
+ {
+ SLcurses_wclrtoeol (win);
+ return do_newline (win);
+ }
+
+ if (ch == '\r')
+ {
+ win->_curx = 0;
+ return 0;
+ }
+
+ if (ch == '\b')
+ {
+ if (win->_curx > 0)
+ win->_curx--;
+
+ return 0;
+ }
+
+ /* HACK HACK!!!! */
+ if (ch == '\t') ch = ' ';
+ }
+
+ if (win->_curx >= win->ncols)
+ do_newline (win);
+
+ b = win->lines[win->_cury] + win->_curx;
+ *b = SLSMG_BUILD_CHAR(ch,color);
+ win->_curx++;
+
+ return 0;
+}
+
+int SLcurses_wnoutrefresh (SLcurses_Window_Type *w)
+{
+ unsigned int len;
+ unsigned int r, c;
+ unsigned int i, imax;
+
+ if (SLcurses_Is_Endwin)
+ {
+ if (TTY_State) init_tty (TTY_State - 1);
+ SLsmg_resume_smg ();
+ SLcurses_Is_Endwin = 0;
+ }
+
+ if (w == NULL)
+ {
+ SLsmg_refresh ();
+ return -1;
+ }
+
+ if (w->modified == 0)
+ return 0;
+
+ r = w->_begy;
+ c = w->_begx;
+
+ len = w->ncols;
+ imax = w->nrows;
+
+ for (i = 0; i < imax; i++)
+ {
+ SLsmg_gotorc (r, c);
+ SLsmg_write_color_chars (w->lines[i], len);
+ r++;
+ }
+
+ if (w->has_box)
+ SLsmg_draw_box(w->_begy, w->_begx, w->nrows, w->ncols);
+
+ SLsmg_gotorc (w->_begy + w->_cury, w->_begx + w->_curx);
+ w->modified = 0;
+ return 0;
+}
+
+int SLcurses_wrefresh (SLcurses_Window_Type *w)
+{
+ if (w == NULL)
+ return -1;
+
+ if (w->modified == 0)
+ return 0;
+
+ SLcurses_wnoutrefresh (w);
+ SLsmg_refresh ();
+ return 0;
+}
+
+int SLcurses_wclrtoeol (SLcurses_Window_Type *w)
+{
+ SLsmg_Char_Type *b, *bmax;
+ SLsmg_Char_Type blank;
+
+ if (w == NULL) return -1;
+ if (w->_cury >= w->nrows)
+ return 0;
+
+ w->modified = 1;
+
+ blank = SLSMG_BUILD_CHAR(' ',w->color);
+
+ b = w->lines[w->_cury];
+ bmax = b + w->ncols;
+ b += w->_curx;
+
+ while (b < bmax) *b++ = blank;
+ return 0;
+}
+
+int SLcurses_wclrtobot (SLcurses_Window_Type *w)
+{
+ SLsmg_Char_Type *b, *bmax;
+ SLsmg_Char_Type blank;
+ unsigned int r;
+
+ if (w == NULL) return -1;
+
+ w->modified = 1;
+ blank = SLSMG_BUILD_CHAR(' ',w->color);
+ SLcurses_wclrtoeol (w);
+ for (r = w->_cury + 1; r < w->nrows; r++)
+ {
+ b = w->lines [r];
+ bmax = b + w->ncols;
+
+ while (b < bmax) *b++ = blank;
+ }
+
+ return 0;
+}
+
+int SLcurses_wscrl (SLcurses_Window_Type *w, int n)
+{
+ SLsmg_Char_Type **lines;
+ unsigned int r, rmax, rmin, ncols;
+ SLsmg_Char_Type color;
+
+ if ((w == NULL) || (w->scroll_ok == 0))
+ return -1;
+
+ w->modified = 1;
+#if 0
+ if (w->is_subwin)
+ {
+ SLang_reset_tty ();
+ SLsmg_reset_smg ();
+ fprintf (stderr, "\rAttempt to scroll a subwindow\n");
+ exit (1);
+ }
+#endif
+
+ color = w->color;
+ ncols = w->ncols;
+ lines = w->lines;
+ rmax = w->scroll_max;
+ rmin = w->scroll_min;
+ if (rmax > w->nrows)
+ rmax = w->nrows;
+ if (rmin >= rmax)
+ return 0;
+
+ while (n > 0)
+ {
+ for (r = rmin + 1; r < rmax; r++)
+ {
+ /* lines[r - 1] = lines[r]; */
+ memcpy ((char *)lines[r - 1], (char *)lines[r],
+ sizeof (SLsmg_Char_Type) * ncols);
+ }
+ blank_line (lines[rmax - 1], ncols, color);
+ n--;
+ }
+
+ rmax--;
+ while (n < 0)
+ {
+ for (r = rmax; r > rmin; r--)
+ {
+ memcpy ((char *)lines[r], (char *)lines[r - 1],
+ sizeof (SLsmg_Char_Type) * ncols);
+ }
+ blank_line (lines[rmin], ncols, color);
+ n++;
+ }
+
+ /* wmove (w, w->nrows - 1, 0); */
+ /* wclrtobot (w); */
+ return 0;
+}
+
+/* Note: if len is < 0, entire string will be used.
+ */
+int SLcurses_waddnstr (SLcurses_Window_Type *w, char *str, int len)
+{
+ SLsmg_Char_Type *b;
+ SLsmg_Char_Type color;
+ unsigned char ch;
+ unsigned int nrows, ncols, crow, ccol;
+
+ if ((w == NULL)
+ || (str == NULL))
+ return -1;
+
+ w->modified = 1;
+ nrows = w->nrows;
+ ncols = w->ncols;
+ crow = w->_cury;
+ ccol = w->_curx;
+ color = w->color;
+
+ if (w->scroll_max <= nrows)
+ nrows = w->scroll_max;
+
+ if (crow >= nrows)
+ crow = 0; /* wrap back to top */
+
+ b = w->lines [crow] + ccol;
+
+ while (len && ((ch = (unsigned char) *str++) != 0))
+ {
+ len--;
+
+ if (ch == '\n')
+ {
+ w->_cury = crow;
+ w->_curx = ccol;
+ SLcurses_wclrtoeol (w);
+ do_newline (w);
+ crow = w->_cury;
+ ccol = w->_curx;
+ b = w->lines[crow];
+ continue;
+ }
+
+ if (ccol >= ncols)
+ {
+ ccol = 0;
+ crow++;
+ if (crow >= nrows)
+ {
+ w->_curx = 0;
+ w->_cury = crow;
+ do_newline (w);
+ crow = w->_cury;
+ ccol = w->_curx;
+ }
+
+ b = w->lines [crow];
+ }
+
+ if (ch == '\t')
+ {
+ unsigned int n = ccol;
+ n += SLsmg_Tab_Width;
+ n = SLsmg_Tab_Width - (n % SLsmg_Tab_Width);
+ if (ccol + n > ncols) n = ncols - len;
+ ccol += n;
+ while (n--)
+ *b++ = SLSMG_BUILD_CHAR(' ',color);
+ continue;
+ }
+
+ *b++ = SLSMG_BUILD_CHAR(ch, color);
+ ccol++;
+ }
+
+ w->_curx = ccol;
+ w->_cury = crow;
+
+ return 0;
+}
+
+/* This routine IS NOT CORRECT. It needs to compute the proper overlap
+ * and copy accordingly. Here, I just assume windows are same size.
+ */
+#if 0
+int SLcurses_overlay (SLcurses_Window_Type *swin, SLcurses_Window_Type *dwin)
+{
+ SLsmg_Char_Type *s, *smax, *d, *dmax;
+
+ if ((swin == NULL) || (dwin == NULL))
+ return -1;
+
+ s = swin->buf;
+ smax = swin->bufmax;
+ d = dwin->buf;
+ dmax = dwin->bufmax;
+
+ while ((s < smax) && (d < dmax))
+ {
+ SLsmg_Char_Type ch = *s++;
+ if (SLSMG_EXTRACT_CHAR(ch) != ' ')
+ *d = ch;
+ d++;
+ }
+
+ return -1; /* not implemented */
+}
+
+#endif
+
+SLcurses_Window_Type *SLcurses_subwin (SLcurses_Window_Type *orig,
+ unsigned int nlines, unsigned int ncols,
+ unsigned int begin_y, unsigned int begin_x)
+{
+ SLcurses_Window_Type *sw;
+ int r, c;
+ unsigned int i;
+
+ if (orig == NULL)
+ return NULL;
+
+ sw = (SLcurses_Window_Type *) SLmalloc (sizeof (SLcurses_Window_Type));
+ if (sw == NULL)
+ return NULL;
+
+ SLMEMSET ((char *)sw, 0, sizeof (SLcurses_Window_Type));
+#if 1
+ r = begin_y - orig->_begy;
+#else
+ r = 1 + ((int)orig->nrows - (int)nlines) / 2;
+#endif
+ if (r < 0) r = 0;
+ if (r + nlines > orig->nrows) nlines = orig->nrows - r;
+
+ c = ((int)orig->ncols - (int)ncols) / 2;
+ if (c < 0) c = 0;
+ if (c + ncols > orig->ncols) ncols = orig->ncols - c;
+
+ sw->scroll_min = 0;
+ sw->scroll_max = sw->nrows = nlines;
+ sw->ncols = ncols;
+ sw->_begy = begin_y;
+ sw->_begx = begin_x;
+ sw->_maxx = (begin_x + ncols) - 1;
+ sw->_maxy = (begin_y + nlines) - 1;
+
+ sw->lines = (SLsmg_Char_Type **) SLmalloc (nlines * sizeof (SLsmg_Char_Type *));
+ if (sw->lines == NULL)
+ {
+ SLcurses_delwin (sw);
+ return NULL;
+ }
+
+ for (i = 0; i < nlines; i++)
+ {
+ sw->lines [i] = orig->lines [r + i] + c;
+ }
+
+ sw->is_subwin = 1;
+ return sw;
+}
+
+int SLcurses_wclear (SLcurses_Window_Type *w)
+{
+ unsigned int i;
+
+ if (w != NULL) w->modified = 1;
+ for (i=0; i < w->nrows; i++)
+ blank_line (w->lines[i], w->ncols, w->color);
+ return 0;
+}
+
+int SLcurses_wdelch (SLcurses_Window_Type *w)
+{
+ SLsmg_Char_Type *p, *p1, *pmax;
+
+ p = w->lines[w->_cury];
+ pmax = p + w->ncols;
+ p += w->_curx;
+ p1 = p + 1;
+
+ while (p1 < pmax)
+ {
+ *p = *p1;
+ p = p1;
+ p1++;
+ }
+
+ if (p < pmax)
+ *p = SLSMG_BUILD_CHAR(' ',w->color);
+
+ w->modified = 1;
+ return 0;
+}
+
+int SLcurses_winsch (SLcurses_Window_Type *w, int ch)
+{
+ SLsmg_Char_Type *p, *p1, *pmax;
+
+ p = w->lines[w->_cury];
+ pmax = p + w->ncols;
+ p += w->_curx;
+ p1 = pmax - 1;
+
+ while (pmax > p)
+ {
+ *pmax = *p1;
+ pmax = p1;
+ p1--;
+ }
+
+ if (p < pmax)
+ *p = SLSMG_BUILD_CHAR(ch, w->color);
+
+ w->modified = 1;
+ return 0;
+}
+
+int SLcurses_endwin (void)
+{
+ SLcurses_Is_Endwin = 1;
+ SLsmg_suspend_smg ();
+ SLang_reset_tty ();
+ return 0;
+}
+
+#if 0
+int SLcurses_mvwscanw (SLcurses_Window_Type *w, unsigned int r, unsigned int c,
+ char *fmt, ...)
+{
+#if HAVE_VFSCANF
+ int ret;
+ va_list ap;
+
+ SLcurses_wmove (w, r, c);
+ SLcurses_wrefresh (w);
+
+ va_start(ap, fmt);
+ ret = vfscanf (stdin, fmt, ap);
+ va_end(ap);
+ return ret;
+#else
+ return 0;
+#endif
+}
+
+int SLcurses_wscanw (SLcurses_Window_Type *w, char *fmt, ...)
+{
+#if HAVE_VFSCANF
+ va_list ap;
+ int ret;
+
+ SLcurses_wrefresh (w);
+
+ va_start(ap, fmt);
+ ret = vfscanf (stdin, fmt, ap);
+ va_end(ap);
+
+ return ret;
+#else
+ return 0;
+#endif
+}
+
+int SLcurses_scanw (char *fmt, ...)
+{
+#ifdef HAVE_VFSCANF
+ va_list ap;
+ int ret;
+
+ SLcurses_wrefresh (SLcurses_Stdscr);
+
+ va_start(ap, fmt);
+ ret = vfscanf (stdin, fmt, ap);
+ va_end(ap);
+
+ return ret;
+#else
+ return 0;
+#endif
+}
+#endif
+
+int SLcurses_clearok (SLcurses_Window_Type *w, int bf)
+{
+ if (bf)
+ {
+ SLsmg_cls ();
+ w->modified = 1;
+ }
+ return 0;
+}
diff --git a/mdk-stage1/slang/slcurses.h b/mdk-stage1/slang/slcurses.h
new file mode 100644
index 000000000..fa082304f
--- /dev/null
+++ b/mdk-stage1/slang/slcurses.h
@@ -0,0 +1,353 @@
+/* Copyright (c) 1998, 1999, 2001 John E. Davis
+ * This file is part of the S-Lang library.
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Perl Artistic License.
+ */
+#include <stdio.h>
+
+#ifndef SLANG_VERSION
+# include <slang.h>
+#endif
+
+/* This is a temporary hack until lynx is fixed to not include this file. */
+#ifndef LYCURSES_H
+
+typedef struct
+{
+ unsigned int _begy, _begx, _maxy, _maxx;
+ unsigned int _curx, _cury;
+ unsigned int nrows, ncols;
+ unsigned int scroll_min, scroll_max;
+ SLsmg_Char_Type **lines;
+ SLsmg_Char_Type color;
+ int is_subwin;
+ SLtt_Char_Type attr;
+ int delay_off;
+ int scroll_ok;
+ int modified;
+ int has_box;
+ int use_keypad;
+}
+SLcurses_Window_Type;
+
+extern int SLcurses_wclrtobot (SLcurses_Window_Type *);
+extern int SLcurses_wscrl (SLcurses_Window_Type *, int);
+extern int SLcurses_wrefresh (SLcurses_Window_Type *);
+extern int SLcurses_delwin (SLcurses_Window_Type *);
+extern int SLcurses_wprintw (SLcurses_Window_Type *, char *, ...);
+extern SLcurses_Window_Type *SLcurses_newwin (unsigned int, unsigned int,
+ unsigned int, unsigned int);
+
+extern SLcurses_Window_Type *SLcurses_subwin (SLcurses_Window_Type *,
+ unsigned int, unsigned int,
+ unsigned int, unsigned int);
+
+extern int SLcurses_wnoutrefresh (SLcurses_Window_Type *);
+extern int SLcurses_wclrtoeol (SLcurses_Window_Type *);
+
+extern int SLcurses_wmove (SLcurses_Window_Type *, unsigned int, unsigned int);
+extern int SLcurses_waddch (SLcurses_Window_Type *, SLtt_Char_Type);
+extern int SLcurses_waddnstr (SLcurses_Window_Type *, char *, int);
+
+#define waddnstr SLcurses_waddnstr
+#define waddch SLcurses_waddch
+#define waddstr(w,s) waddnstr((w),(s),-1)
+#define addstr(x) waddstr(stdscr, (x))
+#define addnstr(s,n) waddnstr(stdscr,(s),(n))
+#define addch(ch) waddch(stdscr,(ch))
+
+#define mvwaddnstr(w,y,x,s,n) \
+ (-1 == wmove((w),(y),(x)) ? -1 : waddnstr((w),(s),(n)))
+#define mvwaddstr(w,y,x,s) \
+ (-1 == wmove((w),(y),(x)) ? -1 : waddnstr((w),(s), -1))
+#define mvaddnstr(y,x,s,n) mvwaddnstr(stdscr,(y),(x),(s),(n))
+#define mvaddstr(y,x,s) mvwaddstr(stdscr,(y),(x),(s))
+#define mvwaddch(w,y,x,c) \
+ ((-1 == wmove((w),(y),(x))) ? -1 : waddch((w),(c)))
+#define mvaddch(y,x,c) mvwaddch(stdscr,(y),(x),(c))
+
+extern int SLcurses_wclear (SLcurses_Window_Type *w);
+extern int SLcurses_printw (char *, ...);
+
+#if 0
+/* Why are these functions part of curses??? */
+extern int SLcurses_mvwscanw (SLcurses_Window_Type *, unsigned int, unsigned int,
+ char *, ...);
+extern int SLcurses_wscanw (SLcurses_Window_Type *, char *, ...);
+extern int SLcurses_scanw (char *, ...);
+#define mvwscanw SLcurses_mvwscanw
+#define wscanw SLcurses_wscanw
+#define scanw SLcurses_scanw
+#endif
+
+extern SLcurses_Window_Type *SLcurses_Stdscr;
+#define WINDOW SLcurses_Window_Type
+#define stdscr SLcurses_Stdscr
+
+#define subwin SLcurses_subwin
+#define wclrtobot SLcurses_wclrtobot
+#define wscrl SLcurses_wscrl
+#define scrl(n) wscrl(stdscr,(n))
+#define scroll(w) wscrl((w),1)
+#define wrefresh SLcurses_wrefresh
+#define delwin SLcurses_delwin
+#define wmove SLcurses_wmove
+#define newwin SLcurses_newwin
+#define wnoutrefresh SLcurses_wnoutrefresh
+#define werase(w) SLcurses_wmove((w),0,0); SLcurses_wclrtobot(w)
+#define wclear(w) SLcurses_wmove((w),0,0); SLcurses_wclrtobot(w)
+#define wprintw SLcurses_wprintw
+#define mvwprintw SLcurses_mvwprintw
+
+#define winch(w) \
+ ((((w)->_cury < (w)->nrows) && ((w)->_curx < (w)->ncols)) \
+ ? ((w)->lines[(w)->_cury][(w)->_curx]) : 0)
+
+#define inch() winch(stdscr)
+#define mvwinch(w,x,y) \
+ ((-1 != wmove((w),(x),(y))) ? winch(w) : (-1))
+#define doupdate SLsmg_refresh
+
+#define mvwin(w,a,b) ((w)->_begy = (a), (w)->_begx = (b))
+
+extern int SLcurses_mvprintw (int, int, char *, ...);
+extern int SLcurses_mvwprintw (SLcurses_Window_Type *, int, int, char *, ...);
+extern int SLcurses_has_colors(void);
+extern int SLcurses_nil (void);
+extern int SLcurses_wgetch (SLcurses_Window_Type *);
+extern int SLcurses_getch (void);
+
+extern int SLcurses_wattrset (SLcurses_Window_Type *, SLtt_Char_Type);
+extern int SLcurses_wattron (SLcurses_Window_Type *, SLtt_Char_Type);
+extern int SLcurses_wattroff (SLcurses_Window_Type *, SLtt_Char_Type);
+#define attrset(x) SLcurses_wattrset(stdscr, (x))
+#define attron(x) SLcurses_wattron(stdscr, (x))
+#define attroff(x) SLcurses_wattroff(stdscr, (x))
+#define wattrset(w, x) SLcurses_wattrset((w), (x))
+#define wattron(w, x) SLcurses_wattron((w), (x))
+#define wattroff(w, x) SLcurses_wattroff((w), (x))
+#define wattr_get(w) ((w)->color << 8)
+#define attr_get() wattr_get(stdscr)
+
+#define COLOR_PAIR(x) ((x) << 8)
+
+extern int SLcurses_start_color (void);
+#define start_color SLcurses_start_color
+
+#define ERR 0xFFFF
+#define wgetch SLcurses_wgetch
+#define getch SLcurses_getch
+
+extern int SLcurses_nodelay (SLcurses_Window_Type *, int);
+extern SLcurses_Window_Type *SLcurses_initscr (void);
+#define initscr SLcurses_initscr
+
+extern int SLcurses_cbreak (void);
+extern int SLcurses_raw (void);
+#define cbreak SLcurses_cbreak
+#define crmode SLcurses_cbreak
+#define raw SLcurses_raw
+#define noraw SLang_reset_tty
+#define nocbreak SLang_reset_tty
+
+#define mvprintw SLcurses_mvprintw
+#define has_colors SLcurses_has_colors
+#define nodelay SLcurses_nodelay
+
+#define ungetch SLang_ungetkey
+
+#define COLS SLtt_Screen_Cols
+#define LINES SLtt_Screen_Rows
+
+#define move(x,y) SLcurses_wmove(stdscr, (x), (y))
+#define wclrtoeol SLcurses_wclrtoeol
+#define clrtoeol() SLcurses_wclrtoeol(stdscr)
+#define clrtobot() SLcurses_wclrtobot(stdscr)
+
+#define printw SLcurses_printw
+#define mvprintw SLcurses_mvprintw
+#define wstandout(w) SLcurses_wattrset((w),A_STANDOUT)
+#define wstandend(w) SLcurses_wattrset((w),A_NORMAL)
+#define standout() SLcurses_wattrset(stdscr,A_STANDOUT)
+#define standend() SLcurses_wattrset(stdscr,A_NORMAL)
+
+#define refresh() SLcurses_wrefresh(stdscr)
+#define clear() SLcurses_wclear(stdscr)
+#define erase() werase(stdscr)
+#define touchline SLsmg_touch_lines
+#define resetterm SLang_reset_tty
+
+extern int SLcurses_endwin (void);
+#define endwin SLcurses_endwin
+extern int SLcurses_Is_Endwin;
+#define isendwin() SLcurses_Is_Endwin
+
+#define keypad(w,x) ((w)->use_keypad = (x))
+
+#define KEY_MIN SL_KEY_UP
+#define KEY_DOWN SL_KEY_DOWN
+#define KEY_UP SL_KEY_UP
+#define KEY_LEFT SL_KEY_LEFT
+#define KEY_RIGHT SL_KEY_RIGHT
+#define KEY_A1 SL_KEY_A1
+#define KEY_B1 SL_KEY_B1
+#define KEY_C1 SL_KEY_C1
+#define KEY_A2 SL_KEY_A2
+#define KEY_B2 SL_KEY_B2
+#define KEY_C2 SL_KEY_C2
+#define KEY_A3 SL_KEY_A3
+#define KEY_B3 SL_KEY_B3
+#define KEY_C3 SL_KEY_C3
+#define KEY_REDO SL_KEY_REDO
+#define KEY_UNDO SL_KEY_UNDO
+#define KEY_BACKSPACE SL_KEY_BACKSPACE
+#define KEY_PPAGE SL_KEY_PPAGE
+#define KEY_NPAGE SL_KEY_NPAGE
+#define KEY_HOME SL_KEY_HOME
+#define KEY_END SL_KEY_END
+#define KEY_F0 SL_KEY_F0
+#define KEY_F SL_KEY_F
+#define KEY_ENTER SL_KEY_ENTER
+#define KEY_MAX 0xFFFF
+
+/* Ugly Hacks that may not work */
+#define flushinp SLcurses_nil
+#define winsertln(w) \
+ ((w)->scroll_min=(w)->_cury, \
+ (w)->scroll_max=(w)->nrows, \
+ wscrl((w), -1))
+
+extern SLtt_Char_Type SLcurses_Acs_Map [128];
+#define acs_map SLcurses_Acs_Map
+
+#define ACS_ULCORNER (acs_map[SLSMG_ULCORN_CHAR])
+#define ACS_URCORNER (acs_map[SLSMG_URCORN_CHAR])
+#define ACS_LRCORNER (acs_map[SLSMG_LRCORN_CHAR])
+#define ACS_LLCORNER (acs_map[SLSMG_LLCORN_CHAR])
+#define ACS_TTEE (acs_map[SLSMG_UTEE_CHAR])
+#define ACS_LTEE (acs_map[SLSMG_LTEE_CHAR])
+#define ACS_RTEE (acs_map[SLSMG_RTEE_CHAR])
+#define ACS_BTEE (acs_map[SLSMG_DTEE_CHAR])
+#define ACS_PLUS (acs_map[SLSMG_PLUS_CHAR])
+#define ACS_VLINE (acs_map[SLSMG_VLINE_CHAR])
+#define ACS_HLINE (acs_map[SLSMG_HLINE_CHAR])
+#define ACS_S1 '-'
+#define ACS_S9 '-'
+#define ACS_DIAMOND '&'
+#define ACS_CKBOARD (acs_map[SLSMG_CKBRD_CHAR])
+#define ACS_DEGREE 'o'
+#define ACS_PLMINUS '+'
+#define ACS_BULLET '*'
+#define ACS_LARROW '<'
+#define ACS_RARROW '>'
+#define ACS_DARROW 'v'
+#define ACS_UARROW '^'
+#define ACS_BOARD '#'
+#define ACS_LANTERN '#'
+#define ACS_BLOCK '#'
+
+#if 1
+#define hline(x,y) SLcurses_nil ()
+#define vline(x,y) SLcurses_nil ()
+#endif
+
+#define A_CHARTEXT 0x00FF
+#define A_NORMAL 0
+#define A_BOLD 0x1000
+#define A_REVERSE 0x2000
+#define A_STANDOUT A_REVERSE
+#define A_UNDERLINE 0x4000
+#define A_BLINK 0
+#define A_COLOR 0x0700
+#define A_ALTCHARSET 0x8000
+#define A_DIM 0
+#define A_PROTECT 0
+#define A_INVIS 0
+
+#define COLOR_BLACK SLSMG_COLOR_BLACK
+#define COLOR_RED SLSMG_COLOR_RED
+#define COLOR_GREEN SLSMG_COLOR_GREEN
+#define COLOR_YELLOW SLSMG_COLOR_BROWN
+#define COLOR_BLUE SLSMG_COLOR_BLUE
+#define COLOR_MAGENTA SLSMG_COLOR_MAGENTA
+#define COLOR_CYAN SLSMG_COLOR_CYAN
+#define COLOR_WHITE SLSMG_COLOR_LGRAY
+
+extern int SLcurses_Num_Colors;
+#define COLORS SLcurses_Num_Colors
+#define COLOR_PAIRS (SLcurses_Num_Colors*SLcurses_Num_Colors)
+
+#define init_pair(_x,_f,_b) \
+ SLtt_set_color_object((_x), ((_f) == (_b) ? 0x0700 : ((_f) | ((_b) << 8)) << 8))
+
+#define scrollok(a,b) ((a)->scroll_ok = (b))
+#define getyx(a,y,x) (y=(a)->_cury, x=(a)->_curx)
+#define getmaxyx(a,y,x) (y=(a)->nrows, x=(a)->ncols)
+#define napms(x) usleep(1000 * (x))
+typedef SLtt_Char_Type chtype;
+#define beep SLtt_beep
+#define curs_set(x) SLtt_set_cursor_visibility(x)
+#define touchwin(x) SLsmg_touch_lines((x)->_begy, (x)->nrows)
+#define flash SLtt_beep
+
+#define wsetscrreg(w,a,b) ((w)->scroll_min = (a), (w)->scroll_max = (b))
+
+#define wtimeout(a,b) (a)->delay_off = ((b >= 0) ? (b) / 100 : -1)
+#define timeout(a) wtimeout(stdscr, a)
+extern int SLcurses_wdelch (SLcurses_Window_Type *);
+#define wdelch SLcurses_wdelch
+#define delch() wdelch(stdscr)
+
+extern int SLcurses_winsch (SLcurses_Window_Type *, int);
+#define winsch SLcurses_winsch
+
+extern int SLcurses_Esc_Delay;/* ESC expire time in milliseconds (ncurses compatible) */
+#define ESCDELAY SLcurses_Esc_Delay
+
+extern int SLcurses_clearok (SLcurses_Window_Type *, int);
+#define clearok SLcurses_clearok
+
+/* Functions that have not been implemented. */
+#define copywin(w,v,a,b,c,d,e,f,g) SLcurses_nil()
+#define wdeleteln(win) SLcurses_nil()
+#define resetty SLcurses_nil
+#define savetty SLcurses_nil
+#define overlay(u,v) SLcurses_nil()
+
+/* These functions do nothing */
+#define savetty SLcurses_nil
+#define nonl SLcurses_nil
+#define echo SLcurses_nil
+#define noecho SLcurses_nil
+#define saveterm SLcurses_nil
+#define box(w,y,z) ((w)->has_box = 1, (w)->modified = 1)
+#define leaveok(a,b) SLcurses_nil()
+#define nl() SLcurses_nil()
+#define trace(x) SLcurses_nil()
+#define tigetstr(x) NULL
+
+/* These have no place in C */
+#define TRUE 1
+#define FALSE 0
+#define bool int
+
+/* Lynx compatability */
+#else
+
+#define stdscr NULL
+#define COLS SLtt_Screen_Cols
+#define LINES SLtt_Screen_Rows
+#define move SLsmg_gotorc
+#define addstr SLsmg_write_string
+#define clear SLsmg_cls
+#define standout SLsmg_reverse_video
+#define standend SLsmg_normal_video
+#define clrtoeol SLsmg_erase_eol
+#define scrollok(a,b) SLsmg_Newline_Moves = ((b) ? 1 : -1)
+#define addch SLsmg_write_char
+#define echo()
+#define printw SLsmg_printf
+#define endwin SLsmg_reset_smg(),SLang_reset_tty
+
+#endif
diff --git a/mdk-stage1/slang/sldisply.c b/mdk-stage1/slang/sldisply.c
new file mode 100644
index 000000000..1e1161774
--- /dev/null
+++ b/mdk-stage1/slang/sldisply.c
@@ -0,0 +1,2596 @@
+/* Copyright (c) 1992, 1999, 2001 John E. Davis
+ * This file is part of the S-Lang library.
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Perl Artistic License.
+ */
+#include "slinclud.h"
+
+#include <time.h>
+#include <ctype.h>
+
+#if !defined(VMS) || (__VMS_VER >= 70000000)
+# include <sys/time.h>
+# ifdef __QNX__
+# include <sys/select.h>
+# endif
+# include <sys/types.h>
+#endif
+
+#ifdef __BEOS__
+/* Prototype for select */
+# include <net/socket.h>
+#endif
+
+#ifdef HAVE_TERMIOS_H
+# include <termios.h>
+#endif
+
+#ifdef VMS
+# include <unixlib.h>
+# include <unixio.h>
+# include <dvidef.h>
+# include <descrip.h>
+# include <lib$routines.h>
+# include <starlet.h>
+#else
+# if !defined(sun)
+# include <sys/ioctl.h>
+# endif
+#endif
+
+#ifdef SYSV
+# include <sys/termio.h>
+# include <sys/stream.h>
+# include <sys/ptem.h>
+# include <sys/tty.h>
+#endif
+
+#if defined (_AIX) && !defined (FD_SET)
+# include <sys/select.h> /* for FD_ISSET, FD_SET, FD_ZERO */
+#endif
+
+#include <errno.h>
+
+#if defined(__DECC) && defined(VMS)
+/* These get prototypes for write an sleep */
+# include <unixio.h>
+#endif
+#include <signal.h>
+
+#include "slang.h"
+#include "_slang.h"
+
+/* Colors: These definitions are used for the display. However, the
+ * application only uses object handles which get mapped to this
+ * internal representation. The mapping is performed by the Color_Map
+ * structure below. */
+
+#define CHAR_MASK 0x000000FF
+#define FG_MASK 0x0000FF00
+#define BG_MASK 0x00FF0000
+#define ATTR_MASK 0x1F000000
+#define BGALL_MASK 0x0FFF0000
+
+/* The 0x10000000 bit represents the alternate character set. BGALL_MASK does
+ * not include this attribute.
+ */
+
+#define GET_FG(color) ((color & FG_MASK) >> 8)
+#define GET_BG(color) ((color & BG_MASK) >> 16)
+#define MAKE_COLOR(fg, bg) (((fg) | ((bg) << 8)) << 8)
+
+int SLtt_Screen_Cols;
+int SLtt_Screen_Rows;
+int SLtt_Term_Cannot_Insert;
+int SLtt_Term_Cannot_Scroll;
+int SLtt_Use_Ansi_Colors;
+int SLtt_Blink_Mode = 1;
+int SLtt_Use_Blink_For_ACS = 0;
+int SLtt_Newline_Ok = 0;
+int SLtt_Has_Alt_Charset = 0;
+int SLtt_Force_Keypad_Init = 0;
+
+void (*_SLtt_color_changed_hook)(void);
+
+#if SLTT_HAS_NON_BCE_SUPPORT
+static int Bce_Color_Offset = 0;
+#endif
+static int Can_Background_Color_Erase = 1;
+
+/* -1 means unknown */
+int SLtt_Has_Status_Line = -1; /* hs */
+int SLang_TT_Write_FD = -1;
+
+static int Automatic_Margins;
+/* static int No_Move_In_Standout; */
+static int Worthless_Highlight;
+#define HP_GLITCH_CODE
+#ifdef HP_GLITCH_CODE
+/* This glitch is exclusive to HP term. Basically it means that to clear
+ * attributes, one has to erase to the end of the line.
+ */
+static int Has_HP_Glitch;
+#endif
+
+static char *Reset_Color_String;
+static int Is_Color_Terminal = 0;
+
+static int Linux_Console;
+
+/* It is crucial that JMAX_COLORS must be less than 128 since the high bit
+ * is used to indicate a character from the ACS (alt char set). The exception
+ * to this rule is if SLtt_Use_Blink_For_ACS is true. This means that of
+ * the highbit is set, we interpret that as a blink character. This is
+ * exploited by DOSemu.
+ */
+#define JMAX_COLORS 256
+#define JNORMAL_COLOR 0
+
+typedef struct
+{
+ SLtt_Char_Type fgbg;
+ SLtt_Char_Type mono;
+ char *custom_esc;
+}
+Ansi_Color_Type;
+
+#define RGB1(r, g, b) ((r) | ((g) << 1) | ((b) << 2))
+#define RGB(r, g, b, br, bg, bb) ((RGB1(r, g, b) << 8) | (RGB1(br, bg, bb) << 16))
+
+static Ansi_Color_Type Ansi_Color_Map[JMAX_COLORS] =
+{
+ {RGB(1, 1, 1, 0, 0, 0), 0x00000000, NULL}, /* white/black */
+ {RGB(0, 1, 0, 0, 0, 0), SLTT_REV_MASK, NULL}, /* green/black */
+ {RGB(1, 0, 1, 0, 0, 0), SLTT_REV_MASK, NULL}, /* magenta/black */
+ {RGB(0, 1, 1, 0, 0, 0), SLTT_REV_MASK, NULL}, /* cyan/black */
+ {RGB(1, 0, 0, 0, 0, 0), SLTT_REV_MASK, NULL},
+ {RGB(0, 1, 0, 0, 0, 1), SLTT_REV_MASK, NULL},
+ {RGB(1, 0, 0, 0, 0, 1), SLTT_REV_MASK, NULL},
+ {RGB(1, 0, 0, 0, 1, 0), SLTT_REV_MASK, NULL},
+ {RGB(0, 0, 1, 1, 0, 0), SLTT_REV_MASK, NULL},
+ {RGB(0, 1, 0, 1, 0, 0), SLTT_REV_MASK, NULL},
+ {RGB(0, 1, 1, 1, 1, 1), SLTT_REV_MASK, NULL},
+ {RGB(1, 1, 0, 1, 1, 1), SLTT_REV_MASK, NULL},
+ {RGB(1, 0, 1, 1, 1, 1), SLTT_REV_MASK, NULL},
+ {RGB(0, 0, 0, 0, 1, 1), SLTT_REV_MASK, NULL},
+ {RGB(0, 1, 0, 1, 1, 1), SLTT_REV_MASK, NULL},
+ {RGB(0, 1, 0, 1, 1, 1), SLTT_REV_MASK, NULL},
+ {RGB(0, 1, 0, 1, 1, 1), SLTT_REV_MASK, NULL},
+ {RGB(0, 1, 0, 1, 1, 1), SLTT_REV_MASK, NULL}
+};
+
+static char *Color_Fg_Str = "\033[3%dm";
+static char *Color_Bg_Str = "\033[4%dm";
+static char *Default_Color_Fg_Str = "\033[39m";
+static char *Default_Color_Bg_Str = "\033[49m";
+
+static int Max_Terminfo_Colors = 8; /* termcap Co */
+
+char *SLtt_Graphics_Char_Pairs; /* ac termcap string -- def is vt100 */
+
+/* 1 if terminal lacks the ability to go into insert mode or into delete
+ mode. Currently controlled by S-Lang but later perhaps termcap. */
+
+static char *UnderLine_Vid_Str;
+static char *Blink_Vid_Str;
+static char *Bold_Vid_Str;
+static char *Ins_Mode_Str; /* = "\033[4h"; */ /* ins mode (im) */
+static char *Eins_Mode_Str; /* = "\033[4l"; */ /* end ins mode (ei) */
+static char *Scroll_R_Str; /* = "\033[%d;%dr"; */ /* scroll region */
+static char *Cls_Str; /* = "\033[2J\033[H"; */ /* cl termcap STR for ansi terminals */
+static char *Rev_Vid_Str; /* = "\033[7m"; */ /* mr,so termcap string */
+static char *Norm_Vid_Str; /* = "\033[m"; */ /* me,se termcap string */
+static char *Del_Eol_Str; /* = "\033[K"; */ /* ce */
+static char *Del_Bol_Str; /* = "\033[1K"; */ /* cb */
+static char *Del_Char_Str; /* = "\033[P"; */ /* dc */
+static char *Del_N_Lines_Str; /* = "\033[%dM"; */ /* DL */
+static char *Add_N_Lines_Str; /* = "\033[%dL"; */ /* AL */
+static char *Rev_Scroll_Str;
+static char *Curs_Up_Str;
+static char *Curs_F_Str; /* RI termcap string */
+static char *Cursor_Visible_Str; /* ve termcap string */
+static char *Cursor_Invisible_Str; /* vi termcap string */
+#if 0
+static char *Start_Mouse_Rpt_Str; /* Start mouse reporting mode */
+static char *End_Mouse_Rpt_Str; /* End mouse reporting mode */
+#endif
+static char *Start_Alt_Chars_Str; /* as */
+static char *End_Alt_Chars_Str; /* ae */
+static char *Enable_Alt_Char_Set; /* eA */
+
+static char *Term_Init_Str;
+static char *Keypad_Init_Str;
+static char *Term_Reset_Str;
+static char *Keypad_Reset_Str;
+
+/* status line functions */
+static char *Disable_Status_line_Str; /* ds */
+static char *Return_From_Status_Line_Str; /* fs */
+static char *Goto_Status_Line_Str; /* ts */
+static int Num_Status_Line_Columns; /* ws */
+/* static int Status_Line_Esc_Ok; */ /* es */
+
+/* static int Len_Curs_F_Str = 5; */
+
+/* cm string has %i%d since termcap numbers columns from 0 */
+/* char *CURS_POS_STR = "\033[%d;%df"; ansi-- hor and vert pos */
+static char *Curs_Pos_Str; /* = "\033[%i%d;%dH";*/ /* cm termcap string */
+
+/* scrolling region */
+static int Scroll_r1 = 0, Scroll_r2 = 23;
+static int Cursor_r, Cursor_c; /* 0 based */
+
+/* current attributes --- initialized to impossible value */
+static SLtt_Char_Type Current_Fgbg = 0xFFFFFFFFU;
+
+static int Cursor_Set; /* 1 if cursor position known, 0
+ * if not. -1 if only row is known
+ */
+
+#define MAX_OUTPUT_BUFFER_SIZE 4096
+
+static unsigned char Output_Buffer[MAX_OUTPUT_BUFFER_SIZE];
+static unsigned char *Output_Bufferp = Output_Buffer;
+
+unsigned long SLtt_Num_Chars_Output;
+
+int _SLusleep (unsigned long usecs)
+{
+#if !defined(VMS) || (__VMS_VER >= 70000000)
+ struct timeval tv;
+ tv.tv_sec = usecs / 1000000;
+ tv.tv_usec = usecs % 1000000;
+ return select(0, NULL, NULL, NULL, &tv);
+#else
+ return 0;
+#endif
+}
+
+int SLtt_flush_output (void)
+{
+ int nwrite = 0;
+ unsigned int total;
+ int n = (int) (Output_Bufferp - Output_Buffer);
+
+ SLtt_Num_Chars_Output += n;
+
+ total = 0;
+ while (n > 0)
+ {
+ nwrite = write (SLang_TT_Write_FD, (char *) Output_Buffer + total, n);
+ if (nwrite == -1)
+ {
+ nwrite = 0;
+#ifdef EAGAIN
+ if (errno == EAGAIN)
+ {
+ _SLusleep (100000); /* 1/10 sec */
+ continue;
+ }
+#endif
+#ifdef EWOULDBLOCK
+ if (errno == EWOULDBLOCK)
+ {
+ _SLusleep (100000);
+ continue;
+ }
+#endif
+#ifdef EINTR
+ if (errno == EINTR) continue;
+#endif
+ break;
+ }
+ n -= nwrite;
+ total += nwrite;
+ }
+ Output_Bufferp = Output_Buffer;
+ return n;
+}
+
+int SLtt_Baud_Rate;
+static void tt_write(char *str, unsigned int n)
+{
+ static unsigned long last_time;
+ static int total;
+ unsigned long now;
+ unsigned int ndiff;
+
+ if ((str == NULL) || (n == 0)) return;
+ total += n;
+
+ while (1)
+ {
+ ndiff = MAX_OUTPUT_BUFFER_SIZE - (int) (Output_Bufferp - Output_Buffer);
+ if (ndiff < n)
+ {
+ SLMEMCPY ((char *) Output_Bufferp, (char *) str, ndiff);
+ Output_Bufferp += ndiff;
+ SLtt_flush_output ();
+ n -= ndiff;
+ str += ndiff;
+ }
+ else
+ {
+ SLMEMCPY ((char *) Output_Bufferp, str, n);
+ Output_Bufferp += n;
+ break;
+ }
+ }
+
+ if (((SLtt_Baud_Rate > 150) && (SLtt_Baud_Rate <= 9600))
+ && (10 * total > SLtt_Baud_Rate))
+ {
+ total = 0;
+ if ((now = (unsigned long) time(NULL)) - last_time <= 1)
+ {
+ SLtt_flush_output ();
+ sleep((unsigned) 1);
+ }
+ last_time = now;
+ }
+}
+
+static void tt_write_string (char *str)
+{
+ if (str != NULL) tt_write(str, strlen(str));
+}
+
+void SLtt_write_string (char *str)
+{
+ tt_write_string (str);
+ Cursor_Set = 0;
+}
+
+void SLtt_putchar (char ch)
+{
+ SLtt_normal_video ();
+ if (Cursor_Set == 1)
+ {
+ if (ch >= ' ') Cursor_c++;
+ else if (ch == '\b') Cursor_c--;
+ else if (ch == '\r') Cursor_c = 0;
+ else Cursor_Set = 0;
+
+ if ((Cursor_c + 1 == SLtt_Screen_Cols)
+ && Automatic_Margins) Cursor_Set = 0;
+ }
+
+ if (Output_Bufferp < Output_Buffer + MAX_OUTPUT_BUFFER_SIZE)
+ {
+ *Output_Bufferp++ = (unsigned char) ch;
+ }
+ else tt_write (&ch, 1);
+}
+
+static unsigned int tt_sprintf(char *buf, char *fmt, int x, int y)
+{
+ char *fmt_max;
+ register unsigned char *b, ch;
+ int offset;
+ int z, z1, parse_level;
+ int zero_pad;
+ int field_width;
+ int variables [26];
+ int stack [64];
+ unsigned int stack_len;
+ int parms [10];
+#define STACK_POP (stack_len ? stack[--stack_len] : 0)
+
+ if (fmt == NULL)
+ {
+ *buf = 0;
+ return 0;
+ }
+
+ stack [0] = y; /* pushed for termcap */
+ stack [1] = x;
+ stack_len = 2;
+
+ parms [1] = x; /* p1 */
+ parms [2] = y; /* p2 */
+
+ offset = 0;
+ zero_pad = 0;
+ field_width = 0;
+
+ b = (unsigned char *) buf;
+ fmt_max = fmt + strlen (fmt);
+
+ while (fmt < fmt_max)
+ {
+ ch = *fmt++;
+
+ if (ch != '%')
+ {
+ *b++ = ch;
+ continue;
+ }
+
+ if (fmt == fmt_max) break;
+ ch = *fmt++;
+
+ switch (ch)
+ {
+ default:
+ *b++ = ch;
+ break;
+
+ case 'p':
+
+ if (fmt == fmt_max) break;
+ ch = *fmt++;
+ if ((ch >= '0') && (ch <= '9'))
+ stack [stack_len++] = parms [ch - '0'];
+ break;
+
+ case '\'': /* 'x' */
+ if (fmt == fmt_max) break;
+ stack [stack_len++] = *fmt++;
+ if (fmt < fmt_max) fmt++; /* skip ' */
+ break;
+
+ case '{': /* literal constant, e.g. {30} */
+ z = 0;
+ while ((fmt < fmt_max) && ((ch = *fmt) <= '9') && (ch >= '0'))
+ {
+ z = z * 10 + (ch - '0');
+ fmt++;
+ }
+ stack [stack_len++] = z;
+ if ((ch == '}') && (fmt < fmt_max)) fmt++;
+ break;
+
+ case '0':
+ if (fmt == fmt_max) break;
+ ch = *fmt;
+ if ((ch != '2') && (ch != '3'))
+ break;
+ zero_pad = 1;
+ fmt++;
+ /* drop */
+
+ case '2':
+ case '3':
+ if (fmt == fmt_max)
+ if (*fmt == 'x')
+ {
+ char x_fmt_buf [4];
+ char *x_fmt_buf_ptr;
+
+ x_fmt_buf_ptr = x_fmt_buf;
+ if (zero_pad) *x_fmt_buf_ptr++ = '0';
+ *x_fmt_buf_ptr++ = ch;
+ *x_fmt_buf_ptr++ = 'X';
+ *x_fmt_buf_ptr = 0;
+
+ z = STACK_POP;
+ z += offset;
+
+ sprintf ((char *)b, x_fmt_buf, z);
+ b += strlen ((char *)b);
+ zero_pad = 0;
+ break;
+ }
+
+ field_width = (ch - '0');
+ /* drop */
+
+ case 'd':
+ z = STACK_POP;
+ z += offset;
+ if (z >= 100)
+ {
+ *b++ = z / 100 + '0';
+ z = z % 100;
+ zero_pad = 1;
+ field_width = 2;
+ }
+ else if (zero_pad && (field_width == 3))
+ *b++ = '0';
+
+ if (z >= 10)
+ {
+ *b++ = z / 10 + '0';
+ z = z % 10;
+ }
+ else if (zero_pad && (field_width >= 2))
+ *b++ = '0';
+
+ *b++ = z + '0';
+ field_width = zero_pad = 0;
+ break;
+
+ case 'x':
+ z = STACK_POP;
+ z += offset;
+ sprintf ((char *) b, "%X", z);
+ b += strlen ((char *)b);
+ break;
+
+ case 'i':
+ offset = 1;
+ break;
+
+ case '+':
+ /* Handling this depends upon whether or not we are parsing
+ * terminfo. Terminfo requires the stack so use it as an
+ * indicator.
+ */
+ if (stack_len > 2)
+ {
+ z = STACK_POP;
+ stack [stack_len - 1] += z;
+ }
+ else if (fmt < fmt_max)
+ {
+ ch = *fmt++;
+ if ((unsigned char) ch == 128) ch = 0;
+ ch = ch + (unsigned char) STACK_POP;
+ if (ch == '\n') ch++;
+ *b++ = ch;
+ }
+ break;
+
+ /* Binary operators */
+ case '-':
+ case '*':
+ case '/':
+ case 'm':
+ case '&':
+ case '|':
+ case '^':
+ case '=':
+ case '>':
+ case '<':
+ case 'A':
+ case 'O':
+ z1 = STACK_POP;
+ z = STACK_POP;
+ switch (ch)
+ {
+ case '-': z = (z - z1); break;
+ case '*': z = (z * z1); break;
+ case '/': z = (z / z1); break;
+ case 'm': z = (z % z1); break;
+ case '&': z = (z & z1); break;
+ case '|': z = (z | z1); break;
+ case '^': z = (z ^ z1); break;
+ case '=': z = (z == z1); break;
+ case '>': z = (z > z1); break;
+ case '<': z = (z < z1); break;
+ case 'A': z = (z && z1); break;
+ case 'O': z = (z || z1); break;
+ }
+ stack [stack_len++] = z;
+ break;
+
+ /* unary */
+ case '!':
+ z = STACK_POP;
+ stack [stack_len++] = !z;
+ break;
+
+ case '~':
+ z = STACK_POP;
+ stack [stack_len++] = ~z;
+ break;
+
+ case 'r': /* termcap -- swap parameters */
+ z = stack [0];
+ stack [0] = stack [1];
+ stack [1] = z;
+ break;
+
+ case '.': /* termcap */
+ case 'c':
+ ch = (unsigned char) STACK_POP;
+ if (ch == '\n') ch++;
+ *b++ = ch;
+ break;
+
+ case 'g':
+ if (fmt == fmt_max) break;
+ ch = *fmt++;
+ if ((ch >= 'a') && (ch <= 'z'))
+ stack [stack_len++] = variables [ch - 'a'];
+ break;
+
+ case 'P':
+ if (fmt == fmt_max) break;
+ ch = *fmt++;
+ if ((ch >= 'a') && (ch <= 'z'))
+ variables [ch - 'a'] = STACK_POP;
+ break;
+
+ /* If then else parsing. Actually, this is rather easy. The
+ * key is to notice that 'then' does all the work. 'if' simply
+ * there to indicate the start of a test and endif indicates
+ * the end of tests. If 'else' is seen, then skip to
+ * endif.
+ */
+ case '?': /* if */
+ case ';': /* endif */
+ break;
+
+ case 't': /* then */
+ z = STACK_POP;
+ if (z != 0)
+ break; /* good. Continue parsing. */
+
+ /* z == 0 and test has failed. So, skip past this entire if
+ * expression to the matching else or matching endif.
+ */
+ /* drop */
+ case 'e': /* else */
+
+ parse_level = 0;
+ while (fmt < fmt_max)
+ {
+ unsigned char ch1;
+
+ ch1 = *fmt++;
+ if ((ch1 != '%') || (fmt == fmt_max))
+ continue;
+
+ ch1 = *fmt++;
+
+ if (ch1 == '?') parse_level++; /* new if */
+ else if (ch1 == 'e')
+ {
+ if ((ch != 'e') && (parse_level == 0))
+ break;
+ }
+ else if (ch1 == ';')
+ {
+ if (parse_level == 0)
+ break;
+ parse_level--;
+ }
+ }
+ break;
+ }
+ }
+ *b = 0;
+ return (unsigned int) (b - (unsigned char *) buf);
+}
+
+static void tt_printf(char *fmt, int x, int y)
+{
+ char buf[1024];
+ unsigned int n;
+ if (fmt == NULL) return;
+ n = tt_sprintf(buf, fmt, x, y);
+ tt_write(buf, n);
+}
+
+void SLtt_set_scroll_region (int r1, int r2)
+{
+ Scroll_r1 = r1;
+ Scroll_r2 = r2;
+ tt_printf (Scroll_R_Str, Scroll_r1, Scroll_r2);
+ Cursor_Set = 0;
+}
+
+void SLtt_reset_scroll_region (void)
+{
+ SLtt_set_scroll_region(0, SLtt_Screen_Rows - 1);
+}
+
+int SLtt_set_cursor_visibility (int show)
+{
+ if ((Cursor_Visible_Str == NULL) || (Cursor_Invisible_Str == NULL))
+ return -1;
+
+ tt_write_string (show ? Cursor_Visible_Str : Cursor_Invisible_Str);
+ return 0;
+}
+
+/* the goto_rc function moves to row relative to scrolling region */
+void SLtt_goto_rc(int r, int c)
+{
+ char *s = NULL;
+ int n;
+ char buf[6];
+
+ if ((c < 0) || (r < 0))
+ {
+ Cursor_Set = 0;
+ return;
+ }
+
+ /* if (No_Move_In_Standout && Current_Fgbg) SLtt_normal_video (); */
+ r += Scroll_r1;
+
+ if ((Cursor_Set > 0) || ((Cursor_Set < 0) && !Automatic_Margins))
+ {
+ n = r - Cursor_r;
+ if ((n == -1) && (Cursor_Set > 0) && (Cursor_c == c)
+ && (Curs_Up_Str != NULL))
+ {
+ s = Curs_Up_Str;
+ }
+ else if ((n >= 0) && (n <= 4))
+ {
+ if ((n == 0) && (Cursor_Set == 1)
+ && ((c > 1) || (c == Cursor_c)))
+ {
+ if (Cursor_c == c) return;
+ if (Cursor_c == c + 1)
+ {
+ s = buf;
+ *s++ = '\b'; *s = 0;
+ s = buf;
+ }
+ }
+ else if (c == 0)
+ {
+ s = buf;
+ if ((Cursor_Set != 1) || (Cursor_c != 0)) *s++ = '\r';
+ while (n--) *s++ = '\n';
+#ifdef VMS
+ /* Need to add this after \n to start a new record. Sheesh. */
+ *s++ = '\r';
+#endif
+ *s = 0;
+ s = buf;
+ }
+ /* Will fail on VMS */
+#ifndef VMS
+ else if (SLtt_Newline_Ok && (Cursor_Set == 1) &&
+ (Cursor_c >= c) && (c + 3 > Cursor_c))
+ {
+ s = buf;
+ while (n--) *s++ = '\n';
+ n = Cursor_c - c;
+ while (n--) *s++ = '\b';
+ *s = 0;
+ s = buf;
+ }
+#endif
+ }
+ }
+ if (s != NULL) tt_write_string(s);
+ else tt_printf(Curs_Pos_Str, r, c);
+ Cursor_c = c; Cursor_r = r;
+ Cursor_Set = 1;
+}
+
+void SLtt_begin_insert (void)
+{
+ tt_write_string(Ins_Mode_Str);
+}
+
+void SLtt_end_insert (void)
+{
+ tt_write_string(Eins_Mode_Str);
+}
+
+void SLtt_delete_char (void)
+{
+ SLtt_normal_video ();
+ tt_write_string(Del_Char_Str);
+}
+
+void SLtt_erase_line (void)
+{
+ tt_write_string("\r");
+ Cursor_Set = 1; Cursor_c = 0;
+ SLtt_del_eol();
+}
+
+/* It appears that the Linux console, and most likely others do not
+ * like scrolling regions that consist of one line. So I have to
+ * resort to this stupidity to make up for that stupidity.
+ */
+static void delete_line_in_scroll_region (void)
+{
+ SLtt_goto_rc (Cursor_r - Scroll_r1, 0);
+ SLtt_del_eol ();
+}
+
+void SLtt_delete_nlines (int n)
+{
+ int r1, curs;
+ char buf[132];
+
+ if (n <= 0) return;
+ SLtt_normal_video ();
+
+ if (Scroll_r1 == Scroll_r2)
+ {
+ delete_line_in_scroll_region ();
+ return;
+ }
+
+ if (Del_N_Lines_Str != NULL) tt_printf(Del_N_Lines_Str,n, 0);
+ else
+ /* get a new terminal */
+ {
+ r1 = Scroll_r1;
+ curs = Cursor_r;
+ SLtt_set_scroll_region(curs, Scroll_r2);
+ SLtt_goto_rc(Scroll_r2 - Scroll_r1, 0);
+ SLMEMSET(buf, '\n', (unsigned int) n);
+ tt_write(buf, (unsigned int) n);
+ /* while (n--) tt_putchar('\n'); */
+ SLtt_set_scroll_region(r1, Scroll_r2);
+ SLtt_goto_rc(curs, 0);
+ }
+}
+
+void SLtt_cls (void)
+{
+ /* If the terminal is a color terminal but the user wants black and
+ * white, then make sure that the colors are reset. This appears to be
+ * necessary.
+ */
+ if ((SLtt_Use_Ansi_Colors == 0) && Is_Color_Terminal)
+ {
+ if (Reset_Color_String != NULL)
+ tt_write_string (Reset_Color_String);
+ else
+ tt_write_string ("\033[0m\033[m");
+ }
+
+ SLtt_normal_video();
+ SLtt_reset_scroll_region ();
+ tt_write_string(Cls_Str);
+}
+
+void SLtt_reverse_index (int n)
+{
+ if (!n) return;
+
+ SLtt_normal_video();
+
+ if (Scroll_r1 == Scroll_r2)
+ {
+ delete_line_in_scroll_region ();
+ return;
+ }
+
+ if (Add_N_Lines_Str != NULL) tt_printf(Add_N_Lines_Str,n, 0);
+ else
+ {
+ while(n--) tt_write_string(Rev_Scroll_Str);
+ }
+}
+
+int SLtt_Ignore_Beep = 1;
+static char *Visible_Bell_Str;
+
+void SLtt_beep (void)
+{
+ if (SLtt_Ignore_Beep & 0x1) SLtt_putchar('\007');
+
+ if (SLtt_Ignore_Beep & 0x2)
+ {
+ if (Visible_Bell_Str != NULL) tt_write_string (Visible_Bell_Str);
+#ifdef __linux__
+ else if (Linux_Console)
+ {
+ tt_write_string ("\033[?5h");
+ SLtt_flush_output ();
+ _SLusleep (50000);
+ tt_write_string ("\033[?5l");
+ }
+#endif
+ }
+ SLtt_flush_output ();
+}
+
+static void del_eol (void)
+{
+ int c;
+
+ if (Del_Eol_Str != NULL)
+ {
+ tt_write_string(Del_Eol_Str);
+ return;
+ }
+
+ c = Cursor_c;
+ /* Avoid writing to the lower right corner. If the terminal does not
+ * have Del_Eol_Str, then it probably does not have what it takes to play
+ * games with insert for for a space into that corner.
+ */
+ if (Cursor_r + 1 < SLtt_Screen_Rows)
+ c++;
+
+ while (c < SLtt_Screen_Cols)
+ {
+ tt_write (" ", 1);
+ c++;
+ }
+}
+
+void SLtt_del_eol (void)
+{
+ if (Current_Fgbg != 0xFFFFFFFFU) SLtt_normal_video ();
+ del_eol ();
+}
+
+typedef struct
+{
+ char *name;
+ SLtt_Char_Type color;
+}
+Color_Def_Type;
+
+#define MAX_COLOR_NAMES 17
+static Color_Def_Type Color_Defs [MAX_COLOR_NAMES] =
+{
+ {"black", SLSMG_COLOR_BLACK},
+ {"red", SLSMG_COLOR_RED},
+ {"green", SLSMG_COLOR_GREEN},
+ {"brown", SLSMG_COLOR_BROWN},
+ {"blue", SLSMG_COLOR_BLUE},
+ {"magenta", SLSMG_COLOR_MAGENTA},
+ {"cyan", SLSMG_COLOR_CYAN},
+ {"lightgray", SLSMG_COLOR_LGRAY},
+ {"gray", SLSMG_COLOR_GRAY},
+ {"brightred", SLSMG_COLOR_BRIGHT_RED},
+ {"brightgreen", SLSMG_COLOR_BRIGHT_GREEN},
+ {"yellow", SLSMG_COLOR_BRIGHT_BROWN},
+ {"brightblue", SLSMG_COLOR_BRIGHT_BLUE},
+ {"brightmagenta", SLSMG_COLOR_BRIGHT_CYAN},
+ {"brightcyan", SLSMG_COLOR_BRIGHT_MAGENTA},
+ {"white", SLSMG_COLOR_BRIGHT_WHITE},
+#define SLSMG_COLOR_DEFAULT 0xFF
+ {"default", SLSMG_COLOR_DEFAULT}
+};
+
+void SLtt_set_mono (int obj, char *what, SLtt_Char_Type mask)
+{
+ (void) what;
+ if ((obj < 0) || (obj >= JMAX_COLORS))
+ {
+ return;
+ }
+ Ansi_Color_Map[obj].mono = mask & ATTR_MASK;
+}
+
+static char *check_color_for_digit_form (char *color)
+{
+ unsigned int i, ich;
+ char *s = color;
+
+ i = 0;
+ while ((ich = (int) *s) != 0)
+ {
+ if ((ich < '0') || (ich > '9'))
+ return color;
+
+ i = i * 10 + (ich - '0');
+ s++;
+ }
+
+ if (i < MAX_COLOR_NAMES)
+ color = Color_Defs[i].name;
+
+ return color;
+}
+
+static int get_default_colors (char **fgp, char **bgp)
+{
+ static char fg_buf[16], bg_buf[16], *bg, *fg;
+ static int already_parsed;
+ char *p, *pmax;
+
+ if (already_parsed == -1)
+ return -1;
+
+ if (already_parsed)
+ {
+ *fgp = fg;
+ *bgp = bg;
+ return 0;
+ }
+
+ already_parsed = -1;
+
+ bg = getenv ("COLORFGBG");
+
+ if (bg == NULL)
+ {
+ bg = getenv ("DEFAULT_COLORS");
+ if (bg == NULL)
+ return -1;
+ }
+
+ p = fg_buf;
+ pmax = p + (sizeof (fg_buf) - 1);
+
+ while ((*bg != 0) && (*bg != ';'))
+ {
+ if (p < pmax) *p++ = *bg;
+ bg++;
+ }
+ *p = 0;
+
+ if (*bg) bg++;
+
+ p = bg_buf;
+ pmax = p + (sizeof (bg_buf) - 1);
+
+ /* Mark suggested allowing for extra spplication specific stuff following
+ * the background color. That is what the check for the semi-colon is for.
+ */
+ while ((*bg != 0) && (*bg != ';'))
+ {
+ if (p < pmax) *p++ = *bg;
+ bg++;
+ }
+ *p = 0;
+
+ if (!strcmp (fg_buf, "default") || !strcmp(bg_buf, "default"))
+ {
+ *fgp = *bgp = fg = bg = "default";
+ }
+ else
+ {
+ *fgp = fg = check_color_for_digit_form (fg_buf);
+ *bgp = bg = check_color_for_digit_form (bg_buf);
+ }
+ already_parsed = 1;
+ return 0;
+}
+
+static unsigned char FgBg_Stats[JMAX_COLORS];
+
+static int Color_0_Modified = 0;
+
+void SLtt_set_color_object (int obj, SLtt_Char_Type attr)
+{
+ char *cust_esc;
+
+ if ((obj < 0) || (obj >= JMAX_COLORS)) return;
+
+ cust_esc = Ansi_Color_Map[obj].custom_esc;
+ if (cust_esc != NULL)
+ {
+ SLfree (cust_esc);
+ FgBg_Stats[(Ansi_Color_Map[obj].fgbg >> 8) & 0x7F] -= 1;
+ Ansi_Color_Map[obj].custom_esc = NULL;
+ }
+
+ Ansi_Color_Map[obj].fgbg = attr;
+ if (obj == 0) Color_0_Modified = 1;
+
+ if (_SLtt_color_changed_hook != NULL)
+ (*_SLtt_color_changed_hook)();
+}
+
+SLtt_Char_Type SLtt_get_color_object (int obj)
+{
+ if ((obj < 0) || (obj >= JMAX_COLORS)) return 0;
+ return Ansi_Color_Map[obj].fgbg;
+}
+
+void SLtt_add_color_attribute (int obj, SLtt_Char_Type attr)
+{
+ if ((obj < 0) || (obj >= JMAX_COLORS)) return;
+
+ Ansi_Color_Map[obj].fgbg |= (attr & ATTR_MASK);
+ if (obj == 0) Color_0_Modified = 1;
+ if (_SLtt_color_changed_hook != NULL)
+ (*_SLtt_color_changed_hook)();
+}
+
+static SLtt_Char_Type fb_to_fgbg (SLtt_Char_Type f, SLtt_Char_Type b)
+{
+ SLtt_Char_Type attr;
+
+ if (Max_Terminfo_Colors != 8)
+ {
+ if (f != SLSMG_COLOR_DEFAULT) f %= Max_Terminfo_Colors;
+ if (b != SLSMG_COLOR_DEFAULT) b %= Max_Terminfo_Colors;
+ return ((f << 8) | (b << 16));
+ }
+
+ /* Otherwise we have 8 ansi colors. Try to get bright versions
+ * by using the BOLD and BLINK attributes.
+ */
+
+ attr = 0;
+
+ /* Note: If f represents default, it will have the value 0xFF */
+ if (f != SLSMG_COLOR_DEFAULT)
+ {
+ if (f & 0x8) attr = SLTT_BOLD_MASK;
+ f &= 0x7;
+ }
+
+ if (b != SLSMG_COLOR_DEFAULT)
+ {
+ if (b & 0x8) attr |= SLTT_BLINK_MASK;
+ b &= 0x7;
+ }
+
+ return ((f << 8) | (b << 16) | attr);
+}
+
+/* This looks for colors with name form 'colorN'. If color is of this
+ * form, N is passed back via paramter list.
+ */
+static int parse_color_digit_name (char *color, SLtt_Char_Type *f)
+{
+ unsigned int i;
+ unsigned char ch;
+
+ if (strncmp (color, "color", 5))
+ return -1;
+
+ color += 5;
+ if (*color == 0)
+ return -1;
+
+ i = 0;
+ while (1)
+ {
+ ch = (unsigned char) *color++;
+ if (ch == 0)
+ break;
+ if ((ch > '9') || (ch < '0'))
+ return -1;
+ i = 10 * i + (ch - '0');
+ }
+
+ *f = (SLtt_Char_Type) i;
+ return 0;
+}
+
+static int make_color_fgbg (char *fg, char *bg, SLtt_Char_Type *fgbg)
+{
+ SLtt_Char_Type f = 0xFFFFFFFFU, b = 0xFFFFFFFFU;
+ char *dfg, *dbg;
+ unsigned int i;
+
+ if ((fg != NULL) && (*fg == 0)) fg = NULL;
+ if ((bg != NULL) && (*bg == 0)) bg = NULL;
+
+ if ((fg == NULL) || (bg == NULL))
+ {
+ if (-1 == get_default_colors (&dfg, &dbg))
+ return -1;
+
+ if (fg == NULL) fg = dfg;
+ if (bg == NULL) bg = dbg;
+ }
+
+ if (-1 == parse_color_digit_name (fg, &f))
+ {
+ for (i = 0; i < MAX_COLOR_NAMES; i++)
+ {
+ if (strcmp(fg, Color_Defs[i].name)) continue;
+ f = Color_Defs[i].color;
+ break;
+ }
+ }
+
+ if (-1 == parse_color_digit_name (bg, &b))
+ {
+ for (i = 0; i < MAX_COLOR_NAMES; i++)
+ {
+ if (strcmp(bg, Color_Defs[i].name)) continue;
+ b = Color_Defs[i].color;
+ break;
+ }
+ }
+
+ if ((f == 0xFFFFFFFFU) || (b == 0xFFFFFFFFU))
+ return -1;
+
+ *fgbg = fb_to_fgbg (f, b);
+ return 0;
+}
+
+void SLtt_set_color (int obj, char *what, char *fg, char *bg)
+{
+ SLtt_Char_Type fgbg;
+
+ (void) what;
+ if ((obj < 0) || (obj >= JMAX_COLORS))
+ return;
+
+ if (-1 != make_color_fgbg (fg, bg, &fgbg))
+ SLtt_set_color_object (obj, fgbg);
+}
+
+void SLtt_set_color_fgbg (int obj, SLtt_Char_Type f, SLtt_Char_Type b)
+{
+ SLtt_set_color_object (obj, fb_to_fgbg (f, b));
+}
+
+void SLtt_set_color_esc (int obj, char *esc)
+{
+ char *cust_esc;
+ SLtt_Char_Type fgbg = 0;
+ int i;
+
+ if ((obj < 0) || (obj >= JMAX_COLORS))
+ {
+ return;
+ }
+
+ cust_esc = Ansi_Color_Map[obj].custom_esc;
+ if (cust_esc != NULL)
+ {
+ SLfree (cust_esc);
+ FgBg_Stats[(Ansi_Color_Map[obj].fgbg >> 8) & 0x7F] -= 1;
+ }
+
+ cust_esc = (char *) SLmalloc (strlen(esc) + 1);
+ if (cust_esc != NULL) strcpy (cust_esc, esc);
+
+ Ansi_Color_Map[obj].custom_esc = cust_esc;
+ if (cust_esc == NULL) fgbg = 0;
+ else
+ {
+ /* The whole point of this is to generate a unique fgbg */
+ for (i = 0; i < JMAX_COLORS; i++)
+ {
+ if (FgBg_Stats[i] == 0) fgbg = i;
+
+ if (obj == i) continue;
+ if ((Ansi_Color_Map[i].custom_esc) == NULL) continue;
+ if (!strcmp (Ansi_Color_Map[i].custom_esc, cust_esc))
+ {
+ fgbg = (Ansi_Color_Map[i].fgbg >> 8) & 0x7F;
+ break;
+ }
+ }
+ FgBg_Stats[fgbg] += 1;
+ }
+
+ fgbg |= 0x80;
+ Ansi_Color_Map[obj].fgbg = (fgbg | (fgbg << 8)) << 8;
+ if (obj == 0) Color_0_Modified = 1;
+ if (_SLtt_color_changed_hook != NULL)
+ (*_SLtt_color_changed_hook)();
+}
+
+void SLtt_set_alt_char_set (int i)
+{
+ static int last_i;
+ if (SLtt_Has_Alt_Charset == 0) return;
+ if (i == last_i) return;
+ tt_write_string (i ? Start_Alt_Chars_Str : End_Alt_Chars_Str );
+ last_i = i;
+}
+
+static void write_attributes (SLtt_Char_Type fgbg)
+{
+ int bg0, fg0;
+ int unknown_attributes;
+
+ if (Worthless_Highlight) return;
+ if (fgbg == Current_Fgbg) return;
+
+ unknown_attributes = 0;
+
+ /* Before spitting out colors, fix attributes */
+ if ((fgbg & ATTR_MASK) != (Current_Fgbg & ATTR_MASK))
+ {
+ if (Current_Fgbg & ATTR_MASK)
+ {
+ tt_write_string(Norm_Vid_Str);
+ /* In case normal video turns off ALL attributes: */
+ if (fgbg & SLTT_ALTC_MASK)
+ Current_Fgbg &= ~SLTT_ALTC_MASK;
+ SLtt_set_alt_char_set (0);
+ }
+
+ if ((fgbg & SLTT_ALTC_MASK)
+ != (Current_Fgbg & SLTT_ALTC_MASK))
+ {
+ SLtt_set_alt_char_set ((int) (fgbg & SLTT_ALTC_MASK));
+ }
+
+ if (fgbg & SLTT_ULINE_MASK) tt_write_string (UnderLine_Vid_Str);
+ if (fgbg & SLTT_BOLD_MASK) SLtt_bold_video ();
+ if (fgbg & SLTT_REV_MASK) tt_write_string (Rev_Vid_Str);
+ if (fgbg & SLTT_BLINK_MASK)
+ {
+ /* Someday Linux will have a blink mode that set high intensity
+ * background. Lets be prepared.
+ */
+ if (SLtt_Blink_Mode) tt_write_string (Blink_Vid_Str);
+ }
+ unknown_attributes = 1;
+ }
+
+ if (SLtt_Use_Ansi_Colors)
+ {
+ fg0 = (int) GET_FG(fgbg);
+ bg0 = (int) GET_BG(fgbg);
+
+ if (unknown_attributes
+ || (fg0 != (int)GET_FG(Current_Fgbg)))
+ {
+ if (fg0 == SLSMG_COLOR_DEFAULT)
+ tt_write_string (Default_Color_Fg_Str);
+ else
+ tt_printf (Color_Fg_Str, fg0, 0);
+ }
+
+ if (unknown_attributes
+ || (bg0 != (int)GET_BG(Current_Fgbg)))
+ {
+ if (bg0 == SLSMG_COLOR_DEFAULT)
+ tt_write_string (Default_Color_Bg_Str);
+ else
+ tt_printf (Color_Bg_Str, bg0, 0);
+ }
+ }
+
+ Current_Fgbg = fgbg;
+}
+
+static int Video_Initialized;
+
+void SLtt_reverse_video (int color)
+{
+ SLtt_Char_Type fgbg;
+ char *esc;
+
+ if (Worthless_Highlight) return;
+ if ((color < 0) || (color >= JMAX_COLORS)) return;
+
+ if (Video_Initialized == 0)
+ {
+ if (color == JNORMAL_COLOR)
+ {
+ tt_write_string (Norm_Vid_Str);
+ }
+ else tt_write_string (Rev_Vid_Str);
+ Current_Fgbg = 0xFFFFFFFFU;
+ return;
+ }
+
+ if (SLtt_Use_Ansi_Colors)
+ {
+ fgbg = Ansi_Color_Map[color].fgbg;
+ if ((esc = Ansi_Color_Map[color].custom_esc) != NULL)
+ {
+ if (fgbg != Current_Fgbg)
+ {
+ Current_Fgbg = fgbg;
+ tt_write_string (esc);
+ return;
+ }
+ }
+ }
+ else fgbg = Ansi_Color_Map[color].mono;
+
+ if (fgbg == Current_Fgbg) return;
+ write_attributes (fgbg);
+}
+
+void SLtt_normal_video (void)
+{
+ SLtt_reverse_video(JNORMAL_COLOR);
+}
+
+void SLtt_narrow_width (void)
+{
+ tt_write_string("\033[?3l");
+}
+
+void SLtt_wide_width (void)
+{
+ tt_write_string("\033[?3h");
+}
+
+/* Highest bit represents the character set. */
+#define COLOR_MASK 0x7F00
+
+#if SLTT_HAS_NON_BCE_SUPPORT
+static int bce_color_eqs (unsigned int a, unsigned int b)
+{
+ a = (a & COLOR_MASK) >> 8;
+ b = (b & COLOR_MASK) >> 8;
+
+ if (a == b)
+ return 1;
+
+ if (SLtt_Use_Ansi_Colors == 0)
+ return Ansi_Color_Map[a].mono == Ansi_Color_Map[b].mono;
+
+ if (Bce_Color_Offset == 0)
+ return Ansi_Color_Map[a].fgbg == Ansi_Color_Map[b].fgbg;
+
+ /* If either are color 0, then we do not know what that means since the
+ * terminal does not support BCE */
+ if ((a == 0) || (b == 0))
+ return 0;
+
+ return Ansi_Color_Map[a-1].fgbg == Ansi_Color_Map[b-1].fgbg;
+}
+#define COLOR_EQS(a,b) bce_color_eqs (a,b)
+#else
+# define COLOR_OF(x) (((unsigned int)(x) & COLOR_MASK) >> 8)
+# define COLOR_EQS(a, b) \
+ (SLtt_Use_Ansi_Colors \
+ ? (Ansi_Color_Map[COLOR_OF(a)].fgbg == Ansi_Color_Map[COLOR_OF(b)].fgbg)\
+ : (Ansi_Color_Map[COLOR_OF(a)].mono == Ansi_Color_Map[COLOR_OF(b)].mono))
+#endif
+
+#define CHAR_EQS(a, b) (((a) == (b))\
+ || ((((a) & ~COLOR_MASK) == ((b) & ~COLOR_MASK))\
+ && COLOR_EQS((a), (b))))
+
+/* The whole point of this routine is to prevent writing to the last column
+ * and last row on terminals with automatic margins.
+ */
+static void write_string_with_care (char *str)
+{
+ unsigned int len;
+
+ if (str == NULL) return;
+
+ len = strlen (str);
+ if (Automatic_Margins && (Cursor_r + 1 == SLtt_Screen_Rows))
+ {
+ if (len + (unsigned int) Cursor_c >= (unsigned int) SLtt_Screen_Cols)
+ {
+ /* For now, just do not write there. Later, something more
+ * sophisticated will be implemented.
+ */
+ if (SLtt_Screen_Cols > Cursor_c)
+ len = SLtt_Screen_Cols - Cursor_c - 1;
+ else
+ len = 0;
+ }
+ }
+ tt_write (str, len);
+}
+
+static void send_attr_str (SLsmg_Char_Type *s)
+{
+ unsigned char out[256], ch, *p;
+ register SLtt_Char_Type attr;
+ register SLsmg_Char_Type sh;
+ int color, last_color = -1;
+
+ p = out;
+ while (0 != (sh = *s++))
+ {
+ ch = sh & 0xFF;
+ color = ((int) sh & 0xFF00) >> 8;
+
+#if SLTT_HAS_NON_BCE_SUPPORT
+ if (Bce_Color_Offset
+ && (color >= Bce_Color_Offset))
+ color -= Bce_Color_Offset;
+#endif
+
+ if (color != last_color)
+ {
+ if (SLtt_Use_Ansi_Colors) attr = Ansi_Color_Map[color & 0x7F].fgbg;
+ else attr = Ansi_Color_Map[color & 0x7F].mono;
+
+ if (sh & 0x8000) /* alternate char set */
+ {
+ if (SLtt_Use_Blink_For_ACS)
+ {
+ if (SLtt_Blink_Mode) attr |= SLTT_BLINK_MASK;
+ }
+ else attr |= SLTT_ALTC_MASK;
+ }
+
+ if (attr != Current_Fgbg)
+ {
+ if ((ch != ' ') ||
+ /* it is a space so only consider it different if it
+ * has different attributes.
+ */
+ (attr & BGALL_MASK) != (Current_Fgbg & BGALL_MASK))
+ {
+ if (p != out)
+ {
+ *p = 0;
+ write_string_with_care ((char *) out);
+ Cursor_c += (int) (p - out);
+ p = out;
+ }
+
+ if (SLtt_Use_Ansi_Colors && (NULL != Ansi_Color_Map[color & 0x7F].custom_esc))
+ {
+ tt_write_string (Ansi_Color_Map[color & 0x7F].custom_esc);
+ /* Just in case the custom escape sequence screwed up
+ * the alt character set state...
+ */
+ if ((attr & SLTT_ALTC_MASK) != (Current_Fgbg & SLTT_ALTC_MASK))
+ SLtt_set_alt_char_set ((int) (attr & SLTT_ALTC_MASK));
+ Current_Fgbg = attr;
+ }
+ else write_attributes (attr);
+
+ last_color = color;
+ }
+ }
+ }
+ *p++ = ch;
+ }
+ *p = 0;
+ if (p != out) write_string_with_care ((char *) out);
+ Cursor_c += (int) (p - out);
+}
+
+static void forward_cursor (unsigned int n, int row)
+{
+ char buf [1024];
+
+ if (n <= 4)
+ {
+ SLtt_normal_video ();
+ SLMEMSET (buf, ' ', n);
+ buf[n] = 0;
+ write_string_with_care (buf);
+ Cursor_c += n;
+ }
+ else if (Curs_F_Str != NULL)
+ {
+ Cursor_c += n;
+ n = tt_sprintf(buf, Curs_F_Str, (int) n, 0);
+ tt_write(buf, n);
+ }
+ else SLtt_goto_rc (row, (int) (Cursor_c + n));
+}
+
+
+void SLtt_smart_puts(SLsmg_Char_Type *neww, SLsmg_Char_Type *oldd, int len, int row)
+{
+ register SLsmg_Char_Type *p, *q, *qmax, *pmax, *buf;
+ SLsmg_Char_Type buffer[256];
+ unsigned int n_spaces;
+ SLsmg_Char_Type *space_match, *last_buffered_match;
+#ifdef HP_GLITCH_CODE
+ int handle_hp_glitch = 0;
+#endif
+ SLsmg_Char_Type space_char;
+#define SLTT_USE_INSERT_HACK 1
+#if SLTT_USE_INSERT_HACK
+ SLsmg_Char_Type insert_hack_prev = 0;
+ SLsmg_Char_Type insert_hack_char = 0;
+
+ if ((row + 1 == SLtt_Screen_Rows)
+ && (len == SLtt_Screen_Cols)
+ && (len > 1)
+ && (SLtt_Term_Cannot_Insert == 0)
+ && Automatic_Margins)
+ {
+ insert_hack_char = neww[len-1];
+ if (oldd[len-1] == insert_hack_char)
+ insert_hack_char = 0;
+ else
+ insert_hack_prev = neww[len-2];
+ }
+#endif
+
+ q = oldd; p = neww;
+ qmax = oldd + len;
+ pmax = p + len;
+
+ /* Find out where to begin --- while they match, we are ok */
+ while (1)
+ {
+ if (q == qmax) return;
+#if SLANG_HAS_KANJI_SUPPORT
+ if (*p & 0x80)
+ { /* new is kanji */
+ if ((*q & 0x80) && ((q + 1) < qmax))
+ { /* old is also kanji */
+ if (((0xFF & *q) != (0xFF & *p))
+ || ((0xFF & q[1]) != (0xFF & p[1])))
+ break; /* both kanji, but not match */
+
+ else
+ { /* kanji match ! */
+ if (!COLOR_EQS(*q, *p)) break;
+ q++; p++;
+ if (!COLOR_EQS(*q, *p)) break;
+ /* really match! */
+ q++; p++;
+ continue;
+ }
+ }
+ else break; /* old is not kanji */
+ }
+ else
+ { /* new is not kanji */
+ if (*q & 0x80) break; /* old is kanji */
+ }
+#endif
+ if (!CHAR_EQS(*q, *p)) break;
+ q++; p++;
+ }
+
+#ifdef HP_GLITCH_CODE
+ if (Has_HP_Glitch)
+ {
+ SLsmg_Char_Type *qq = q;
+
+ SLtt_goto_rc (row, (int) (p - neww));
+
+ while (qq < qmax)
+ {
+ if (*qq & 0xFF00)
+ {
+ SLtt_normal_video ();
+ SLtt_del_eol ();
+ qmax = q;
+ handle_hp_glitch = 1;
+ break;
+ }
+ qq++;
+ }
+ }
+#endif
+ /* Find where the last non-blank character on old/new screen is */
+
+ space_char = ' ';
+ if ((*(pmax-1) & 0xFF) == ' ')
+ {
+ /* If we get here, then we can erase to the end of the line to create
+ * the final space. However, this will only work _if_ erasing will
+ * get us the correct color. If the terminal supports BCE, then this
+ * is easy. If it does not, then we can only perform this operation
+ * if the color is known via something like COLORFGBG. For now,
+ * I just will not perform the optimization for such terminals.
+ */
+ if ((Can_Background_Color_Erase)
+ && SLtt_Use_Ansi_Colors)
+ space_char = *(pmax - 1);
+
+ while (pmax > p)
+ {
+ pmax--;
+ if (!CHAR_EQS(*pmax, space_char))
+ {
+ pmax++;
+ break;
+ }
+ }
+ }
+
+ while (qmax > q)
+ {
+ qmax--;
+ if (!CHAR_EQS(*qmax, space_char))
+ {
+ qmax++;
+ break;
+ }
+ }
+
+ last_buffered_match = buf = buffer; /* buffer is empty */
+
+#ifdef HP_GLITCH_CODE
+ if (handle_hp_glitch)
+ {
+ while (p < pmax)
+ {
+ *buf++ = *p++;
+ }
+ }
+#endif
+
+#ifdef HP_GLITCH_CODE
+ if (Has_HP_Glitch == 0)
+ {
+#endif
+ /* Try use use erase to bol if possible */
+ if ((Del_Bol_Str != NULL) && ((*neww & 0xFF) == 32))
+ {
+ SLsmg_Char_Type *p1;
+ SLsmg_Char_Type blank;
+
+ p1 = neww;
+ if ((Can_Background_Color_Erase)
+ && SLtt_Use_Ansi_Colors)
+ blank = *p1;
+ /* black+white attributes do not support bce */
+ else
+ blank = 32;
+
+ while ((p1 < pmax) && (CHAR_EQS (*p1, blank)))
+ p1++;
+
+ /* Is this optimization worth it? Assume Del_Bol_Str is ESC [ 1 K
+ * It costs 4 chars + the space needed to properly position the
+ * cursor, e.g., ESC [ 10;10H. So, it costs at least 13 characters.
+ */
+ if ((p1 > neww + 13)
+ && (p1 >= p)
+ /* Avoid erasing from the end of the line */
+ && ((p1 != pmax) || (pmax < neww + len)))
+ {
+ int ofs = (int) (p1 - neww);
+ q = oldd + ofs;
+ p = p1;
+ SLtt_goto_rc (row, ofs - 1);
+ SLtt_reverse_video (blank >> 8);
+ tt_write_string (Del_Bol_Str);
+ tt_write (" ", 1);
+ Cursor_c += 1;
+ }
+ else
+ SLtt_goto_rc (row, (int) (p - neww));
+ }
+ else
+ SLtt_goto_rc (row, (int) (p - neww));
+#ifdef HP_GLITCH_CODE
+ }
+#endif
+
+
+ /* loop using overwrite then skip algorithm until done */
+ while (1)
+ {
+ /* while they do not match and we do not hit a space, buffer them up */
+ n_spaces = 0;
+ while (p < pmax)
+ {
+ if (CHAR_EQS(*q, 32) && CHAR_EQS(*p, 32))
+ {
+ /* If *q is not a space, we would have to overwrite it.
+ * However, if *q is a space, then while *p is also one,
+ * we only need to skip over the blank field.
+ */
+ space_match = p;
+ p++; q++;
+ while ((p < pmax)
+ && CHAR_EQS(*q, 32)
+ && CHAR_EQS(*p, 32))
+ {
+ p++;
+ q++;
+ }
+ n_spaces = (unsigned int) (p - space_match);
+ break;
+ }
+#if SLANG_HAS_KANJI_SUPPORT
+ if ((*p & 0x80) && ((p + 1) < pmax))
+ { /* new is kanji */
+ if (*q & 0x80)
+ { /* old is also kanji */
+ if (((0xFF & *q) != (0xFF & *p))
+ || ((0xFF & q[1]) != (0xFF & p[1])))
+ {
+ /* both kanji, but not match */
+ *buf++ = *p++;
+ *buf++ = *p++;
+ q += 2;
+ continue;
+ }
+ else
+ { /* kanji match ? */
+ if (!COLOR_EQS(*q, *p) || !COLOR_EQS(*(q+1), *(p+1)))
+ {
+ /* code is match, but color is diff */
+ *buf++ = *p++;
+ *buf++ = *p++;
+ q += 2;
+ continue;
+ }
+ /* really match ! */
+ break;
+ }
+ }
+ else
+ { /* old is not kanji */
+ *buf++ = *p++;
+ *buf++ = *p++;
+ q += 2;
+ continue;
+ }
+ }
+ else
+ { /* new is not kanji */
+ if (*q & 0x80)
+ { /* old is kanji */
+ *buf++ = *p++;
+ q++;
+ continue;
+ }
+ }
+#endif
+
+ if (CHAR_EQS(*q, *p)) break;
+ *buf++ = *p++;
+ q++;
+ }
+ *buf = 0;
+
+ if (buf != buffer) send_attr_str (buffer);
+ buf = buffer;
+
+ if (n_spaces
+ && ((p < pmax) /* erase to eol will achieve this effect*/
+ || (space_char != 32)))/* unless space_char is not a simple space */
+ {
+ forward_cursor (n_spaces, row);
+ }
+
+ /* Now we overwrote what we could and cursor is placed at position
+ * of a possible match of new and old. If this is the case, skip
+ * some more.
+ */
+#if !SLANG_HAS_KANJI_SUPPORT
+ while ((p < pmax) && CHAR_EQS(*p, *q))
+ {
+ *buf++ = *p++;
+ q++;
+ }
+#else
+ /* Kanji */
+ while (p < pmax)
+ {
+ if ((*p & 0x80) && ((p + 1) < pmax))
+ { /* new is kanji */
+ if (*q & 0x80)
+ { /* old is also kanji */
+ if (((0xFF & *q) == (0xFF & *p))
+ && ((0xFF & q[1]) == (0xFF & p[1])))
+ {
+ /* kanji match ? */
+ if (!COLOR_EQS(*q, *p)
+ || !COLOR_EQS(q[1], p[1]))
+ break;
+
+ *buf++ = *p++;
+ q++;
+ if (p >= pmax)
+ {
+ *buf++ = 32;
+ p++;
+ break;
+ }
+ else
+ {
+ *buf++ = *p++;
+ q++;
+ continue;
+ }
+ }
+ else break; /* both kanji, but not match */
+ }
+ else break; /* old is not kanji */
+ }
+ else
+ { /* new is not kanji */
+ if (*q & 0x80) break; /* old is kanji */
+ if (!CHAR_EQS(*q, *p)) break;
+ *buf++ = *p++;
+ q++;
+ }
+ }
+#endif
+ last_buffered_match = buf;
+ if (p >= pmax) break;
+
+ /* jump to new position is it is greater than 5 otherwise
+ * let it sit in the buffer and output it later.
+ */
+ if ((int) (buf - buffer) >= 5)
+ {
+ forward_cursor ((unsigned int) (buf - buffer), row);
+ last_buffered_match = buf = buffer;
+ }
+ }
+
+ if (buf != buffer)
+ {
+ if (q < qmax)
+ {
+ if ((buf == last_buffered_match)
+ && ((int) (buf - buffer) >= 5))
+ {
+ forward_cursor ((unsigned int) (buf - buffer), row);
+ }
+ else
+ {
+ *buf = 0;
+ send_attr_str (buffer);
+ }
+ }
+ }
+
+ if (q < qmax)
+ {
+ SLtt_reverse_video (space_char >> 8);
+ del_eol ();
+ }
+
+#if SLTT_USE_INSERT_HACK
+ else if (insert_hack_char)
+ {
+ SLtt_goto_rc (SLtt_Screen_Rows-1, SLtt_Screen_Cols-2);
+ buffer[0] = insert_hack_char;
+ buffer[1] = 0;
+ send_attr_str (buffer);
+ SLtt_goto_rc (SLtt_Screen_Rows-1, SLtt_Screen_Cols-2);
+ buffer[0] = insert_hack_prev;
+ SLtt_begin_insert ();
+ send_attr_str (buffer);
+ SLtt_end_insert ();
+ }
+#endif
+
+ if (Automatic_Margins && (Cursor_c + 1 >= SLtt_Screen_Cols)) Cursor_Set = 0;
+}
+
+static void get_color_info (void)
+{
+ char *fg, *bg;
+
+ /* Allow easy mechanism to override inadequate termcap/terminfo files. */
+ if (SLtt_Use_Ansi_Colors == 0)
+ SLtt_Use_Ansi_Colors = (NULL != getenv ("COLORTERM"));
+
+ if (SLtt_Use_Ansi_Colors)
+ Is_Color_Terminal = 1;
+
+#if SLTT_HAS_NON_BCE_SUPPORT
+ if (Can_Background_Color_Erase == 0)
+ Can_Background_Color_Erase = (NULL != getenv ("COLORTERM_BCE"));
+#endif
+
+ if (-1 == get_default_colors (&fg, &bg))
+ return;
+
+ /* Check to see if application has already set them. */
+ if (Color_0_Modified)
+ return;
+
+ SLtt_set_color (0, NULL, fg, bg);
+ SLtt_set_color (1, NULL, bg, fg);
+}
+
+/* termcap stuff */
+
+#ifdef __unix__
+
+static int Termcap_Initalized = 0;
+
+#ifdef USE_TERMCAP
+/* Termcap based system */
+static char Termcap_Buf[4096];
+static char Termcap_String_Buf[4096];
+static char *Termcap_String_Ptr;
+extern char *tgetstr(char *, char **);
+extern int tgetent(char *, char *);
+extern int tgetnum(char *);
+extern int tgetflag(char *);
+#else
+/* Terminfo */
+static SLterminfo_Type *Terminfo;
+#endif
+
+#define TGETFLAG(x) (SLtt_tgetflag(x) > 0)
+
+static char *fixup_tgetstr (char *what)
+{
+ register char *w, *w1;
+ char *wsave;
+
+ if (what == NULL)
+ return NULL;
+
+ /* Check for AIX brain-damage */
+ if (*what == '@')
+ return NULL;
+
+ /* lose pad info --- with today's technology, term is a loser if
+ it is really needed */
+ while ((*what == '.') ||
+ ((*what >= '0') && (*what <= '9'))) what++;
+ if (*what == '*') what++;
+
+ /* lose terminfo padding--- looks like $<...> */
+ w = what;
+ while (*w) if ((*w++ == '$') && (*w == '<'))
+ {
+ w1 = w - 1;
+ while (*w && (*w != '>')) w++;
+ if (*w == 0) break;
+ w++;
+ wsave = w1;
+ while ((*w1++ = *w++) != 0);
+ w = wsave;
+ }
+
+ if (*what == 0) what = NULL;
+ return what;
+}
+
+char *SLtt_tgetstr (char *s)
+{
+ if (Termcap_Initalized == 0)
+ return NULL;
+
+#ifdef USE_TERMCAP
+ s = tgetstr (s, &Termcap_String_Ptr);
+#else
+ s = _SLtt_tigetstr (Terminfo, s);
+#endif
+ return fixup_tgetstr (s);
+}
+
+int SLtt_tgetnum (char *s)
+{
+ if (Termcap_Initalized == 0)
+ return -1;
+#ifdef USE_TERMCAP
+ return tgetnum (s);
+#else
+ return _SLtt_tigetnum (Terminfo, s);
+#endif
+}
+
+int SLtt_tgetflag (char *s)
+{
+ if (Termcap_Initalized == 0)
+ return -1;
+#ifdef USE_TERMCAP
+ return tgetflag (s);
+#else
+ return _SLtt_tigetflag (Terminfo, s);
+#endif
+}
+
+static int Vt100_Like = 0;
+
+void SLtt_get_terminfo (void)
+{
+ char *term;
+ int status;
+
+ term = getenv ("TERM");
+ if (term == NULL)
+ SLang_exit_error("TERM environment variable needs set.");
+
+ if (0 == (status = SLtt_initialize (term)))
+ return;
+
+ if (status == -1)
+ {
+ SLang_exit_error ("Unknown terminal: %s\n\
+Check the TERM environment variable.\n\
+Also make sure that the terminal is defined in the terminfo database.\n\
+Alternatively, set the TERMCAP environment variable to the desired\n\
+termcap entry.",
+ term);
+ }
+
+ if (status == -2)
+ {
+ SLang_exit_error ("\
+Your terminal lacks the ability to clear the screen or position the cursor.\n");
+ }
+}
+
+/* Returns 0 if all goes well, -1 if terminal capabilities cannot be deduced,
+ * or -2 if terminal cannot position the cursor.
+ */
+int SLtt_initialize (char *term)
+{
+ char *t, ch;
+ int is_xterm;
+ int almost_vtxxx;
+
+ if (SLang_TT_Write_FD == -1)
+ {
+ /* Apparantly, this cannot fail according to the man pages. */
+ SLang_TT_Write_FD = fileno (stdout);
+ }
+
+ if (term == NULL)
+ {
+ term = getenv ("TERM");
+ if (term == NULL)
+ return -1;
+ }
+
+ Linux_Console = (!strncmp (term, "linux", 5)
+# ifdef linux
+ || !strncmp(term, "con", 3)
+# endif
+ );
+
+ t = term;
+
+ if (strcmp(t, "vt52") && (*t++ == 'v') && (*t++ == 't')
+ && (ch = *t, (ch >= '1') && (ch <= '9'))) Vt100_Like = 1;
+
+ is_xterm = ((0 == strncmp (term, "xterm", 5))
+ || (0 == strncmp (term, "rxvt", 4))
+ || (0 == strncmp (term, "Eterm", 5)));
+
+ almost_vtxxx = (Vt100_Like
+ || Linux_Console
+ || is_xterm
+ || !strcmp (term, "screen"));
+
+# ifndef USE_TERMCAP
+ if (NULL == (Terminfo = _SLtt_tigetent (term)))
+ {
+ if (almost_vtxxx) /* Special cases. */
+ {
+ int vt102 = 1;
+ if (!strcmp (term, "vt100")) vt102 = 0;
+ get_color_info ();
+ SLtt_set_term_vtxxx (&vt102);
+ return 0;
+ }
+ return -1;
+ }
+# else /* USE_TERMCAP */
+ if (1 != tgetent(Termcap_Buf, term))
+ return -1;
+ Termcap_String_Ptr = Termcap_String_Buf;
+# endif /* NOT USE_TERMCAP */
+
+ Termcap_Initalized = 1;
+
+ Cls_Str = SLtt_tgetstr ("cl");
+ Curs_Pos_Str = SLtt_tgetstr ("cm");
+
+ if ((NULL == (Ins_Mode_Str = SLtt_tgetstr("im")))
+ || ( NULL == (Eins_Mode_Str = SLtt_tgetstr("ei")))
+ || ( NULL == (Del_Char_Str = SLtt_tgetstr("dc"))))
+ SLtt_Term_Cannot_Insert = 1;
+
+ Visible_Bell_Str = SLtt_tgetstr ("vb");
+ Curs_Up_Str = SLtt_tgetstr ("up");
+ Rev_Scroll_Str = SLtt_tgetstr("sr");
+ Del_N_Lines_Str = SLtt_tgetstr("DL");
+ Add_N_Lines_Str = SLtt_tgetstr("AL");
+
+ /* Actually these are used to initialize terminals that use cursor
+ * addressing. Hard to believe.
+ */
+ Term_Init_Str = SLtt_tgetstr ("ti");
+ Term_Reset_Str = SLtt_tgetstr ("te");
+
+ /* If I do this for vtxxx terminals, arrow keys start sending ESC O A,
+ * which I do not want. This is mainly for HP terminals.
+ */
+ if ((almost_vtxxx == 0) || SLtt_Force_Keypad_Init)
+ {
+ Keypad_Init_Str = SLtt_tgetstr ("ks");
+ Keypad_Reset_Str = SLtt_tgetstr ("ke");
+ }
+
+ /* Make up for defective termcap/terminfo databases */
+ if ((Vt100_Like && (term[2] != '1'))
+ || Linux_Console
+ || is_xterm
+ )
+ {
+ if (Del_N_Lines_Str == NULL) Del_N_Lines_Str = "\033[%dM";
+ if (Add_N_Lines_Str == NULL) Add_N_Lines_Str = "\033[%dL";
+ }
+
+ Scroll_R_Str = SLtt_tgetstr("cs");
+
+ SLtt_get_screen_size ();
+
+ if ((Scroll_R_Str == NULL)
+ || (((NULL == Del_N_Lines_Str) || (NULL == Add_N_Lines_Str))
+ && (NULL == Rev_Scroll_Str)))
+ {
+ if (is_xterm
+ || Linux_Console
+ )
+ {
+ /* Defective termcap mode!!!! */
+ SLtt_set_term_vtxxx (NULL);
+ }
+ else SLtt_Term_Cannot_Scroll = 1;
+ }
+
+ Del_Eol_Str = SLtt_tgetstr("ce");
+ Del_Bol_Str = SLtt_tgetstr("cb");
+ if (is_xterm && (Del_Bol_Str == NULL))
+ Del_Bol_Str = "\033[1K";
+ if (is_xterm && (Del_Eol_Str == NULL))
+ Del_Bol_Str = "\033[K";
+
+ Rev_Vid_Str = SLtt_tgetstr("mr");
+ if (Rev_Vid_Str == NULL) Rev_Vid_Str = SLtt_tgetstr("so");
+
+ Bold_Vid_Str = SLtt_tgetstr("md");
+
+ /* Although xterm cannot blink, it does display the blinking characters
+ * as bold ones. Some Rxvt will display the background as high intensity.
+ */
+ if ((NULL == (Blink_Vid_Str = SLtt_tgetstr("mb")))
+ && is_xterm)
+ Blink_Vid_Str = "\033[5m";
+
+ UnderLine_Vid_Str = SLtt_tgetstr("us");
+
+ Start_Alt_Chars_Str = SLtt_tgetstr ("as"); /* smacs */
+ End_Alt_Chars_Str = SLtt_tgetstr ("ae"); /* rmacs */
+ Enable_Alt_Char_Set = SLtt_tgetstr ("eA"); /* enacs */
+ SLtt_Graphics_Char_Pairs = SLtt_tgetstr ("ac");
+
+ if (NULL == SLtt_Graphics_Char_Pairs)
+ {
+ /* make up for defective termcap/terminfo */
+ if (Vt100_Like)
+ {
+ Start_Alt_Chars_Str = "\016";
+ End_Alt_Chars_Str = "\017";
+ Enable_Alt_Char_Set = "\033)0";
+ }
+ }
+
+ /* aixterm added by willi */
+ if (is_xterm || !strncmp (term, "aixterm", 7))
+ {
+ Start_Alt_Chars_Str = "\016";
+ End_Alt_Chars_Str = "\017";
+ Enable_Alt_Char_Set = "\033(B\033)0";
+ }
+
+ if ((SLtt_Graphics_Char_Pairs == NULL) &&
+ ((Start_Alt_Chars_Str == NULL) || (End_Alt_Chars_Str == NULL)))
+ {
+ SLtt_Has_Alt_Charset = 0;
+ Enable_Alt_Char_Set = NULL;
+ }
+ else SLtt_Has_Alt_Charset = 1;
+
+#ifdef AMIGA
+ Enable_Alt_Char_Set = Start_Alt_Chars_Str = End_Alt_Chars_Str = NULL;
+#endif
+
+ /* status line capabilities */
+ if ((SLtt_Has_Status_Line == -1)
+ && (0 != (SLtt_Has_Status_Line = TGETFLAG ("hs"))))
+ {
+ Disable_Status_line_Str = SLtt_tgetstr ("ds");
+ Return_From_Status_Line_Str = SLtt_tgetstr ("fs");
+ Goto_Status_Line_Str = SLtt_tgetstr ("ts");
+ /* Status_Line_Esc_Ok = TGETFLAG("es"); */
+ Num_Status_Line_Columns = SLtt_tgetnum ("ws");
+ if (Num_Status_Line_Columns < 0) Num_Status_Line_Columns = 0;
+ }
+
+ if (NULL == (Norm_Vid_Str = SLtt_tgetstr("me")))
+ {
+ Norm_Vid_Str = SLtt_tgetstr("se");
+ }
+
+ Cursor_Invisible_Str = SLtt_tgetstr("vi");
+ Cursor_Visible_Str = SLtt_tgetstr("ve");
+
+ Curs_F_Str = SLtt_tgetstr("RI");
+
+# if 0
+ if (NULL != Curs_F_Str)
+ {
+ Len_Curs_F_Str = strlen(Curs_F_Str);
+ }
+ else Len_Curs_F_Str = strlen(Curs_Pos_Str);
+# endif
+
+ Automatic_Margins = TGETFLAG ("am");
+ /* No_Move_In_Standout = !TGETFLAG ("ms"); */
+# ifdef HP_GLITCH_CODE
+ Has_HP_Glitch = TGETFLAG ("xs");
+# else
+ Worthless_Highlight = TGETFLAG ("xs");
+# endif
+
+ if (Worthless_Highlight == 0)
+ { /* Magic cookie glitch */
+ Worthless_Highlight = (SLtt_tgetnum ("sg") > 0);
+ }
+
+ if (Worthless_Highlight)
+ SLtt_Has_Alt_Charset = 0;
+
+ Reset_Color_String = SLtt_tgetstr ("op");
+ Color_Fg_Str = SLtt_tgetstr ("AF"); /* ANSI setaf */
+ Color_Bg_Str = SLtt_tgetstr ("AB"); /* ANSI setbf */
+ if ((Color_Fg_Str == NULL) || (Color_Bg_Str == NULL))
+ {
+ Color_Fg_Str = SLtt_tgetstr ("Sf"); /* setf */
+ Color_Bg_Str = SLtt_tgetstr ("Sb"); /* setb */
+ }
+
+ if ((Max_Terminfo_Colors = SLtt_tgetnum ("Co")) < 0)
+ Max_Terminfo_Colors = 8;
+
+ if ((Color_Bg_Str != NULL) && (Color_Fg_Str != NULL))
+ SLtt_Use_Ansi_Colors = 1;
+ else
+ {
+#if 0
+ Color_Fg_Str = "%?%p1%{7}%>%t\033[1;3%p1%{8}%m%dm%e\033[3%p1%dm%;";
+ Color_Bg_Str = "%?%p1%{7}%>%t\033[5;4%p1%{8}%m%dm%e\033[4%p1%dm%;";
+ Max_Terminfo_Colors = 16;
+#else
+ Color_Fg_Str = "\033[3%dm";
+ Color_Bg_Str = "\033[4%dm";
+ Max_Terminfo_Colors = 8;
+#endif
+ }
+
+#if SLTT_HAS_NON_BCE_SUPPORT
+ Can_Background_Color_Erase = TGETFLAG ("ut"); /* bce */
+ /* Modern xterms have the BCE capability as well as the linux console */
+ if (Can_Background_Color_Erase == 0)
+ {
+ Can_Background_Color_Erase = (Linux_Console
+# if SLTT_XTERM_ALWAYS_BCE
+ || is_xterm
+# endif
+ );
+ }
+#endif
+ get_color_info ();
+
+
+ if ((Cls_Str == NULL)
+ || (Curs_Pos_Str == NULL))
+ return -2;
+
+ return 0;
+}
+
+#endif
+/* Unix */
+
+/* specific to vtxxx only */
+void SLtt_enable_cursor_keys (void)
+{
+#ifdef __unix__
+ if (Vt100_Like)
+#endif
+ tt_write_string("\033=\033[?1l");
+}
+
+#ifdef VMS
+int SLtt_initialize (char *term)
+{
+ SLtt_get_terminfo ();
+ return 0;
+}
+
+void SLtt_get_terminfo ()
+{
+ int zero = 0;
+
+ Color_Fg_Str = "\033[3%dm";
+ Color_Bg_Str = "\033[4%dm";
+ Max_Terminfo_Colors = 8;
+
+ get_color_info ();
+
+ SLtt_set_term_vtxxx(&zero);
+ Start_Alt_Chars_Str = "\016";
+ End_Alt_Chars_Str = "\017";
+ SLtt_Has_Alt_Charset = 1;
+ SLtt_Graphics_Char_Pairs = "aaffgghhjjkkllmmnnooqqssttuuvvwwxx";
+ Enable_Alt_Char_Set = "\033(B\033)0";
+ SLtt_get_screen_size ();
+}
+#endif
+
+/* This sets term for vt102 terminals it parameter vt100 is 0. If vt100
+ * is non-zero, set terminal appropriate for a only vt100
+ * (no add line capability). */
+
+void SLtt_set_term_vtxxx(int *vt100)
+{
+ Norm_Vid_Str = "\033[m";
+
+ Scroll_R_Str = "\033[%i%d;%dr";
+ Cls_Str = "\033[2J\033[H";
+ Rev_Vid_Str = "\033[7m";
+ Bold_Vid_Str = "\033[1m";
+ Blink_Vid_Str = "\033[5m";
+ UnderLine_Vid_Str = "\033[4m";
+ Del_Eol_Str = "\033[K";
+ Del_Bol_Str = "\033[1K";
+ Rev_Scroll_Str = "\033M";
+ Curs_F_Str = "\033[%dC";
+ /* Len_Curs_F_Str = 5; */
+ Curs_Pos_Str = "\033[%i%d;%dH";
+ if ((vt100 == NULL) || (*vt100 == 0))
+ {
+ Ins_Mode_Str = "\033[4h";
+ Eins_Mode_Str = "\033[4l";
+ Del_Char_Str = "\033[P";
+ Del_N_Lines_Str = "\033[%dM";
+ Add_N_Lines_Str = "\033[%dL";
+ SLtt_Term_Cannot_Insert = 0;
+ }
+ else
+ {
+ Del_N_Lines_Str = NULL;
+ Add_N_Lines_Str = NULL;
+ SLtt_Term_Cannot_Insert = 1;
+ }
+ SLtt_Term_Cannot_Scroll = 0;
+ /* No_Move_In_Standout = 0; */
+}
+
+int SLtt_init_video (void)
+{
+ /* send_string_to_term("\033[?6h"); */
+ /* relative origin mode */
+ tt_write_string (Term_Init_Str);
+ tt_write_string (Keypad_Init_Str);
+ SLtt_reset_scroll_region();
+ SLtt_end_insert();
+ tt_write_string (Enable_Alt_Char_Set);
+ Video_Initialized = 1;
+ return 0;
+}
+
+int SLtt_reset_video (void)
+{
+ SLtt_goto_rc (SLtt_Screen_Rows - 1, 0);
+ Cursor_Set = 0;
+ SLtt_normal_video (); /* MSKermit requires this */
+ tt_write_string(Norm_Vid_Str);
+
+ Current_Fgbg = 0xFFFFFFFFU;
+ SLtt_set_alt_char_set (0);
+ if (SLtt_Use_Ansi_Colors)
+ {
+ if (Reset_Color_String == NULL)
+ {
+ SLtt_Char_Type attr;
+ if (-1 != make_color_fgbg (NULL, NULL, &attr))
+ write_attributes (attr);
+ else tt_write_string ("\033[0m\033[m");
+ }
+ else tt_write_string (Reset_Color_String);
+ Current_Fgbg = 0xFFFFFFFFU;
+ }
+ SLtt_erase_line ();
+ tt_write_string (Keypad_Reset_Str);
+ tt_write_string (Term_Reset_Str);
+ SLtt_flush_output ();
+ Video_Initialized = 0;
+ return 0;
+}
+
+void SLtt_bold_video (void)
+{
+ tt_write_string (Bold_Vid_Str);
+}
+
+int SLtt_set_mouse_mode (int mode, int force)
+{
+ char *term;
+
+ if (force == 0)
+ {
+ if (NULL == (term = (char *) getenv("TERM"))) return -1;
+ if (strncmp ("xterm", term, 5))
+ return -1;
+ }
+
+ if (mode)
+ tt_write_string ("\033[?9h");
+ else
+ tt_write_string ("\033[?9l");
+
+ return 0;
+}
+
+void SLtt_disable_status_line (void)
+{
+ if (SLtt_Has_Status_Line > 0)
+ {
+ tt_write_string (Disable_Status_line_Str);
+ SLtt_flush_output ();
+ }
+}
+
+int SLtt_write_to_status_line (char *s, int col)
+{
+ if ((SLtt_Has_Status_Line <= 0)
+ || (Goto_Status_Line_Str == NULL)
+ || (Return_From_Status_Line_Str == NULL))
+ return -1;
+
+ tt_printf (Goto_Status_Line_Str, col, 0);
+ tt_write_string (s);
+ tt_write_string (Return_From_Status_Line_Str);
+ return 0;
+}
+
+void SLtt_get_screen_size (void)
+{
+#ifdef VMS
+ int status, code;
+ unsigned short chan;
+ $DESCRIPTOR(dev_dsc, "SYS$INPUT:");
+#endif
+ int r = 0, c = 0;
+
+#ifdef TIOCGWINSZ
+ struct winsize wind_struct;
+
+ do
+ {
+ if ((ioctl(1,TIOCGWINSZ,&wind_struct) == 0)
+ || (ioctl(0, TIOCGWINSZ, &wind_struct) == 0)
+ || (ioctl(2, TIOCGWINSZ, &wind_struct) == 0))
+ {
+ c = (int) wind_struct.ws_col;
+ r = (int) wind_struct.ws_row;
+ break;
+ }
+ }
+ while (errno == EINTR);
+
+#endif
+
+#ifdef VMS
+ status = sys$assign(&dev_dsc,&chan,0,0,0);
+ if (status & 1)
+ {
+ code = DVI$_DEVBUFSIZ;
+ status = lib$getdvi(&code, &chan,0, &c, 0,0);
+ if (!(status & 1))
+ c = 80;
+ code = DVI$_TT_PAGE;
+ status = lib$getdvi(&code, &chan,0, &r, 0,0);
+ if (!(status & 1))
+ r = 24;
+ sys$dassgn(chan);
+ }
+#endif
+
+ if (r <= 0)
+ {
+ char *s = getenv ("LINES");
+ if (s != NULL) r = atoi (s);
+ }
+
+ if (c <= 0)
+ {
+ char *s = getenv ("COLUMNS");
+ if (s != NULL) c = atoi (s);
+ }
+
+ if (r <= 0) r = 24;
+ if (c <= 0) c = 80;
+#if 0
+ if ((r <= 0) || (r > 200)) r = 24;
+ if ((c <= 0) || (c > 250)) c = 80;
+#endif
+ SLtt_Screen_Rows = r;
+ SLtt_Screen_Cols = c;
+}
+
+#if SLTT_HAS_NON_BCE_SUPPORT
+int _SLtt_get_bce_color_offset (void)
+{
+ if ((SLtt_Use_Ansi_Colors == 0)
+ || Can_Background_Color_Erase
+ || SLtt_Use_Blink_For_ACS) /* in this case, we cannot lose a color */
+ Bce_Color_Offset = 0;
+ else
+ {
+ if (GET_BG(Ansi_Color_Map[0].fgbg) == SLSMG_COLOR_DEFAULT)
+ Bce_Color_Offset = 0;
+ else
+ Bce_Color_Offset = 1;
+ }
+
+ return Bce_Color_Offset;
+}
+#endif
diff --git a/mdk-stage1/slang/slerr.c b/mdk-stage1/slang/slerr.c
new file mode 100644
index 000000000..139b3859b
--- /dev/null
+++ b/mdk-stage1/slang/slerr.c
@@ -0,0 +1,181 @@
+/* error handling common to all routines. */
+/* Copyright (c) 1992, 1999, 2001 John E. Davis
+ * This file is part of the S-Lang library.
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Perl Artistic License.
+ */
+
+#include "slinclud.h"
+
+#include "slang.h"
+#include "_slang.h"
+
+void (*SLang_VMessage_Hook) (char *, va_list);
+void (*SLang_Error_Hook)(char *);
+void (*SLang_Exit_Error_Hook)(char *, va_list);
+volatile int SLang_Error = 0;
+char *SLang_Error_Message;
+volatile int SLKeyBoard_Quit = 0;
+
+static char *get_error_string (void)
+{
+ char *str;
+
+ if (!SLang_Error) SLang_Error = SL_UNKNOWN_ERROR;
+ if (SLang_Error_Message != NULL) str = SLang_Error_Message;
+ else switch(SLang_Error)
+ {
+ case SL_NOT_IMPLEMENTED: str = "Not Implemented"; break;
+ case SL_APPLICATION_ERROR: str = "Application Error"; break;
+ case SL_VARIABLE_UNINITIALIZED: str = "Variable Uninitialized"; break;
+ case SL_MALLOC_ERROR : str = "Malloc Error"; break;
+ case SL_INTERNAL_ERROR: str = "Internal Error"; break;
+ case SL_STACK_OVERFLOW: str = "Stack Overflow"; break;
+ case SL_STACK_UNDERFLOW: str = "Stack Underflow"; break;
+ case SL_INTRINSIC_ERROR: str = "Intrinsic Error"; break;
+ case SL_USER_BREAK: str = "User Break"; break;
+ case SL_UNDEFINED_NAME: str = "Undefined Name"; break;
+ case SL_SYNTAX_ERROR: str = "Syntax Error"; break;
+ case SL_DUPLICATE_DEFINITION: str = "Duplicate Definition"; break;
+ case SL_TYPE_MISMATCH: str = "Type Mismatch"; break;
+ case SL_READONLY_ERROR: str = "Variable is read-only"; break;
+ case SL_DIVIDE_ERROR: str = "Divide by zero"; break;
+ case SL_OBJ_NOPEN: str = "Object not opened"; break;
+ case SL_OBJ_UNKNOWN: str = "Object unknown"; break;
+ case SL_INVALID_PARM: str = "Invalid Parameter"; break;
+ case SL_TYPE_UNDEFINED_OP_ERROR:
+ str = "Operation not defined for datatype"; break;
+ case SL_USER_ERROR:
+ str = "User Error"; break;
+ case SL_USAGE_ERROR:
+ str = "Illegal usage of function";
+ break;
+ case SL_FLOATING_EXCEPTION:
+ str = "Floating Point Exception";
+ break;
+ case SL_UNKNOWN_ERROR:
+ default: str = "Unknown Error Code";
+ }
+
+ SLang_Error_Message = NULL;
+ return str;
+}
+
+void SLang_doerror (char *error)
+{
+ char *str = NULL;
+ char *err;
+ char *malloced_err_buf;
+ char err_buf [1024];
+
+ malloced_err_buf = NULL;
+
+ if (((SLang_Error == SL_USER_ERROR)
+ || (SLang_Error == SL_USAGE_ERROR))
+ && (error != NULL) && (*error != 0))
+ err = error;
+ else
+ {
+ char *sle = "S-Lang Error: ";
+ unsigned int len;
+ char *fmt;
+
+ str = get_error_string ();
+
+ fmt = "%s%s%s";
+ if ((error == NULL) || (*error == 0))
+ error = "";
+ else if (SLang_Error == SL_UNKNOWN_ERROR)
+ /* Do not display an unknown error message if error is non-NULL */
+ str = "";
+ else
+ fmt = "%s%s: %s";
+
+ len = strlen (sle) + strlen (str) + strlen(error) + 1;
+
+ err = err_buf;
+ if (len >= sizeof (err_buf))
+ {
+ if (NULL == (malloced_err_buf = SLmalloc (len)))
+ err = NULL;
+ else
+ err = malloced_err_buf;
+ }
+
+ if (err != NULL) sprintf (err, fmt, sle, str, error);
+ else err = "Out of memory";
+ }
+
+ if (SLang_Error_Hook == NULL)
+ {
+ fputs (err, stderr);
+ fputs("\r\n", stderr);
+ fflush (stderr);
+ }
+ else
+ (*SLang_Error_Hook)(err);
+
+ SLfree (malloced_err_buf);
+}
+
+void SLang_verror (int err_code, char *fmt, ...)
+{
+ va_list ap;
+ char err [1024];
+
+ if (err_code == 0) err_code = SL_INTRINSIC_ERROR;
+ if (SLang_Error == 0) SLang_Error = err_code;
+
+ if (fmt != NULL)
+ {
+ va_start(ap, fmt);
+ (void) _SLvsnprintf (err, sizeof (err), fmt, ap);
+ fmt = err;
+ va_end(ap);
+ }
+
+ SLang_doerror (fmt);
+}
+
+void SLang_exit_error (char *fmt, ...)
+{
+ va_list ap;
+
+ va_start (ap, fmt);
+ if (SLang_Exit_Error_Hook != NULL)
+ {
+ (*SLang_Exit_Error_Hook) (fmt, ap);
+ exit (1);
+ }
+
+ if (fmt != NULL)
+ {
+ vfprintf (stderr, fmt, ap);
+ fputs ("\r\n", stderr);
+ fflush (stderr);
+ }
+ va_end (ap);
+
+ exit (1);
+}
+
+void SLang_vmessage (char *fmt, ...)
+{
+ va_list ap;
+
+ if (fmt == NULL)
+ return;
+
+ va_start (ap, fmt);
+
+ if (SLang_VMessage_Hook != NULL)
+ (*SLang_VMessage_Hook) (fmt, ap);
+ else
+ {
+ vfprintf (stdout, fmt, ap);
+ fputs ("\r\n", stdout);
+ }
+
+ va_end (ap);
+}
diff --git a/mdk-stage1/slang/slerrno.c b/mdk-stage1/slang/slerrno.c
new file mode 100644
index 000000000..662fadde1
--- /dev/null
+++ b/mdk-stage1/slang/slerrno.c
@@ -0,0 +1,219 @@
+/* The point of this file is to handle errno values in a system independent
+ * way so that they may be used in slang scripts.
+ */
+/* Copyright (c) 1998, 1999, 2001 John E. Davis
+ * This file is part of the S-Lang library.
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Perl Artistic License.
+ */
+#include "slinclud.h"
+
+#include <errno.h>
+#include "slang.h"
+#include "_slang.h"
+
+typedef struct
+{
+ char *msg;
+ int sys_errno;
+ char *symbolic_name;
+}
+Errno_Map_Type;
+
+static Errno_Map_Type Errno_Map [] =
+{
+#ifndef EPERM
+# define EPERM -1
+#endif
+ {"Not owner", EPERM, "EPERM"},
+#ifndef ENOENT
+# define ENOENT -1
+#endif
+ {"No such file or directory", ENOENT, "ENOENT"},
+#ifndef ESRCH
+# define ESRCH -1
+#endif
+ {"No such process", ESRCH, "ESRCH"},
+#ifndef EINTR
+# define EINTR -1
+#endif
+ {"Interrupted system call", EINTR, "EINTR"},
+#ifndef EIO
+# define EIO -1
+#endif
+ {"I/O error", EIO, "EIO"},
+#ifndef ENXIO
+# define ENXIO -1
+#endif
+ {"No such device or address", ENXIO, "ENXIO"},
+#ifndef E2BIG
+# define E2BIG -1
+#endif
+ {"Arg list too long", E2BIG, "E2BIG"},
+#ifndef ENOEXEC
+# define ENOEXEC -1
+#endif
+ {"Exec format error", ENOEXEC,"ENOEXEC"},
+#ifndef EBADF
+# define EBADF -1
+#endif
+ {"Bad file number", EBADF, "EBADF"},
+#ifndef ECHILD
+# define ECHILD -1
+#endif
+ {"No children", ECHILD, "ECHILD"},
+#ifndef EAGAIN
+# define EAGAIN -1
+#endif
+ {"Try again", EAGAIN, "EAGAIN"},
+#ifndef ENOMEM
+# define ENOMEM -1
+#endif
+ {"Not enough core", ENOMEM, "ENOMEM"},
+#ifndef EACCES
+# define EACCES -1
+#endif
+ {"Permission denied", EACCES, "EACCES"},
+#ifndef EFAULT
+# define EFAULT -1
+#endif
+ {"Bad address", EFAULT, "EFAULT"},
+#ifndef ENOTBLK
+# define ENOTBLK -1
+#endif
+ {"Block device required", ENOTBLK, "ENOTBLK"},
+#ifndef EBUSY
+# define EBUSY -1
+#endif
+ {"Mount device busy", EBUSY, "EBUSY"},
+#ifndef EEXIST
+# define EEXIST -1
+#endif
+ {"File exists", EEXIST, "EEXIST"},
+#ifndef EXDEV
+# define EXDEV -1
+#endif
+ {"Cross-device link", EXDEV, "EXDEV"},
+#ifndef ENODEV
+# define ENODEV -1
+#endif
+ {"No such device", ENODEV, "ENODEV"},
+#ifndef ENOTDIR
+# define ENOTDIR -1
+#endif
+ {"Not a directory", ENOTDIR, "ENOTDIR"},
+#ifndef EISDIR
+# define EISDIR -1
+#endif
+ {"Is a directory", EISDIR, "EISDIR"},
+#ifndef EINVAL
+# define EINVAL -1
+#endif
+ {"Invalid argument", EINVAL, "EINVAL"},
+#ifndef ENFILE
+# define ENFILE -1
+#endif
+ {"File table overflow", ENFILE, "ENFILE"},
+#ifndef EMFILE
+# define EMFILE -1
+#endif
+ {"Too many open files", EMFILE, "EMFILE"},
+#ifndef ENOTTY
+# define ENOTTY -1
+#endif
+ {"Not a typewriter", ENOTTY, "ENOTTY"},
+#ifndef ETXTBSY
+# define ETXTBSY -1
+#endif
+ {"Text file busy", ETXTBSY, "ETXTBSY"},
+#ifndef EFBIG
+# define EFBIG -1
+#endif
+ {"File too large", EFBIG, "EFBIG"},
+#ifndef ENOSPC
+# define ENOSPC -1
+#endif
+ {"No space left on device", ENOSPC, "ENOSPC"},
+#ifndef ESPIPE
+# define ESPIPE -1
+#endif
+ {"Illegal seek", ESPIPE, "ESPIPE"},
+#ifndef EROFS
+# define EROFS -1
+#endif
+ {"Read-only file system", EROFS, "EROFS"},
+#ifndef EMLINK
+# define EMLINK -1
+#endif
+ {"Too many links", EMLINK, "EMLINK"},
+#ifndef EPIPE
+# define EPIPE -1
+#endif
+ {"Broken pipe", EPIPE, "EPIPE"},
+#ifndef ELOOP
+# define ELOOP -1
+#endif
+ {"Too many levels of symbolic links",ELOOP, "ELOOP"},
+#ifndef ENAMETOOLONG
+# define ENAMETOOLONG -1
+#endif
+ {"File name too long", ENAMETOOLONG, "ENAMETOOLONG"},
+
+ {NULL, 0, NULL}
+};
+
+int _SLerrno_errno;
+
+int SLerrno_set_errno (int sys_errno)
+{
+ _SLerrno_errno = sys_errno;
+ return 0;
+}
+
+char *SLerrno_strerror (int sys_errno)
+{
+ Errno_Map_Type *e;
+
+ e = Errno_Map;
+ while (e->msg != NULL)
+ {
+ if (e->sys_errno == sys_errno)
+ return e->msg;
+
+ e++;
+ }
+
+ if (sys_errno == SL_ERRNO_NOT_IMPLEMENTED)
+ return "System call not available for this platform";
+
+ return "Unknown error";
+}
+
+static char *intrin_errno_string (int *sys_errno)
+{
+ return SLerrno_strerror (*sys_errno);
+}
+
+int _SLerrno_init (void)
+{
+ static Errno_Map_Type *e;
+
+ if (e != NULL) /* already initialized */
+ return 0;
+
+ if ((-1 == SLadd_intrinsic_function ("errno_string", (FVOID_STAR) intrin_errno_string,
+ SLANG_STRING_TYPE, 1, SLANG_INT_TYPE))
+ || (-1 == SLadd_intrinsic_variable ("errno", (VOID_STAR)&_SLerrno_errno, SLANG_INT_TYPE, 1)))
+ return -1;
+
+ e = Errno_Map;
+ while (e->msg != NULL)
+ {
+ if (-1 == SLadd_intrinsic_variable (e->symbolic_name, (VOID_STAR) &e->sys_errno, SLANG_INT_TYPE, 1))
+ return -1;
+ e++;
+ }
+
+ return 0;
+}
diff --git a/mdk-stage1/slang/slgetkey.c b/mdk-stage1/slang/slgetkey.c
new file mode 100644
index 000000000..2f2914f07
--- /dev/null
+++ b/mdk-stage1/slang/slgetkey.c
@@ -0,0 +1,306 @@
+/* Copyright (c) 1992, 1999, 2001 John E. Davis
+ * This file is part of the S-Lang library.
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Perl Artistic License.
+ */
+
+#include "slinclud.h"
+
+#include "slang.h"
+#include "_slang.h"
+
+unsigned int SLang_Input_Buffer_Len = 0;
+unsigned char SLang_Input_Buffer [SL_MAX_INPUT_BUFFER_LEN];
+
+int SLang_Abort_Char = 7;
+int SLang_Ignore_User_Abort = 0;
+
+/* This has the effect of mapping all characters in the range 128-169 to
+ * ESC [ something
+ */
+
+unsigned int SLang_getkey (void)
+{
+ unsigned int imax;
+ unsigned int ch;
+
+ if (SLang_Input_Buffer_Len)
+ {
+ ch = (unsigned int) *SLang_Input_Buffer;
+ SLang_Input_Buffer_Len--;
+ imax = SLang_Input_Buffer_Len;
+
+ SLMEMCPY ((char *) SLang_Input_Buffer,
+ (char *) (SLang_Input_Buffer + 1), imax);
+ }
+ else if (SLANG_GETKEY_ERROR == (ch = _SLsys_getkey ())) return ch;
+
+#if _SLANG_MAP_VTXXX_8BIT
+# if !defined(IBMPC_SYSTEM)
+ if (ch & 0x80)
+ {
+ unsigned char i;
+ i = (unsigned char) (ch & 0x7F);
+ if (i < ' ')
+ {
+ i += 64;
+ SLang_ungetkey (i);
+ ch = 27;
+ }
+ }
+# endif
+#endif
+ return(ch);
+}
+
+int SLang_ungetkey_string (unsigned char *s, unsigned int n)
+{
+ register unsigned char *bmax, *b, *b1;
+ if (SLang_Input_Buffer_Len + n + 3 > SL_MAX_INPUT_BUFFER_LEN)
+ return -1;
+
+ b = SLang_Input_Buffer;
+ bmax = (b - 1) + SLang_Input_Buffer_Len;
+ b1 = bmax + n;
+ while (bmax >= b) *b1-- = *bmax--;
+ bmax = b + n;
+ while (b < bmax) *b++ = *s++;
+ SLang_Input_Buffer_Len += n;
+ return 0;
+}
+
+int SLang_buffer_keystring (unsigned char *s, unsigned int n)
+{
+
+ if (n + SLang_Input_Buffer_Len + 3 > SL_MAX_INPUT_BUFFER_LEN) return -1;
+
+ SLMEMCPY ((char *) SLang_Input_Buffer + SLang_Input_Buffer_Len,
+ (char *) s, n);
+ SLang_Input_Buffer_Len += n;
+ return 0;
+}
+
+int SLang_ungetkey (unsigned char ch)
+{
+ return SLang_ungetkey_string(&ch, 1);
+}
+
+int SLang_input_pending (int tsecs)
+{
+ int n;
+ unsigned char c;
+ if (SLang_Input_Buffer_Len) return (int) SLang_Input_Buffer_Len;
+
+ n = _SLsys_input_pending (tsecs);
+
+ if (n <= 0) return 0;
+
+ c = (unsigned char) SLang_getkey ();
+ SLang_ungetkey_string (&c, 1);
+
+ return n;
+}
+
+void SLang_flush_input (void)
+{
+ int quit = SLKeyBoard_Quit;
+
+ SLang_Input_Buffer_Len = 0;
+ SLKeyBoard_Quit = 0;
+ while (_SLsys_input_pending (0) > 0)
+ {
+ (void) _SLsys_getkey ();
+ /* Set this to 0 because _SLsys_getkey may stuff keyboard buffer if
+ * key sends key sequence (OS/2, DOS, maybe VMS).
+ */
+ SLang_Input_Buffer_Len = 0;
+ }
+ SLKeyBoard_Quit = quit;
+}
+
+#ifdef IBMPC_SYSTEM
+static int Map_To_ANSI;
+int SLgetkey_map_to_ansi (int enable)
+{
+ Map_To_ANSI = enable;
+ return 0;
+}
+
+static int convert_scancode (unsigned int scan,
+ unsigned int shift,
+ int getkey,
+ unsigned int *ret_key)
+{
+ unsigned char buf[16];
+ unsigned char *b;
+ unsigned char end;
+ int is_arrow;
+
+ shift &= (_SLTT_KEY_ALT|_SLTT_KEY_SHIFT|_SLTT_KEY_CTRL);
+
+ b = buf;
+ if (_SLTT_KEY_ALT == shift)
+ {
+ shift = 0;
+ *b++ = 27;
+ }
+ *b++ = 27;
+ *b++ = '[';
+
+ is_arrow = 0;
+ end = '~';
+ if (shift)
+ {
+ if (shift == _SLTT_KEY_CTRL)
+ end = '^';
+ else if (shift == _SLTT_KEY_SHIFT)
+ end = '$';
+ else shift = 0;
+ }
+
+ /* These mappings correspond to what rxvt produces under Linux */
+ switch (scan & 0xFF)
+ {
+ default:
+ return -1;
+
+ case 0x47: /* home */
+ *b++ = '1';
+ break;
+ case 0x48: /* up */
+ end = 'A';
+ is_arrow = 1;
+ break;
+ case 0x49: /* PgUp */
+ *b++ = '5';
+ break;
+ case 0x4B: /* Left */
+ end = 'D';
+ is_arrow = 1;
+ break;
+ case 0x4D: /* Right */
+ end = 'C';
+ is_arrow = 1;
+ break;
+ case 0x4F: /* End */
+ *b++ = '4';
+ break;
+ case 0x50: /* Down */
+ end = 'B';
+ is_arrow = 1;
+ break;
+ case 0x51: /* PgDn */
+ *b++ = '6';
+ break;
+ case 0x52: /* Insert */
+ *b++ = '2';
+ break;
+ case 0x53: /* Delete */
+ *b++ = '3';
+ break;
+ case ';': /* F1 */
+ *b++ = '1';
+ *b++ = '1';
+ break;
+ case '<': /* F2 */
+ *b++ = '1';
+ *b++ = '2';
+ break;
+ case '=': /* F3 */
+ *b++ = '1';
+ *b++ = '3';
+ break;
+
+ case '>': /* F4 */
+ *b++ = '1';
+ *b++ = '4';
+ break;
+
+ case '?': /* F5 */
+ *b++ = '1';
+ *b++ = '5';
+ break;
+
+ case '@': /* F6 */
+ *b++ = '1';
+ *b++ = '7';
+ break;
+
+ case 'A': /* F7 */
+ *b++ = '1';
+ *b++ = '8';
+ break;
+
+ case 'B': /* F8 */
+ *b++ = '1';
+ *b++ = '9';
+ break;
+
+ case 'C': /* F9 */
+ *b++ = '2';
+ *b++ = '0';
+ break;
+
+ case 'D': /* F10 */
+ *b++ = '2';
+ *b++ = '1';
+ break;
+
+ case 0x57: /* F11 */
+ *b++ = '2';
+ *b++ = '3';
+ break;
+
+ case 0x58: /* F12 */
+ *b++ = '2';
+ *b++ = '4';
+ break;
+ }
+
+ if (is_arrow && shift)
+ {
+ if (shift == _SLTT_KEY_CTRL)
+ end &= 0x1F;
+ else
+ end |= 0x20;
+ }
+ *b++ = end;
+
+ if (getkey)
+ {
+ (void) SLang_buffer_keystring (buf + 1, (unsigned int) (b - (buf + 1)));
+ *ret_key = buf[0];
+ return 0;
+ }
+
+ (void) SLang_buffer_keystring (buf, (unsigned int) (b - buf));
+ return 0;
+}
+
+
+unsigned int _SLpc_convert_scancode (unsigned int scan,
+ unsigned int shift,
+ int getkey)
+{
+ unsigned char buf[16];
+
+ if (Map_To_ANSI)
+ {
+ if (0 == convert_scancode (scan, shift, getkey, &scan))
+ return scan;
+ }
+
+ if (getkey)
+ {
+ buf[0] = scan & 0xFF;
+ SLang_buffer_keystring (buf, 1);
+ return (scan >> 8) & 0xFF;
+ }
+ buf[0] = (scan >> 8) & 0xFF;
+ buf[1] = scan & 0xFF;
+ (void) SLang_buffer_keystring (buf, 2);
+ return 0;
+}
+
+#endif
diff --git a/mdk-stage1/slang/slimport.c b/mdk-stage1/slang/slimport.c
new file mode 100644
index 000000000..44b4b25e1
--- /dev/null
+++ b/mdk-stage1/slang/slimport.c
@@ -0,0 +1,281 @@
+/* Copyright (c) 1998, 1999, 2001 John E. Davis
+ * This file is part of the S-Lang library.
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Perl Artistic License.
+ */
+
+#include "slinclud.h"
+
+#include "slang.h"
+#include "_slang.h"
+
+#define SLANG_HAS_DYNAMIC_LINKING 1
+
+#ifndef HAVE_DLFCN_H
+# undef SLANG_HAS_DYNAMIC_LINKING
+# define SLANG_HAS_DYNAMIC_LINKING 0
+#endif
+
+/* The rest of this file is in the if block */
+#if SLANG_HAS_DYNAMIC_LINKING
+
+#ifdef HAVE_DLFCN_H
+# include <dlfcn.h>
+#endif
+
+static char *Module_Path;
+#define MODULE_PATH_ENV_NAME "SLANG_MODULE_PATH"
+#ifndef MODULE_INSTALL_DIR
+# define MODULE_INSTALL_DIR "/usr/local/lib/slang/modules"
+#endif
+
+typedef struct _Handle_Type
+{
+ struct _Handle_Type *next;
+ char *name;
+ VOID_STAR handle;
+ void (*deinit_fun) (void);
+}
+Handle_Type;
+
+static Handle_Type *Handle_List;
+
+static void delete_handles (void)
+{
+ while (Handle_List != NULL)
+ {
+ Handle_Type *next = Handle_List->next;
+
+ if (Handle_List->deinit_fun != NULL)
+ Handle_List->deinit_fun ();
+ (void) dlclose (Handle_List->handle);
+ SLang_free_slstring (Handle_List->name);
+ SLfree ((char *)Handle_List);
+ Handle_List = next;
+ }
+}
+
+static Handle_Type *save_handle (char *name, VOID_STAR h, void (*df)(void))
+{
+ Handle_Type *l;
+
+ l = (Handle_Type *) SLmalloc (sizeof (Handle_Type));
+ if (l == NULL)
+ return NULL;
+ memset ((char *) l, 0, sizeof(Handle_Type));
+ if (NULL == (l->name = SLang_create_slstring (name)))
+ {
+ SLfree ((char *) l);
+ return NULL;
+ }
+ l->handle = h;
+ l->next = Handle_List;
+ l->deinit_fun = df;
+ Handle_List = l;
+
+ return l;
+}
+
+static Handle_Type *find_handle (char *name)
+{
+ Handle_Type *l;
+
+ l = Handle_List;
+ while (l != NULL)
+ {
+ if (0 == strcmp (l->name, name))
+ break;
+ l = l->next;
+ }
+ return l;
+}
+
+static int import_from_library (char *name,
+ char *init_fun_name, char *deinit_fun_name,
+ char *file,
+ char *ns,
+ char *ns_init_fun_name)
+{
+ VOID_STAR handle;
+ int (*init_fun) (void);
+ int (*ns_init_fun) (char *);
+ void (*deinit_fun) (void);
+ char *err;
+ char filebuf[1024];
+ char *fun_name;
+
+ if (NULL != find_handle (name))
+ return 0; /* already loaded */
+
+ while (1)
+ {
+#ifndef RTLD_GLOBAL
+# define RTLD_GLOBAL 0
+#endif
+#ifdef RTLD_NOW
+ handle = (VOID_STAR) dlopen (file, RTLD_NOW | RTLD_GLOBAL);
+#else
+ handle = (VOID_STAR) dlopen (file, RTLD_LAZY | RTLD_GLOBAL);
+#endif
+
+ if (handle != NULL)
+ break;
+
+ if (NULL == strchr (file, '/'))
+ {
+ _SLsnprintf (filebuf, sizeof (filebuf), "./%s", file);
+ file = filebuf;
+ continue;
+ }
+
+ if (NULL == (err = (char *) dlerror ()))
+ err = "UNKNOWN";
+
+ SLang_verror (SL_INTRINSIC_ERROR,
+ "Error linking to %s: %s", file, err);
+ return -1;
+ }
+
+ fun_name = ns_init_fun_name;
+ ns_init_fun = (int (*)(char *)) dlsym (handle, fun_name);
+ if (ns_init_fun == NULL)
+ {
+ if ((ns != NULL)
+ && (0 != strcmp (ns, "Global")))
+ goto return_error;
+
+ fun_name = init_fun_name;
+ init_fun = (int (*)(void)) dlsym (handle, fun_name);
+ if (init_fun == NULL)
+ goto return_error;
+
+ if (-1 == (*init_fun) ())
+ {
+ dlclose (handle);
+ return -1;
+ }
+ }
+ else if (-1 == (*ns_init_fun) (ns))
+ {
+ dlclose (handle);
+ return -1;
+ }
+
+
+ deinit_fun = (void (*)(void)) dlsym (handle, deinit_fun_name);
+
+ (void) save_handle (name, handle, deinit_fun);
+ return 0;
+
+ return_error:
+
+ if (NULL == (err = (char *) dlerror ()))
+ err = "UNKNOWN";
+
+ dlclose (handle);
+ SLang_verror (SL_INTRINSIC_ERROR,
+ "Unable to get symbol %s from %s: %s",
+ name, file, err);
+ return -1;
+}
+
+static void import_module (void)
+{
+ char module_name[256];
+ char symbol_name[256];
+ char deinit_name[256];
+ char ns_init_name[256];
+ char *path;
+ char *file;
+ char *module;
+ char *ns = NULL;
+
+ if (SLang_Num_Function_Args == 2)
+ {
+ if (-1 == SLang_pop_slstring (&ns))
+ return;
+ }
+
+ if (-1 == SLang_pop_slstring (&module))
+ {
+ SLang_free_slstring (ns); /* NULL ok */
+ return;
+ }
+
+ _SLsnprintf (symbol_name, sizeof(symbol_name), "init_%s_module", module);
+ _SLsnprintf (module_name, sizeof(module_name), "%s-module.so", module);
+ _SLsnprintf (deinit_name, sizeof(deinit_name), "deinit_%s_module", module);
+ _SLsnprintf (ns_init_name, sizeof (ns_init_name), "init_%s_module_ns", module);
+
+ if (Module_Path != NULL)
+ file = SLpath_find_file_in_path (Module_Path, module_name);
+ else file = NULL;
+
+ if ((file == NULL)
+ && (NULL != (path = getenv (MODULE_PATH_ENV_NAME))))
+ file = SLpath_find_file_in_path (path, module_name);
+
+ if (file == NULL)
+ file = SLpath_find_file_in_path (MODULE_INSTALL_DIR, module_name);
+
+ if (file != NULL)
+ {
+ (void) import_from_library (symbol_name, symbol_name, deinit_name, file, ns, ns_init_name);
+ SLfree (file);
+ }
+ else
+ {
+ /* Maybe the system loader can find it in LD_LIBRARY_PATH */
+ (void) import_from_library (symbol_name, symbol_name, deinit_name, module_name, ns, ns_init_name);
+ }
+}
+
+static void set_import_module_path (char *path)
+{
+ (void) SLang_set_module_load_path (path);
+}
+
+static char *get_import_module_path (void)
+{
+ char *path;
+ if (Module_Path != NULL)
+ return Module_Path;
+ if (NULL != (path = getenv (MODULE_PATH_ENV_NAME)))
+ return path;
+ return MODULE_INSTALL_DIR;
+}
+
+static SLang_Intrin_Fun_Type Module_Intrins [] =
+{
+ MAKE_INTRINSIC_0("import", import_module, SLANG_VOID_TYPE),
+ MAKE_INTRINSIC_S("set_import_module_path", set_import_module_path, SLANG_VOID_TYPE),
+ MAKE_INTRINSIC_0("get_import_module_path", get_import_module_path, SLANG_STRING_TYPE),
+ SLANG_END_INTRIN_FUN_TABLE
+};
+
+#endif /* SLANG_HAS_DYNAMIC_LINKING */
+
+int SLang_set_module_load_path (char *path)
+{
+#if SLANG_HAS_DYNAMIC_LINKING
+ if (NULL == (path = SLang_create_slstring (path)))
+ return -1;
+ SLang_free_slstring (Module_Path);
+ Module_Path = path;
+ return 0;
+#else
+ (void) path;
+ return -1;
+#endif
+}
+
+int SLang_init_import (void)
+{
+#if SLANG_HAS_DYNAMIC_LINKING
+ (void) SLang_add_cleanup_function (delete_handles);
+ return SLadd_intrin_fun_table (Module_Intrins, "__IMPORT__");
+#else
+ return 0;
+#endif
+}
diff --git a/mdk-stage1/slang/slinclud.h b/mdk-stage1/slang/slinclud.h
new file mode 100644
index 000000000..d60a4423e
--- /dev/null
+++ b/mdk-stage1/slang/slinclud.h
@@ -0,0 +1,26 @@
+#ifndef _SLANG_INCLUDE_H_
+#define _SLANG_INCLUDE_H_
+
+#include "config.h"
+#include "sl-feat.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#ifdef HAVE_STDLIB_H
+# include <stdlib.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#ifdef HAVE_MALLOC_H
+# include <malloc.h>
+#endif
+
+#ifdef HAVE_MEMORY_H
+# include <memory.h>
+#endif
+
+#endif /* _SLANG_INCLUDE_H_ */
diff --git a/mdk-stage1/slang/slintall.c b/mdk-stage1/slang/slintall.c
new file mode 100644
index 000000000..a66b9d6d2
--- /dev/null
+++ b/mdk-stage1/slang/slintall.c
@@ -0,0 +1,27 @@
+/* Copyright (c) 1998, 1999, 2001 John E. Davis
+ * This file is part of the S-Lang library.
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Perl Artistic License.
+ */
+#include "slinclud.h"
+
+#include "slang.h"
+#include "_slang.h"
+
+int SLang_init_all (void)
+{
+ if ((-1 == SLang_init_slang ())
+ || (-1 == SLang_init_slmath ())
+ || (-1 == SLang_init_posix_dir ())
+ || (-1 == SLang_init_posix_process ())
+ || (-1 == SLang_init_stdio ())
+ || (-1 == SLang_init_array ())
+ || (-1 == SLang_init_posix_io ())
+ || (-1 == SLang_init_ospath ())
+ )
+ return -1;
+
+ return 0;
+}
+
diff --git a/mdk-stage1/slang/slistruc.c b/mdk-stage1/slang/slistruc.c
new file mode 100644
index 000000000..06b8fd6ff
--- /dev/null
+++ b/mdk-stage1/slang/slistruc.c
@@ -0,0 +1,218 @@
+/* Intrinsic Structure type implementation */
+/* Copyright (c) 1998, 1999, 2001 John E. Davis
+ * This file is part of the S-Lang library.
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Perl Artistic License.
+ */
+#include "slinclud.h"
+
+#include "slang.h"
+#include "_slang.h"
+
+/* Intrinsic structures */
+
+typedef struct
+{
+ char *name;
+ VOID_STAR addr;
+ SLang_IStruct_Field_Type *fields;
+}
+_SLang_IStruct_Type;
+
+static SLang_IStruct_Field_Type *istruct_pop_field (char *name, int no_readonly, VOID_STAR *addr)
+{
+ _SLang_IStruct_Type *s;
+ SLang_IStruct_Field_Type *f;
+ char *struct_addr;
+
+ /* Note: There is no need to free this object */
+ if (-1 == SLclass_pop_ptr_obj (SLANG_ISTRUCT_TYPE, (VOID_STAR *) &s))
+ return NULL;
+
+ if (NULL == (struct_addr = *(char **)s->addr))
+ {
+ SLang_verror (SL_INTRINSIC_ERROR,
+ "%s is NULL. Unable to access field", s->name);
+ return NULL;
+ }
+
+ f = s->fields;
+ while (f->field_name != NULL)
+ {
+ /* Since both these are slstrings, just test pointers */
+ if (f->field_name != name)
+ {
+ f++;
+ continue;
+ }
+
+ if (no_readonly && f->read_only)
+ {
+ SLang_verror (SL_READONLY_ERROR,
+ "%s.%s is read-only", s->name, name);
+ return NULL;
+ }
+
+ *addr = (VOID_STAR) (struct_addr + f->offset);
+ return f;
+ }
+
+ SLang_verror (SL_TYPE_MISMATCH,
+ "%s has no field called %s", s->name, name);
+ return NULL;
+}
+
+static int istruct_sget (unsigned char type, char *name)
+{
+ SLang_IStruct_Field_Type *f;
+ VOID_STAR addr;
+ SLang_Class_Type *cl;
+
+ if (NULL == (f = istruct_pop_field (name, 0, &addr)))
+ return -1;
+
+ type = f->type;
+ cl = _SLclass_get_class (type);
+
+ return (cl->cl_push_intrinsic)(f->type, addr);
+}
+
+static int istruct_sput (unsigned char type, char *name)
+{
+ SLang_IStruct_Field_Type *f;
+ VOID_STAR addr;
+ SLang_Class_Type *cl;
+
+ if (NULL == (f = istruct_pop_field (name, 1, &addr)))
+ return -1;
+
+ type = f->type;
+ cl = _SLclass_get_class (type);
+
+ return (*cl->cl_pop) (type, addr);
+}
+
+static int istruct_push (unsigned char type, VOID_STAR ptr)
+{
+ _SLang_IStruct_Type *s;
+
+ s = *(_SLang_IStruct_Type **) ptr;
+ if ((s == NULL)
+ || (s->addr == NULL)
+ || (*(char **) s->addr == NULL))
+ return SLang_push_null ();
+
+ return SLclass_push_ptr_obj (type, (VOID_STAR) s);
+}
+
+static int istruct_pop (unsigned char type, VOID_STAR ptr)
+{
+ return SLclass_pop_ptr_obj (type, (VOID_STAR *)ptr);
+}
+
+static void istruct_destroy (unsigned char type, VOID_STAR ptr)
+{
+ (void) type;
+ (void) ptr;
+}
+
+/* Intrinsic struct objects are not stored in a variable. So, the address that
+ * is passed here is actually a pointer to the struct. So, pass its address
+ * to istruct_push since v is a variable. Confusing, n'est pas?
+ */
+static int istruct_push_intrinsic (unsigned char type, VOID_STAR v)
+{
+ return istruct_push (type, (VOID_STAR) &v);
+}
+
+static int init_intrin_struct (void)
+{
+ SLang_Class_Type *cl;
+ static int initialized;
+
+ if (initialized)
+ return 0;
+
+ if (NULL == (cl = SLclass_allocate_class ("IStruct_Type")))
+ return -1;
+
+ cl->cl_pop = istruct_pop;
+ cl->cl_push = istruct_push;
+ cl->cl_sget = istruct_sget;
+ cl->cl_sput = istruct_sput;
+ cl->cl_destroy = istruct_destroy;
+ cl->cl_push_intrinsic = istruct_push_intrinsic;
+
+ if (-1 == SLclass_register_class (cl, SLANG_ISTRUCT_TYPE, sizeof (_SLang_IStruct_Type *),
+ SLANG_CLASS_TYPE_PTR))
+ return -1;
+
+ initialized = 1;
+ return 0;
+}
+
+int SLadd_istruct_table (SLang_IStruct_Field_Type *fields, VOID_STAR addr, char *name)
+{
+ _SLang_IStruct_Type *s;
+ SLang_IStruct_Field_Type *f;
+
+ if (-1 == init_intrin_struct ())
+ return -1;
+
+ if (addr == NULL)
+ {
+ SLang_verror (SL_INVALID_PARM,
+ "SLadd_istruct_table: address must be non-NULL");
+ return -1;
+ }
+
+ if (fields == NULL)
+ return -1;
+
+ /* Make the field names slstrings so that only the pointers need to be
+ * compared. However, this table may have been already been added for
+ * another instance of the intrinsic object. So, check for the presence
+ * of an slstring.
+ */
+ f = fields;
+ while (f->field_name != NULL)
+ {
+ char *fname;
+
+ fname = SLang_create_slstring (f->field_name);
+ if (fname == NULL)
+ return -1;
+
+ /* Here is the check for the slstring */
+ if (f->field_name == fname)
+ SLang_free_slstring (fname);
+ else /* replace string literal with slstring */
+ f->field_name = fname;
+
+ f++;
+ }
+
+ s = (_SLang_IStruct_Type *)SLmalloc (sizeof (_SLang_IStruct_Type));
+ if (s == NULL)
+ return -1;
+
+ memset ((char *)s, 0, sizeof (_SLang_IStruct_Type));
+ if (NULL == (s->name = SLang_create_slstring (name)))
+ {
+ SLfree ((char *) s);
+ return -1;
+ }
+
+ s->addr = addr;
+ s->fields = fields;
+
+ if (-1 == SLadd_intrinsic_variable (name, (VOID_STAR) s, SLANG_ISTRUCT_TYPE, 1))
+ {
+ SLang_free_slstring (s->name);
+ SLfree ((char *) s);
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/mdk-stage1/slang/slkeymap.c b/mdk-stage1/slang/slkeymap.c
new file mode 100644
index 000000000..dff65433e
--- /dev/null
+++ b/mdk-stage1/slang/slkeymap.c
@@ -0,0 +1,596 @@
+/* Keymap routines for SLang. The role of these keymap routines is simple:
+ * Just read keys from the tty and return a pointer to a keymap structure.
+ * That is, a keymap is simple a mapping of strings (keys from tty) to
+ * structures. Also included are routines for managing the keymaps.
+ */
+/* Copyright (c) 1992, 1999, 2001 John E. Davis
+ * This file is part of the S-Lang library.
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Perl Artistic License.
+ */
+
+#include "slinclud.h"
+
+#include "slang.h"
+#include "_slang.h"
+
+/* We need a define a rule for upperand lower case chars that user cannot
+ change! This could be a problem for international chars! */
+
+#define UPPER_CASE_KEY(x) (((x) >= 'a') && ((x) <= 'z') ? (x) - 32 : (x))
+#define LOWER_CASE_KEY(x) (((x) >= 'A') && ((x) <= 'Z') ? (x) + 32 : (x))
+
+int SLang_Key_TimeOut_Flag = 0; /* true if more than 1 sec has elapsed
+ without key in multikey sequence */
+
+int SLang_Last_Key_Char;
+
+SLKeyMap_List_Type SLKeyMap_List[SLANG_MAX_KEYMAPS];
+
+static SLang_Key_Type *malloc_key(unsigned char *str)
+{
+ SLang_Key_Type *neew;
+
+ if (NULL == (neew = (SLang_Key_Type *) SLmalloc(sizeof(SLang_Key_Type))))
+ return NULL;
+
+ SLMEMSET ((char *) neew, 0, sizeof (SLang_Key_Type));
+ SLMEMCPY((char *) neew->str, (char *) str, (unsigned int) *str);
+ return(neew);
+}
+
+static SLKeyMap_List_Type *add_keymap (char *name, SLang_Key_Type *map)
+{
+ int i;
+
+ for (i = 0; i < SLANG_MAX_KEYMAPS; i++)
+ {
+ if (SLKeyMap_List[i].keymap == NULL)
+ {
+ if (NULL == (name = SLang_create_slstring (name)))
+ return NULL;
+
+ SLKeyMap_List[i].keymap = map;
+ SLKeyMap_List[i].name = name;
+ return &SLKeyMap_List[i];
+ }
+ }
+ SLang_Error = SL_UNKNOWN_ERROR;
+ /* SLang_doerror ("Keymap quota exceeded."); */
+ return NULL;
+}
+
+FVOID_STAR SLang_find_key_function(char *name, SLKeyMap_List_Type *keymap)
+{
+ SLKeymap_Function_Type *fp = keymap -> functions;
+ char ch = *name;
+
+ while ((fp != NULL) && (fp->name != NULL))
+ {
+ if ((ch == *fp->name)
+ && (0 == strcmp(fp->name, name)))
+ return (FVOID_STAR) fp->f;
+
+ fp++;
+ }
+ return NULL;
+}
+
+#ifdef REAL_UNIX_SYSTEM
+/* Expand termcap string specified by s. s as passed will have the format:
+ * "XY)..." where XY represents a termcap keyname.
+ */
+static char *process_termcap_string (char *s, char *str, int *ip, int imax)
+{
+ char c[3], *val;
+ int i;
+
+ if ((0 == (c[0] = s[0]))
+ || (0 == (c[1] = s[1]))
+ || (s[2] != ')'))
+ {
+ SLang_verror (SL_SYNTAX_ERROR, "setkey: ^(%s is badly formed", s);
+ return NULL;
+ }
+ s += 3;
+
+ c[2] = 0;
+ if ((NULL == (val = SLtt_tgetstr (c)))
+ || (*val == 0))
+ return NULL;
+
+ i = *ip;
+ while ((i < imax) && (*val != 0))
+ {
+ str[i++] = *val++;
+ }
+ *ip = i;
+
+ return s;
+}
+#endif
+
+/* convert things like "^A" to 1 etc... The 0th char is the strlen INCLUDING
+ * the length character itself.
+ */
+char *SLang_process_keystring(char *s)
+{
+ /* FIXME: v2.0, make this thread safe */
+ static char str[32];
+ unsigned char ch;
+ int i;
+
+ i = 1;
+ while (*s != 0)
+ {
+ ch = (unsigned char) *s++;
+ if (ch == '^')
+ {
+ ch = *s++;
+ if (ch == 0)
+ {
+ if (i < 32)
+ str[i++] = '^';
+ break;
+ }
+#ifdef REAL_UNIX_SYSTEM
+ if (ch == '(')
+ {
+ s = process_termcap_string (s, str, &i, 32);
+ if (s == NULL)
+ {
+ str[0] = 1;
+ return str;
+ }
+ continue;
+ }
+#endif
+ ch = UPPER_CASE_KEY(ch);
+ if (ch == '?') ch = 127; else ch = ch - 'A' + 1;
+ }
+
+ if (i >= 32) break;
+ str[i++] = ch;
+ }
+
+ if (i > SLANG_MAX_KEYMAP_KEY_SEQ)
+ {
+ SLang_verror (SL_INVALID_PARM, "Key sequence is too long");
+ return NULL;
+ }
+
+ str[0] = i;
+ return(str);
+}
+
+static int key_string_compare (unsigned char *a, unsigned char *b, unsigned int len)
+{
+ unsigned char *amax = a + len;
+ int cha, chb, cha_up, chb_up;
+
+ while (a < amax)
+ {
+ cha = *a++;
+ chb = *b++;
+
+ if (cha == chb) continue;
+
+ cha_up = UPPER_CASE_KEY(cha);
+ chb_up = UPPER_CASE_KEY(chb);
+
+ if (cha_up == chb_up)
+ {
+ /* Use case-sensitive result. */
+ return cha - chb;
+ }
+ /* Use case-insensitive result. */
+ return cha_up - chb_up;
+ }
+ return 0;
+}
+
+static char *Define_Key_Error = "Inconsistency in define key.";
+
+/* This function also performs an insertion in an ordered way. */
+static int find_the_key (char *s, SLKeyMap_List_Type *kml, SLang_Key_Type **keyp)
+{
+ unsigned char ch;
+ unsigned int str_len;
+ SLang_Key_Type *key, *last, *neew;
+ unsigned char *str;
+
+ *keyp = NULL;
+
+ if (NULL == (str = (unsigned char *) SLang_process_keystring(s)))
+ return -2;
+
+ if (1 == (str_len = str[0]))
+ return 0;
+
+ ch = str[1];
+ key = kml->keymap + ch;
+
+ if (str_len == 2)
+ {
+ if (key->next != NULL)
+ {
+ SLang_doerror (Define_Key_Error);
+ return -2;
+ }
+
+ if (key->type == SLKEY_F_INTERPRET)
+ SLang_free_slstring (key->f.s);
+
+ key->str[0] = str_len;
+ key->str[1] = ch;
+
+ *keyp = key;
+ return 0;
+ }
+
+ /* insert the key definition */
+ while (1)
+ {
+ int cmp;
+ unsigned int key_len, len;
+
+ last = key;
+ key = key->next;
+
+ if ((key != NULL) && (key->str != NULL))
+ {
+ len = key_len = key->str[0];
+ if (len > str_len) len = str_len;
+
+ cmp = key_string_compare (str + 1, key->str + 1, len - 1);
+
+ if (cmp > 0)
+ continue;
+
+ if (cmp == 0)
+ {
+ if (key_len != str_len)
+ {
+ SLang_doerror (Define_Key_Error);
+ return -2;
+ }
+
+ if (key->type == SLKEY_F_INTERPRET)
+ SLang_free_slstring (key->f.s);
+
+ *keyp = key;
+ return 0;
+ }
+ /* Drop to cmp < 0 case */
+ }
+
+ if (NULL == (neew = malloc_key(str))) return -1;
+
+ neew -> next = key;
+ last -> next = neew;
+
+ *keyp = neew;
+ return 0;
+ }
+}
+
+/* returns -2 if inconsistent, -1 if malloc error, 0 upon success */
+int SLkm_define_key (char *s, FVOID_STAR f, SLKeyMap_List_Type *kml)
+{
+ SLang_Key_Type *key;
+ unsigned int type = SLKEY_F_INTRINSIC;
+ int ret;
+
+ ret = find_the_key (s, kml, &key);
+ if ((ret != 0) || (key == NULL))
+ return ret;
+
+ key->type = type;
+ key->f.f = f;
+ return 0;
+}
+
+int SLang_define_key (char *s, char *funct, SLKeyMap_List_Type *kml)
+{
+ SLang_Key_Type *key;
+ FVOID_STAR f;
+ int ret;
+
+ ret = find_the_key (s, kml, &key);
+ if ((ret != 0) || (key == NULL))
+ return ret;
+
+ f = SLang_find_key_function(funct, kml);
+
+ if (f == NULL) /* assume interpreted */
+ {
+ char *str = SLang_create_slstring (funct);
+ if (str == NULL) return -1;
+ key->type = SLKEY_F_INTERPRET;
+ key->f.s = str;
+ }
+ else
+ {
+ key->type = SLKEY_F_INTRINSIC;
+ key->f.f = f;
+ }
+ return 0;
+}
+
+int SLkm_define_keysym (char *s, unsigned int keysym, SLKeyMap_List_Type *kml)
+{
+ SLang_Key_Type *key;
+ int ret;
+
+ ret = find_the_key (s, kml, &key);
+
+ if ((ret != 0) || (key == NULL))
+ return ret;
+
+ key->type = SLKEY_F_KEYSYM;
+ key->f.keysym = keysym;
+ return 0;
+}
+
+SLang_Key_Type *SLang_do_key(SLKeyMap_List_Type *kml, int (*getkey)(void))
+{
+ register SLang_Key_Type *key, *next, *kmax;
+ unsigned int len;
+ unsigned char input_ch;
+ register unsigned char chup, chlow;
+ unsigned char key_ch = 0;
+
+ SLang_Last_Key_Char = (*getkey)();
+ SLang_Key_TimeOut_Flag = 0;
+
+ if (SLANG_GETKEY_ERROR == (unsigned int) SLang_Last_Key_Char)
+ return NULL;
+
+ input_ch = (unsigned char) SLang_Last_Key_Char;
+
+ key = (SLang_Key_Type *) &((kml->keymap)[input_ch]);
+
+ /* if the next one is null, then we know this MAY be it. */
+ while (key->next == NULL)
+ {
+ if (key->type != 0)
+ return key;
+
+ /* Try its opposite case counterpart */
+ chlow = LOWER_CASE_KEY(input_ch);
+ if (input_ch == chlow)
+ input_ch = UPPER_CASE_KEY(input_ch);
+
+ key = kml->keymap + input_ch;
+ if (key->type == 0)
+ return NULL;
+ }
+
+ /* It appears to be a prefix character in a key sequence. */
+
+ len = 1; /* already read one character */
+ key = key->next; /* Now we are in the key list */
+ kmax = NULL; /* set to end of list */
+
+ while (1)
+ {
+ SLang_Key_TimeOut_Flag = 1;
+ SLang_Last_Key_Char = (*getkey)();
+ SLang_Key_TimeOut_Flag = 0;
+
+ len++;
+
+ if ((SLANG_GETKEY_ERROR == (unsigned int) SLang_Last_Key_Char)
+ || SLKeyBoard_Quit)
+ break;
+
+ input_ch = (unsigned char) SLang_Last_Key_Char;
+
+ chup = UPPER_CASE_KEY(input_ch); chlow = LOWER_CASE_KEY(input_ch);
+
+ while (key != kmax)
+ {
+ if (key->str[0] > len)
+ {
+ key_ch = key->str[len];
+ if (chup == UPPER_CASE_KEY(key_ch))
+ break;
+ }
+ key = key->next;
+ }
+
+ if (key == kmax) break;
+
+ /* If the input character is lowercase, check to see if there is
+ * a lowercase match. If so, set key to it. Note: the
+ * algorithm assumes the sorting performed by key_string_compare.
+ */
+ if (input_ch != key_ch)
+ {
+ next = key->next;
+ while (next != kmax)
+ {
+ if (next->str[0] > len)
+ {
+ unsigned char next_ch = next->str[len];
+ if (next_ch == input_ch)
+ {
+ key = next;
+ break;
+ }
+ if (next_ch != chup)
+ break;
+ }
+ next = next->next;
+ }
+ }
+
+ /* Ok, we found the first position of a possible match. If it
+ * is exact, we are done.
+ */
+ if ((unsigned int) key->str[0] == len + 1)
+ return key;
+
+ /* Apparantly, there are some ambiguities. Read next key to resolve
+ * the ambiguity. Adjust kmax to encompass ambiguities.
+ */
+
+ next = key->next;
+ while (next != kmax)
+ {
+ if ((unsigned int) next->str[0] > len)
+ {
+ key_ch = next->str[len];
+ if (chup != UPPER_CASE_KEY(key_ch))
+ break;
+ }
+ next = next->next;
+ }
+ kmax = next;
+ }
+
+ return NULL;
+}
+
+void SLang_undefine_key(char *s, SLKeyMap_List_Type *kml)
+{
+ int n, i;
+ SLang_Key_Type *key, *next, *last, *key_root, *keymap;
+ unsigned char *str;
+
+ keymap = kml -> keymap;
+ if (NULL == (str = (unsigned char *) SLang_process_keystring(s)))
+ return;
+
+ if (0 == (n = *str++ - 1)) return;
+ i = *str;
+
+ last = key_root = (SLang_Key_Type *) &(keymap[i]);
+ key = key_root->next;
+
+ while (key != NULL)
+ {
+ next = key->next;
+ if (0 == SLMEMCMP ((char *)(key->str + 1), (char *) str, n))
+ {
+ if (key->type == SLKEY_F_INTERPRET)
+ SLang_free_slstring (key->f.s);
+
+ SLfree((char *) key);
+ last->next = next;
+ }
+ else last = key;
+ key = next;
+ }
+
+ if (n == 1)
+ {
+ *key_root->str = 0;
+ key_root->f.f = NULL;
+ key_root->type = 0;
+ }
+}
+
+char *SLang_make_keystring(unsigned char *s)
+{
+ static char buf [3 * SLANG_MAX_KEYMAP_KEY_SEQ + 1];
+ char *b;
+ int n;
+
+ n = *s++ - 1;
+
+ if (n > SLANG_MAX_KEYMAP_KEY_SEQ)
+ {
+ SLang_verror (SL_INVALID_PARM, "Key sequence is too long");
+ return NULL;
+ }
+
+ b = buf;
+ while (n--)
+ {
+ if (*s < 32)
+ {
+ *b++ = '^';
+ *b++ = *s + 'A' - 1;
+ }
+ else *b++ = *s;
+ s++;
+ }
+ *b = 0;
+ return(buf);
+}
+
+static SLang_Key_Type *copy_keymap(SLKeyMap_List_Type *kml)
+{
+ int i;
+ SLang_Key_Type *neew, *old, *new_root, *km;
+
+ if (NULL == (new_root = (SLang_Key_Type *) SLcalloc(256, sizeof(SLang_Key_Type))))
+ return NULL;
+
+ if (kml == NULL) return new_root;
+ km = kml->keymap;
+
+ for (i = 0; i < 256; i++)
+ {
+ old = &(km[i]);
+ neew = &(new_root[i]);
+
+ if (old->type == SLKEY_F_INTERPRET)
+ neew->f.s = SLang_create_slstring (old->f.s);
+ else
+ neew->f.f = old->f.f;
+
+ neew->type = old->type;
+ SLMEMCPY((char *) neew->str, (char *) old->str, (unsigned int) *old->str);
+
+ old = old->next;
+ while (old != NULL)
+ {
+ neew->next = malloc_key((unsigned char *) old->str);
+ neew = neew->next;
+
+ if (old->type == SLKEY_F_INTERPRET)
+ neew->f.s = SLang_create_slstring (old->f.s);
+ else
+ neew->f.f = old->f.f;
+
+ neew->type = old->type;
+ old = old->next;
+ }
+ neew->next = NULL;
+ }
+ return(new_root);
+}
+
+SLKeyMap_List_Type *SLang_create_keymap(char *name, SLKeyMap_List_Type *map)
+{
+ SLang_Key_Type *neew;
+ SLKeyMap_List_Type *new_map;
+
+ if ((NULL == (neew = copy_keymap(map)))
+ || (NULL == (new_map = add_keymap(name, neew)))) return NULL;
+
+ if (map != NULL) new_map -> functions = map -> functions;
+
+ return new_map;
+}
+
+SLKeyMap_List_Type *SLang_find_keymap(char *name)
+{
+ SLKeyMap_List_Type *kmap, *kmap_max;
+
+ kmap = SLKeyMap_List;
+ kmap_max = kmap + SLANG_MAX_KEYMAPS;
+
+ while (kmap < kmap_max)
+ {
+ if ((kmap->name != NULL)
+ && (0 == strcmp (kmap->name, name)))
+ return kmap;
+
+ kmap++;
+ }
+ return NULL;
+}
diff --git a/mdk-stage1/slang/slkeypad.c b/mdk-stage1/slang/slkeypad.c
new file mode 100644
index 000000000..524dc80fa
--- /dev/null
+++ b/mdk-stage1/slang/slkeypad.c
@@ -0,0 +1,163 @@
+/* Copyright (c) 1998, 1999, 2001 John E. Davis
+ * This file is part of the S-Lang library.
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Perl Artistic License.
+ */
+#include "slinclud.h"
+
+#include "slang.h"
+#include "_slang.h"
+
+static SLKeyMap_List_Type *Keymap_List;
+
+int SLkp_init (void)
+{
+ char esc_seq[10];
+ int i;
+
+ if (NULL == (Keymap_List = SLang_create_keymap ("_SLKeypad", NULL)))
+ return -1;
+
+ esc_seq[1] = 0;
+ for (i = 1; i < 256; i++)
+ {
+ esc_seq[0] = (char) i;
+ SLkm_define_keysym (esc_seq, i, Keymap_List);
+ }
+
+ /* Now add most common ones. */
+#ifndef IBMPC_SYSTEM
+ SLkm_define_keysym ("^@", 0, Keymap_List);
+
+ SLkm_define_keysym ("\033[A", SL_KEY_UP, Keymap_List);
+ SLkm_define_keysym ("\033OA", SL_KEY_UP, Keymap_List);
+ SLkm_define_keysym ("\033[B", SL_KEY_DOWN, Keymap_List);
+ SLkm_define_keysym ("\033OB", SL_KEY_DOWN, Keymap_List);
+ SLkm_define_keysym ("\033[C", SL_KEY_RIGHT, Keymap_List);
+ SLkm_define_keysym ("\033OC", SL_KEY_RIGHT, Keymap_List);
+ SLkm_define_keysym ("\033[D", SL_KEY_LEFT, Keymap_List);
+ SLkm_define_keysym ("\033OD", SL_KEY_LEFT, Keymap_List);
+ SLkm_define_keysym ("\033[2~", SL_KEY_IC, Keymap_List);
+ SLkm_define_keysym ("\033[7~", SL_KEY_HOME, Keymap_List);
+ SLkm_define_keysym ("\033[5~", SL_KEY_PPAGE, Keymap_List);
+ SLkm_define_keysym ("\033[6~", SL_KEY_NPAGE, Keymap_List);
+ SLkm_define_keysym ("\033[8~", SL_KEY_END, Keymap_List);
+ SLkm_define_keysym ("\033[3~", SL_KEY_DELETE, Keymap_List);
+#else
+ /* Note: This will not work if SLgetkey_map_to_ansi (1) has
+ * been called.
+ */
+ SLkm_define_keysym ("^@\x48", SL_KEY_UP, Keymap_List );
+ SLkm_define_keysym ("^@\x50", SL_KEY_DOWN, Keymap_List );
+ SLkm_define_keysym ("^@\x4d", SL_KEY_RIGHT, Keymap_List );
+ SLkm_define_keysym ("^@\x4b", SL_KEY_LEFT, Keymap_List );
+ SLkm_define_keysym ("^@\x47", SL_KEY_HOME, Keymap_List );
+ SLkm_define_keysym ("^@\x49", SL_KEY_PPAGE, Keymap_List );
+ SLkm_define_keysym ("^@\x51", SL_KEY_NPAGE, Keymap_List );
+ SLkm_define_keysym ("^@\x4f", SL_KEY_END, Keymap_List );
+ SLkm_define_keysym ("^@\x52", SL_KEY_IC, Keymap_List );
+ SLkm_define_keysym ("^@\x53", SL_KEY_DELETE, Keymap_List );
+
+ SLkm_define_keysym ("\xE0\x48", SL_KEY_UP, Keymap_List );
+ SLkm_define_keysym ("\xE0\x50", SL_KEY_DOWN, Keymap_List );
+ SLkm_define_keysym ("\xE0\x4d", SL_KEY_RIGHT, Keymap_List );
+ SLkm_define_keysym ("\xE0\x4b", SL_KEY_LEFT, Keymap_List );
+ SLkm_define_keysym ("\xE0\x47", SL_KEY_HOME, Keymap_List );
+ SLkm_define_keysym ("\xE0\x49", SL_KEY_PPAGE, Keymap_List );
+ SLkm_define_keysym ("\xE0\x51", SL_KEY_NPAGE, Keymap_List );
+ SLkm_define_keysym ("\xE0\x4f", SL_KEY_END, Keymap_List );
+ SLkm_define_keysym ("\xE0\x52", SL_KEY_IC, Keymap_List );
+ SLkm_define_keysym ("\xE0\x53", SL_KEY_DELETE, Keymap_List );
+
+ strcpy (esc_seq, "^@ "); /* guarantees esc_seq[3] = 0. */
+
+ for (i = 0x3b; i < 0x45; i++)
+ {
+ esc_seq [2] = i;
+ SLkm_define_keysym (esc_seq, SL_KEY_F(i - 0x3a), Keymap_List);
+ }
+ esc_seq[2] = 0x57; SLkm_define_keysym (esc_seq, SL_KEY_F(11), Keymap_List);
+ esc_seq[2] = 0x58; SLkm_define_keysym (esc_seq, SL_KEY_F(12), Keymap_List);
+#endif
+
+#ifdef REAL_UNIX_SYSTEM
+ strcpy (esc_seq, "^(kX)");
+ for (i = 0; i <= 9; i++)
+ {
+ esc_seq[3] = '0' + i;
+ SLkm_define_keysym (esc_seq, SL_KEY_F(i), Keymap_List);
+ }
+ SLkm_define_keysym ("^(k;)", SL_KEY_F(10), Keymap_List);
+
+ SLkm_define_keysym ("^(ku)", SL_KEY_UP, Keymap_List);
+ SLkm_define_keysym ("^(kd)", SL_KEY_DOWN, Keymap_List);
+ SLkm_define_keysym ("^(kl)", SL_KEY_LEFT, Keymap_List);
+ SLkm_define_keysym ("^(kr)", SL_KEY_RIGHT, Keymap_List);
+ SLkm_define_keysym ("^(kP)", SL_KEY_PPAGE, Keymap_List);
+ SLkm_define_keysym ("^(kN)", SL_KEY_NPAGE, Keymap_List);
+ SLkm_define_keysym ("^(kh)", SL_KEY_HOME, Keymap_List);
+ SLkm_define_keysym ("^(@7)", SL_KEY_END, Keymap_List);
+ SLkm_define_keysym ("^(K1)", SL_KEY_A1, Keymap_List);
+ SLkm_define_keysym ("^(K3)", SL_KEY_A3, Keymap_List);
+ SLkm_define_keysym ("^(K2)", SL_KEY_B2, Keymap_List);
+ SLkm_define_keysym ("^(K4)", SL_KEY_C1, Keymap_List);
+ SLkm_define_keysym ("^(K5)", SL_KEY_C3, Keymap_List);
+ SLkm_define_keysym ("^(%0)", SL_KEY_REDO, Keymap_List);
+ SLkm_define_keysym ("^(&8)", SL_KEY_UNDO, Keymap_List);
+ SLkm_define_keysym ("^(kb)", SL_KEY_BACKSPACE, Keymap_List);
+ SLkm_define_keysym ("^(@8)", SL_KEY_ENTER, Keymap_List);
+ SLkm_define_keysym ("^(kD)", SL_KEY_DELETE, Keymap_List);
+#endif
+
+ if (SLang_Error)
+ return -1;
+ return 0;
+}
+
+int SLkp_getkey (void)
+{
+ SLang_Key_Type *key;
+
+ key = SLang_do_key (Keymap_List, (int (*)(void)) SLang_getkey);
+ if ((key == NULL) || (key->type != SLKEY_F_KEYSYM))
+ {
+ SLang_flush_input ();
+ return SL_KEY_ERR;
+ }
+
+ return key->f.keysym;
+}
+
+int SLkp_define_keysym (char *keystr, unsigned int keysym)
+{
+ if (SLkm_define_keysym (keystr, keysym, Keymap_List) < 0)
+ return -1;
+
+ return 0;
+}
+
+#if 0
+int main (int argc, char **argv)
+{
+ int ch;
+
+ SLtt_get_terminfo ();
+
+ if (-1 == SLkp_init ())
+ return 1;
+
+ SLang_init_tty (-1, 0, 0);
+
+ while ('q' != (ch = SLkp_getkey ()))
+ {
+ fprintf (stdout, "Keycode = %d\r\n", ch);
+ fflush (stdout);
+ }
+
+ SLang_reset_tty ();
+
+ return 0;
+}
+#endif
+
diff --git a/mdk-stage1/slang/sllimits.h b/mdk-stage1/slang/sllimits.h
new file mode 100644
index 000000000..c4ae03b83
--- /dev/null
+++ b/mdk-stage1/slang/sllimits.h
@@ -0,0 +1,64 @@
+/* Copyright (c) 1998, 1999, 2001 John E. Davis
+ * This file is part of the S-Lang library.
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Perl Artistic License.
+ */
+/* sllimits.h */
+
+/* slstring.c: Size of the hash table used for strings (prime numbers) */
+#ifdef __MSDOS_16BIT__
+# define SLSTRING_HASH_TABLE_SIZE 601
+# define SLASSOC_HASH_TABLE_SIZE 601
+#else
+# define SLSTRING_HASH_TABLE_SIZE 2909
+# define SLASSOC_HASH_TABLE_SIZE 2909
+#endif
+
+/* slang.c: maximum size of run time stack */
+#ifdef __MSDOS_16BIT__
+# define SLANG_MAX_STACK_LEN 500
+#else
+# define SLANG_MAX_STACK_LEN 2500
+#endif
+
+/* slang.c: This sets the size on the depth of function calls */
+#ifdef __MSDOS_16BIT__
+# define SLANG_MAX_RECURSIVE_DEPTH 50
+#else
+# define SLANG_MAX_RECURSIVE_DEPTH 250
+#endif
+
+/* slang.c: Size of the stack used for local variables */
+#ifdef __MSDOS_16BIT__
+# define SLANG_MAX_LOCAL_STACK 200
+#else
+# define SLANG_MAX_LOCAL_STACK 1024
+#endif
+
+/* slang.c: The size of the hash table used for local and global objects.
+ * These should be prime numbers.
+ */
+#define SLGLOBALS_HASH_TABLE_SIZE 2909
+#define SLLOCALS_HASH_TABLE_SIZE 73
+#define SLSTATIC_HASH_TABLE_SIZE 73
+
+/* Size of the keyboard buffer use by the ungetkey routines */
+#ifdef __MSDOS_16BIT__
+# define SL_MAX_INPUT_BUFFER_LEN 40
+#else
+# define SL_MAX_INPUT_BUFFER_LEN 1024
+#endif
+
+/* Maximum number of nested switch statements */
+#define SLANG_MAX_NESTED_SWITCH 10
+
+/* Size of the block stack (used in byte-compiling) */
+#define SLANG_MAX_BLOCK_STACK_LEN 50
+
+/* slfile.c: Max number of open file pointers */
+#ifdef __MSDOS_16BIT__
+# define SL_MAX_FILES 32
+#else
+# define SL_MAX_FILES 256
+#endif
diff --git a/mdk-stage1/slang/slmalloc.c b/mdk-stage1/slang/slmalloc.c
new file mode 100644
index 000000000..be4ed6cae
--- /dev/null
+++ b/mdk-stage1/slang/slmalloc.c
@@ -0,0 +1,165 @@
+/* Copyright (c) 1992, 1999, 2001 John E. Davis
+ * This file is part of the S-Lang library.
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Perl Artistic License.
+ */
+#include "slinclud.h"
+
+#ifdef SL_MALLOC_DEBUG
+# undef SL_MALLOC_DEBUG
+#endif
+
+#include "slang.h"
+#include "_slang.h"
+
+#ifdef __alpha
+# define Chunk 8
+#else
+# define Chunk 4
+#endif
+
+static long Total_Allocated;
+static long Max_Single_Allocation;
+static long Max_Allocated;
+/* #define SLDEBUG_DOUT */
+
+#ifdef SLDEBUG_DOUT
+static FILE *dout;
+#endif
+
+void SLmalloc_dump_statistics (void)
+{
+#ifdef SLDEBUG_DOUT
+ fflush (dout);
+#endif
+ fprintf (stderr, "Total Allocated: %ld\nHighest single allocation: %ld\nHighest Total Allocated:%ld\n",
+ Total_Allocated, Max_Single_Allocation, Max_Allocated);
+}
+
+static void register_at_exit_fun (void)
+{
+ static int is_registered = 0;
+ if (is_registered)
+ return;
+ is_registered = 1;
+
+#ifdef SLDEBUG_DOUT
+ if (dout == NULL) dout = fopen ("malloc.out", "w");
+#endif
+ SLang_add_cleanup_function (SLmalloc_dump_statistics);
+}
+
+static void fixup (unsigned char *p, unsigned long n, char *what)
+{
+ register_at_exit_fun ();
+
+ p += Chunk;
+ *(p - 4)= (unsigned char) ((n >> 24) & 0xFF);
+ *(p - 3) = (unsigned char) ((n >> 16) & 0xFF);
+ *(p - 2) = (unsigned char) ((n >> 8) & 0xFF);
+ *(p - 1) = (unsigned char) (n & 0xFF);
+ *(p + (int) n) = 27;
+ *(p + (int) (n + 1)) = 182;
+ *(p + (int) (n + 2)) = 81;
+ *(p + (int) (n + 3)) = 86;
+ Total_Allocated += (long) n;
+ if (Total_Allocated > Max_Allocated) Max_Allocated = Total_Allocated;
+ if ((long) n > Max_Single_Allocation)
+ Max_Single_Allocation = (long) n;
+
+#ifdef SLDEBUG_DOUT
+ fprintf (dout, "ALLOC: %s\t%p %ld\n", what, p, (long) n);
+#else
+ (void) what;
+#endif
+}
+
+static void SLmalloc_doerror (char *buf)
+{
+ SLang_doerror (buf);
+}
+
+static int check_memory (unsigned char *p, char *what)
+{
+ char buf[128];
+ unsigned long n;
+
+ register_at_exit_fun ();
+
+ n = ((unsigned long) *(p - 4)) << 24;
+ n |= ((unsigned long) *(p - 3)) << 16;
+ n |= ((unsigned long) *(p - 2)) << 8;
+ n |= (unsigned long) *(p - 1);
+
+ if (n == 0xFFFFFFFFUL)
+ {
+ sprintf (buf, "%s: %p: Already FREE! Abort NOW.", what, (void*)p - Chunk);
+ SLmalloc_doerror (buf);
+ return -1;
+ }
+
+ if ((*(p + (int) n) != 27)
+ || (*(p + (int) (n + 1)) != 182)
+ || (*(p + (int) (n + 2)) != 81)
+ || (*(p + (int) (n + 3)) != 86))
+ {
+ sprintf (buf, "\007%s: %p: Memory corrupt! Abort NOW.", what, (void*)p);
+ SLmalloc_doerror (buf);
+ return -1;
+ }
+
+ *(p - 4) = *(p - 3) = *(p - 2) = *(p - 1) = 0xFF;
+
+ Total_Allocated -= (long) n;
+ if (Total_Allocated < 0)
+ {
+ sprintf (buf, "\007%s: %p\nFreed %ld, Allocated is: %ld!\n",
+ what, (void*)p, (long) n, Total_Allocated);
+ SLang_doerror (buf);
+ }
+#ifdef SLDEBUG_DOUT
+ fprintf (dout, "FREE: %s:\t%p %ld\n", what, p, (long) n);
+#endif
+ return 0;
+}
+
+void SLdebug_free (char *p)
+{
+ if (p == NULL) return;
+ if (-1 == check_memory ((unsigned char *) p, "FREE")) return;
+
+ SLFREE (p - Chunk);
+}
+
+char *SLdebug_malloc (unsigned long n)
+{
+ char *p;
+
+ if ((p = (char *) SLMALLOC (n + 2 * Chunk)) == NULL) return NULL;
+
+ fixup ((unsigned char *) p, n, "MALLOC");
+ return p + Chunk;
+}
+
+char *SLdebug_realloc (char *p, unsigned long n)
+{
+ if (-1 == check_memory ((unsigned char *) p, "REALLOC")) return NULL;
+ if ((p = (char *) SLREALLOC (p - Chunk, n + 2 * Chunk)) == NULL) return NULL;
+ fixup ((unsigned char *) p, n, "REALLOC");
+ return p + Chunk;
+}
+
+char *SLdebug_calloc (unsigned long n, unsigned long size)
+{
+ char *p;
+ int m;
+
+ /* This is tough -- hope this is a good assumption!! */
+ if (size >= Chunk) m = 1; else m = Chunk;
+
+ if ((p = (char *) SLCALLOC (n + m + m, size)) == NULL) return NULL;
+ fixup ((unsigned char *) p, size * n, "CALLOC");
+ return p + Chunk;
+}
+
diff --git a/mdk-stage1/slang/slmath.c b/mdk-stage1/slang/slmath.c
new file mode 100644
index 000000000..1d61e14d3
--- /dev/null
+++ b/mdk-stage1/slang/slmath.c
@@ -0,0 +1,565 @@
+/* sin, cos, etc, for S-Lang */
+/* Copyright (c) 1992, 1999, 2001 John E. Davis
+ * This file is part of the S-Lang library.
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Perl Artistic License.
+ */
+
+#include "slinclud.h"
+
+#include <math.h>
+
+#include "slang.h"
+#include "_slang.h"
+
+#ifdef PI
+# undef PI
+#endif
+#define PI 3.14159265358979323846264338327950288
+
+#if defined(__unix__)
+#include <signal.h>
+#include <errno.h>
+
+#define SIGNAL SLsignal
+
+static void math_floating_point_exception (int sig)
+{
+ sig = errno;
+ if (SLang_Error == 0) SLang_Error = SL_FLOATING_EXCEPTION;
+ (void) SIGNAL (SIGFPE, math_floating_point_exception);
+ errno = sig;
+}
+#endif
+
+double SLmath_hypot (double x, double y)
+{
+ double fr, fi, ratio;
+
+ fr = fabs(x);
+ fi = fabs(y);
+
+ if (fr > fi)
+ {
+ ratio = y / x;
+ x = fr * sqrt (1.0 + ratio * ratio);
+ }
+ else if (fi == 0.0) x = 0.0;
+ else
+ {
+ ratio = x / y;
+ x = fi * sqrt (1.0 + ratio * ratio);
+ }
+
+ return x;
+}
+
+/* usage here is a1 a2 ... an n x ==> a1x^n + a2 x ^(n - 1) + ... + an */
+static double math_poly (void)
+{
+ int n;
+ double xn = 1.0, sum = 0.0;
+ double an, x;
+
+ if ((SLang_pop_double(&x, NULL, NULL))
+ || (SLang_pop_integer(&n))) return(0.0);
+
+ while (n-- > 0)
+ {
+ if (SLang_pop_double(&an, NULL, NULL)) break;
+ sum += an * xn;
+ xn = xn * x;
+ }
+ return (double) sum;
+}
+
+static int double_math_op_result (int op, unsigned char a, unsigned char *b)
+{
+ (void) op;
+
+ if (a != SLANG_FLOAT_TYPE)
+ *b = SLANG_DOUBLE_TYPE;
+ else
+ *b = a;
+
+ return 1;
+}
+
+#ifdef HAVE_ASINH
+# define ASINH_FUN asinh
+#else
+# define ASINH_FUN my_asinh
+static double my_asinh (double x)
+{
+ return log (x + sqrt (x*x + 1));
+}
+#endif
+#ifdef HAVE_ACOSH
+# define ACOSH_FUN acosh
+#else
+# define ACOSH_FUN my_acosh
+static double my_acosh (double x)
+{
+ return log (x + sqrt(x*x - 1)); /* x >= 1 */
+}
+#endif
+#ifdef HAVE_ATANH
+# define ATANH_FUN atanh
+#else
+# define ATANH_FUN my_atanh
+static double my_atanh (double x)
+{
+ return 0.5 * log ((1.0 + x)/(1.0 - x)); /* 0 <= x^2 < 1 */
+}
+#endif
+
+static int double_math_op (int op,
+ unsigned char type, VOID_STAR ap, unsigned int na,
+ VOID_STAR bp)
+{
+ double *a, *b;
+ unsigned int i;
+ double (*fun) (double);
+
+ (void) type;
+ a = (double *) ap;
+ b = (double *) bp;
+
+ switch (op)
+ {
+ default:
+ return 0;
+
+ case SLMATH_SINH:
+ fun = sinh;
+ break;
+ case SLMATH_COSH:
+ fun = cosh;
+ break;
+ case SLMATH_TANH:
+ fun = tanh;
+ break;
+ case SLMATH_TAN:
+ fun = tan;
+ break;
+ case SLMATH_ASIN:
+ fun = asin;
+ break;
+ case SLMATH_ACOS:
+ fun = acos;
+ break;
+ case SLMATH_ATAN:
+ fun = atan;
+ break;
+ case SLMATH_EXP:
+ fun = exp;
+ break;
+ case SLMATH_LOG:
+ fun = log;
+ break;
+ case SLMATH_LOG10:
+ fun = log10;
+ break;
+ case SLMATH_SQRT:
+ fun = sqrt;
+ break;
+ case SLMATH_SIN:
+ fun = sin;
+ break;
+ case SLMATH_COS:
+ fun = cos;
+ break;
+
+ case SLMATH_ASINH:
+ fun = ASINH_FUN;
+ break;
+ case SLMATH_ATANH:
+ fun = ATANH_FUN;
+ break;
+ case SLMATH_ACOSH:
+ fun = ACOSH_FUN;
+ break;
+
+ case SLMATH_CONJ:
+ case SLMATH_REAL:
+ for (i = 0; i < na; i++)
+ b[i] = a[i];
+ return 1;
+ case SLMATH_IMAG:
+ for (i = 0; i < na; i++)
+ b[i] = 0.0;
+ return 1;
+ }
+
+ for (i = 0; i < na; i++)
+ b[i] = (*fun) (a[i]);
+
+ return 1;
+}
+
+static int float_math_op (int op,
+ unsigned char type, VOID_STAR ap, unsigned int na,
+ VOID_STAR bp)
+{
+ float *a, *b;
+ unsigned int i;
+ double (*fun) (double);
+
+ (void) type;
+ a = (float *) ap;
+ b = (float *) bp;
+
+
+ switch (op)
+ {
+ default:
+ return 0;
+
+ case SLMATH_SINH:
+ fun = sinh;
+ break;
+ case SLMATH_COSH:
+ fun = cosh;
+ break;
+ case SLMATH_TANH:
+ fun = tanh;
+ break;
+ case SLMATH_TAN:
+ fun = tan;
+ break;
+ case SLMATH_ASIN:
+ fun = asin;
+ break;
+ case SLMATH_ACOS:
+ fun = acos;
+ break;
+ case SLMATH_ATAN:
+ fun = atan;
+ break;
+ case SLMATH_EXP:
+ fun = exp;
+ break;
+ case SLMATH_LOG:
+ fun = log;
+ break;
+ case SLMATH_LOG10:
+ fun = log10;
+ break;
+ case SLMATH_SQRT:
+ fun = sqrt;
+ break;
+ case SLMATH_SIN:
+ fun = sin;
+ break;
+ case SLMATH_COS:
+ fun = cos;
+ break;
+
+ case SLMATH_ASINH:
+ fun = ASINH_FUN;
+ break;
+ case SLMATH_ATANH:
+ fun = ATANH_FUN;
+ break;
+ case SLMATH_ACOSH:
+ fun = ACOSH_FUN;
+ break;
+
+ case SLMATH_CONJ:
+ case SLMATH_REAL:
+ for (i = 0; i < na; i++)
+ b[i] = a[i];
+ return 1;
+ case SLMATH_IMAG:
+ for (i = 0; i < na; i++)
+ b[i] = 0.0;
+ return 1;
+ }
+
+ for (i = 0; i < na; i++)
+ b[i] = (float) (*fun) ((double) a[i]);
+
+ return 1;
+}
+
+static int generic_math_op (int op,
+ unsigned char type, VOID_STAR ap, unsigned int na,
+ VOID_STAR bp)
+{
+ double *b;
+ unsigned int i;
+ SLang_To_Double_Fun_Type to_double;
+ double (*fun) (double);
+ unsigned int da;
+ char *a;
+
+ if (NULL == (to_double = SLarith_get_to_double_fun (type, &da)))
+ return 0;
+
+ b = (double *) bp;
+ a = (char *) ap;
+
+ switch (op)
+ {
+ default:
+ return 0;
+
+ case SLMATH_SINH:
+ fun = sinh;
+ break;
+ case SLMATH_COSH:
+ fun = cosh;
+ break;
+ case SLMATH_TANH:
+ fun = tanh;
+ break;
+ case SLMATH_TAN:
+ fun = tan;
+ break;
+ case SLMATH_ASIN:
+ fun = asin;
+ break;
+ case SLMATH_ACOS:
+ fun = acos;
+ break;
+ case SLMATH_ATAN:
+ fun = atan;
+ break;
+ case SLMATH_EXP:
+ fun = exp;
+ break;
+ case SLMATH_LOG:
+ fun = log;
+ break;
+ case SLMATH_LOG10:
+ fun = log10;
+ break;
+ case SLMATH_SQRT:
+ fun = sqrt;
+ break;
+ case SLMATH_SIN:
+ fun = sin;
+ break;
+ case SLMATH_COS:
+ fun = cos;
+ break;
+
+ case SLMATH_ASINH:
+ fun = ASINH_FUN;
+ break;
+ case SLMATH_ATANH:
+ fun = ATANH_FUN;
+ break;
+ case SLMATH_ACOSH:
+ fun = ACOSH_FUN;
+ break;
+
+
+ case SLMATH_CONJ:
+ case SLMATH_REAL:
+ for (i = 0; i < na; i++)
+ {
+ b[i] = to_double((VOID_STAR) a);
+ a += da;
+ }
+ return 1;
+
+ case SLMATH_IMAG:
+ for (i = 0; i < na; i++)
+ b[i] = 0.0;
+ return 1;
+ }
+
+ for (i = 0; i < na; i++)
+ {
+ b[i] = (*fun) (to_double ((VOID_STAR) a));
+ a += da;
+ }
+
+ return 1;
+}
+
+#if SLANG_HAS_COMPLEX
+static int complex_math_op_result (int op, unsigned char a, unsigned char *b)
+{
+ (void) a;
+ switch (op)
+ {
+ default:
+ *b = SLANG_COMPLEX_TYPE;
+ break;
+
+ case SLMATH_REAL:
+ case SLMATH_IMAG:
+ *b = SLANG_DOUBLE_TYPE;
+ break;
+ }
+ return 1;
+}
+
+static int complex_math_op (int op,
+ unsigned char type, VOID_STAR ap, unsigned int na,
+ VOID_STAR bp)
+{
+ double *a, *b;
+ unsigned int i;
+ unsigned int na2 = na * 2;
+ double *(*fun) (double *, double *);
+
+ (void) type;
+ a = (double *) ap;
+ b = (double *) bp;
+
+ switch (op)
+ {
+ default:
+ return 0;
+
+ case SLMATH_REAL:
+ for (i = 0; i < na; i++)
+ b[i] = a[2 * i];
+ return 1;
+
+ case SLMATH_IMAG:
+ for (i = 0; i < na; i++)
+ b[i] = a[2 * i + 1];
+ return 1;
+
+ case SLMATH_CONJ:
+ for (i = 0; i < na2; i += 2)
+ {
+ b[i] = a[i];
+ b[i+1] = -a[i+1];
+ }
+ return 1;
+
+ case SLMATH_ATANH:
+ fun = SLcomplex_atanh;
+ break;
+ case SLMATH_ACOSH:
+ fun = SLcomplex_acosh;
+ break;
+ case SLMATH_ASINH:
+ fun = SLcomplex_asinh;
+ break;
+ case SLMATH_EXP:
+ fun = SLcomplex_exp;
+ break;
+ case SLMATH_LOG:
+ fun = SLcomplex_log;
+ break;
+ case SLMATH_LOG10:
+ fun = SLcomplex_log10;
+ break;
+ case SLMATH_SQRT:
+ fun = SLcomplex_sqrt;
+ break;
+ case SLMATH_SIN:
+ fun = SLcomplex_sin;
+ break;
+ case SLMATH_COS:
+ fun = SLcomplex_cos;
+ break;
+ case SLMATH_SINH:
+ fun = SLcomplex_sinh;
+ break;
+ case SLMATH_COSH:
+ fun = SLcomplex_cosh;
+ break;
+ case SLMATH_TANH:
+ fun = SLcomplex_tanh;
+ break;
+ case SLMATH_TAN:
+ fun = SLcomplex_tan;
+ break;
+ case SLMATH_ASIN:
+ fun = SLcomplex_asin;
+ break;
+ case SLMATH_ACOS:
+ fun = SLcomplex_acos;
+ break;
+ case SLMATH_ATAN:
+ fun = SLcomplex_atan;
+ break;
+ }
+
+ for (i = 0; i < na2; i += 2)
+ (void) (*fun) (b + i, a + i);
+
+ return 1;
+}
+#endif
+
+static SLang_DConstant_Type DConst_Table [] =
+{
+ MAKE_DCONSTANT("E", 2.718281828459045),
+ MAKE_DCONSTANT("PI", 3.14159265358979323846264338327950288),
+ SLANG_END_DCONST_TABLE
+};
+
+static SLang_Math_Unary_Type SLmath_Table [] =
+{
+ MAKE_MATH_UNARY("sinh", SLMATH_SINH),
+ MAKE_MATH_UNARY("asinh", SLMATH_ASINH),
+ MAKE_MATH_UNARY("cosh", SLMATH_COSH),
+ MAKE_MATH_UNARY("acosh", SLMATH_ACOSH),
+ MAKE_MATH_UNARY("tanh", SLMATH_TANH),
+ MAKE_MATH_UNARY("atanh", SLMATH_ATANH),
+ MAKE_MATH_UNARY("sin", SLMATH_SIN),
+ MAKE_MATH_UNARY("cos", SLMATH_COS),
+ MAKE_MATH_UNARY("tan", SLMATH_TAN),
+ MAKE_MATH_UNARY("atan", SLMATH_ATAN),
+ MAKE_MATH_UNARY("acos", SLMATH_ACOS),
+ MAKE_MATH_UNARY("asin", SLMATH_ASIN),
+ MAKE_MATH_UNARY("exp", SLMATH_EXP),
+ MAKE_MATH_UNARY("log", SLMATH_LOG),
+ MAKE_MATH_UNARY("sqrt", SLMATH_SQRT),
+ MAKE_MATH_UNARY("log10", SLMATH_LOG10),
+#if SLANG_HAS_COMPLEX
+ MAKE_MATH_UNARY("Real", SLMATH_REAL),
+ MAKE_MATH_UNARY("Imag", SLMATH_IMAG),
+ MAKE_MATH_UNARY("Conj", SLMATH_CONJ),
+#endif
+ SLANG_END_MATH_UNARY_TABLE
+};
+
+static SLang_Intrin_Fun_Type SLang_Math_Table [] =
+{
+ MAKE_INTRINSIC_0("polynom", math_poly, SLANG_DOUBLE_TYPE),
+ SLANG_END_INTRIN_FUN_TABLE
+};
+
+int SLang_init_slmath (void)
+{
+ unsigned char *int_types;
+
+#if defined(__unix__)
+ (void) SIGNAL (SIGFPE, math_floating_point_exception);
+#endif
+
+ int_types = _SLarith_Arith_Types;
+
+ while (*int_types != SLANG_FLOAT_TYPE)
+ {
+ if (-1 == SLclass_add_math_op (*int_types, generic_math_op, double_math_op_result))
+ return -1;
+ int_types++;
+ }
+
+ if ((-1 == SLclass_add_math_op (SLANG_FLOAT_TYPE, float_math_op, double_math_op_result))
+ || (-1 == SLclass_add_math_op (SLANG_DOUBLE_TYPE, double_math_op, double_math_op_result))
+#if SLANG_HAS_COMPLEX
+ || (-1 == SLclass_add_math_op (SLANG_COMPLEX_TYPE, complex_math_op, complex_math_op_result))
+#endif
+ )
+ return -1;
+
+ if ((-1 == SLadd_math_unary_table (SLmath_Table, "__SLMATH__"))
+ || (-1 == SLadd_intrin_fun_table (SLang_Math_Table, NULL))
+ || (-1 == SLadd_dconstant_table (DConst_Table, NULL)))
+ return -1;
+
+ return 0;
+}
+
diff --git a/mdk-stage1/slang/slmemchr.c b/mdk-stage1/slang/slmemchr.c
new file mode 100644
index 000000000..1417bc549
--- /dev/null
+++ b/mdk-stage1/slang/slmemchr.c
@@ -0,0 +1,47 @@
+/* Copyright (c) 1992, 1999, 2001 John E. Davis
+ * This file is part of the S-Lang library.
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Perl Artistic License.
+ */
+
+/* These routines are fast memcpy, memset routines. When available, I
+ use system rouines. For msdos, I use inline assembly. */
+
+/* The current versions only work in the forward direction only!! */
+
+#include "slinclud.h"
+
+#include "slang.h"
+#include "_slang.h"
+
+char *SLmemchr(register char *p, register char c, register int n)
+{
+ int n2;
+ register char *pmax;
+
+ pmax = p + (n - 32);
+
+ while (p <= pmax)
+ {
+ if ((*p == c) || (*++p == c) || (*++p == c) || (*++p == c)
+ || (*++p == c) || (*++p == c) || (*++p == c) || (*++p == c)
+ || (*++p == c) || (*++p == c) || (*++p == c) || (*++p == c)
+ || (*++p == c) || (*++p == c) || (*++p == c) || (*++p == c)
+ || (*++p == c) || (*++p == c) || (*++p == c) || (*++p == c)
+ || (*++p == c) || (*++p == c) || (*++p == c) || (*++p == c)
+ || (*++p == c) || (*++p == c) || (*++p == c) || (*++p == c)
+ || (*++p == c) || (*++p == c) || (*++p == c) || (*++p == c))
+ return p;
+ p++;
+ }
+
+ n2 = n % 32;
+
+ while (n2--)
+ {
+ if (*p == c) return p;
+ p++;
+ }
+ return(NULL);
+}
diff --git a/mdk-stage1/slang/slmemcmp.c b/mdk-stage1/slang/slmemcmp.c
new file mode 100644
index 000000000..c5ed50095
--- /dev/null
+++ b/mdk-stage1/slang/slmemcmp.c
@@ -0,0 +1,76 @@
+/* Copyright (c) 1992, 1999, 2001 John E. Davis
+ * This file is part of the S-Lang library.
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Perl Artistic License.
+ */
+
+/* These routines are fast memcpy, memset routines. When available, I
+ use system rouines. For msdos, I use inline assembly. */
+
+/* The current versions only work in the forward direction only!! */
+
+#include "slinclud.h"
+
+#include "slang.h"
+#include "_slang.h"
+
+/* This is an UNSIGNED comparison designed for systems that either do not have
+* this function or performed a signed comparison (SunOS)
+*/
+int SLmemcmp(register char *s1, register char *s2, int n)
+{
+ register int cmp;
+ register char *s1max;
+
+ s1max = s1 + (n - 32);
+
+ while (s1 <= s1max)
+ {
+ if (*s1 != *s2) return ((unsigned char) *s1 - (unsigned char) *s2);
+ if (*(s1 + 1) != *(s2 + 1)) return ((unsigned char) *(s1 + 1) - (unsigned char) *(s2 + 1));
+ if (*(s1 + 2) != *(s2 + 2)) return ((unsigned char) *(s1 + 2) - (unsigned char) *(s2 + 2));
+ if (*(s1 + 3) != *(s2 + 3)) return ((unsigned char) *(s1 + 3) - (unsigned char) *(s2 + 3));
+ if (*(s1 + 4) != *(s2 + 4)) return ((unsigned char) *(s1 + 4) - (unsigned char) *(s2 + 4));
+ if (*(s1 + 5) != *(s2 + 5)) return ((unsigned char) *(s1 + 5) - (unsigned char) *(s2 + 5));
+ if (*(s1 + 6) != *(s2 + 6)) return ((unsigned char) *(s1 + 6) - (unsigned char) *(s2 + 6));
+ if (*(s1 + 7) != *(s2 + 7)) return ((unsigned char) *(s1 + 7) - (unsigned char) *(s2 + 7));
+ if (*(s1 + 8) != *(s2 + 8)) return ((unsigned char) *(s1 + 8) - (unsigned char) *(s2 + 8));
+ if (*(s1 + 9) != *(s2 + 9)) return ((unsigned char) *(s1 + 9) - (unsigned char) *(s2 + 9));
+ if (*(s1 + 10) != *(s2 + 10)) return ((unsigned char) *(s1 + 10) - (unsigned char) *(s2 + 10));
+ if (*(s1 + 11) != *(s2 + 11)) return ((unsigned char) *(s1 + 11) - (unsigned char) *(s2 + 11));
+ if (*(s1 + 12) != *(s2 + 12)) return ((unsigned char) *(s1 + 12) - (unsigned char) *(s2 + 12));
+ if (*(s1 + 13) != *(s2 + 13)) return ((unsigned char) *(s1 + 13) - (unsigned char) *(s2 + 13));
+ if (*(s1 + 14) != *(s2 + 14)) return ((unsigned char) *(s1 + 14) - (unsigned char) *(s2 + 14));
+ if (*(s1 + 15) != *(s2 + 15)) return ((unsigned char) *(s1 + 15) - (unsigned char) *(s2 + 15));
+ if (*(s1 + 16) != *(s2 + 16)) return ((unsigned char) *(s1 + 16) - (unsigned char) *(s2 + 16));
+ if (*(s1 + 17) != *(s2 + 17)) return ((unsigned char) *(s1 + 17) - (unsigned char) *(s2 + 17));
+ if (*(s1 + 18) != *(s2 + 18)) return ((unsigned char) *(s1 + 18) - (unsigned char) *(s2 + 18));
+ if (*(s1 + 19) != *(s2 + 19)) return ((unsigned char) *(s1 + 19) - (unsigned char) *(s2 + 19));
+ if (*(s1 + 20) != *(s2 + 20)) return ((unsigned char) *(s1 + 20) - (unsigned char) *(s2 + 20));
+ if (*(s1 + 21) != *(s2 + 21)) return ((unsigned char) *(s1 + 21) - (unsigned char) *(s2 + 21));
+ if (*(s1 + 22) != *(s2 + 22)) return ((unsigned char) *(s1 + 22) - (unsigned char) *(s2 + 22));
+ if (*(s1 + 23) != *(s2 + 23)) return ((unsigned char) *(s1 + 23) - (unsigned char) *(s2 + 23));
+ if (*(s1 + 24) != *(s2 + 24)) return ((unsigned char) *(s1 + 24) - (unsigned char) *(s2 + 24));
+ if (*(s1 + 25) != *(s2 + 25)) return ((unsigned char) *(s1 + 25) - (unsigned char) *(s2 + 25));
+ if (*(s1 + 26) != *(s2 + 26)) return ((unsigned char) *(s1 + 26) - (unsigned char) *(s2 + 26));
+ if (*(s1 + 27) != *(s2 + 27)) return ((unsigned char) *(s1 + 27) - (unsigned char) *(s2 + 27));
+ if (*(s1 + 28) != *(s2 + 28)) return ((unsigned char) *(s1 + 28) - (unsigned char) *(s2 + 28));
+ if (*(s1 + 29) != *(s2 + 29)) return ((unsigned char) *(s1 + 29) - (unsigned char) *(s2 + 29));
+ if (*(s1 + 30) != *(s2 + 30)) return ((unsigned char) *(s1 + 30) - (unsigned char) *(s2 + 30));
+ if (*(s1 + 31) != *(s2 + 31)) return ((unsigned char) *(s1 + 31) - (unsigned char) *(s2 + 31));
+ s1 += 32; s2 += 32;
+ }
+
+ s1max = s1 + (n % 32);
+
+ while (s1 < s1max)
+ {
+ cmp = (unsigned char) *s1 - (unsigned char) *s2;
+ if (cmp) return(cmp);
+ s1++;
+ s2++;
+ }
+
+ return(0);
+}
diff --git a/mdk-stage1/slang/slmemcpy.c b/mdk-stage1/slang/slmemcpy.c
new file mode 100644
index 000000000..e8665e4c6
--- /dev/null
+++ b/mdk-stage1/slang/slmemcpy.c
@@ -0,0 +1,49 @@
+/* Copyright (c) 1992, 1999, 2001 John E. Davis
+ * This file is part of the S-Lang library.
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Perl Artistic License.
+ */
+
+/* These routines are fast memcpy, memset routines. When available, I
+ use system rouines. For msdos, I use inline assembly. */
+
+/* The current versions only work in the forward direction only!! */
+
+#include "slinclud.h"
+
+#include "slang.h"
+#include "_slang.h"
+
+char *SLmemcpy(char *s1, char *s2, int n)
+{
+#if defined(__BORLANDC__) && defined(__MSDOS__)
+ asm mov ax, ds
+ asm mov bx, si
+ asm mov dx, di
+ asm mov cx, n
+ asm les di, s1
+ asm lds si, s2
+ asm cld
+ asm rep movsb
+ asm mov ds, ax
+ asm mov si, bx
+ asm mov di, dx
+ return(s1);
+
+#else
+ register char *smax, *s = s1;
+ int n2;
+
+ n2 = n % 4;
+ smax = s + (n - 4);
+ while (s <= smax)
+ {
+ *s = *s2; *(s + 1) = *(s2 + 1); *(s + 2) = *(s2 + 2); *(s + 3) = *(s2 + 3);
+ s += 4;
+ s2 += 4;
+ }
+ while (n2--) *s++ = *s2++;
+ return(s1);
+#endif
+}
diff --git a/mdk-stage1/slang/slmemset.c b/mdk-stage1/slang/slmemset.c
new file mode 100644
index 000000000..3851663c5
--- /dev/null
+++ b/mdk-stage1/slang/slmemset.c
@@ -0,0 +1,39 @@
+/* Copyright (c) 1992, 1999, 2001 John E. Davis
+ * This file is part of the S-Lang library.
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Perl Artistic License.
+ */
+
+/* These routines are fast memcpy, memset routines. When available, I
+ use system rouines. For msdos, I use inline assembly. */
+
+/* The current versions only work in the forward direction only!! */
+
+#include "slinclud.h"
+
+#include "slang.h"
+#include "_slang.h"
+
+void SLmemset(char *p, char space, int n)
+{
+#if defined(__BORLANDC__) && defined(__MSDOS__)
+ asm mov al, space
+ asm mov dx, di
+ asm mov cx, n
+ asm les di, p
+ asm cld
+ asm rep stosb
+ asm mov di, dx
+#else
+ register char *pmax;
+
+ pmax = p + (n - 4);
+ n = n % 4;
+ while (p <= pmax)
+ {
+ *p++ = space; *p++ = space; *p++ = space; *p++= space;
+ }
+ while (n--) *p++ = space;
+#endif
+}
diff --git a/mdk-stage1/slang/slmisc.c b/mdk-stage1/slang/slmisc.c
new file mode 100644
index 000000000..ccc7a9bdf
--- /dev/null
+++ b/mdk-stage1/slang/slmisc.c
@@ -0,0 +1,330 @@
+/* Copyright (c) 1992, 1999, 2001 John E. Davis
+ * This file is part of the S-Lang library.
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Perl Artistic License.
+ */
+#include "slinclud.h"
+
+#include "slang.h"
+#include "_slang.h"
+
+#define DEBUG_MALLOC 0
+
+#if DEBUG_MALLOC
+# define SLREALLOC_FUN SLdebug_realloc
+# define SLMALLOC_FUN SLdebug_malloc
+# define SLFREE_FUN SLdebug_free
+#else
+# define SLREALLOC_FUN SLREALLOC
+# define SLMALLOC_FUN SLMALLOC
+# define SLFREE_FUN SLFREE
+#endif
+
+/* Version information goes here since this file is always needed. */
+int SLang_Version = SLANG_VERSION;
+char *SLang_Version_String = SLANG_VERSION_STRING;
+
+char *SLmake_string(char *str)
+{
+ return SLmake_nstring(str, strlen (str));
+}
+
+char *SLmake_nstring (char *str, unsigned int n)
+{
+ char *ptr;
+
+ if (NULL == (ptr = SLmalloc(n + 1)))
+ {
+ return NULL;
+ }
+ SLMEMCPY (ptr, str, n);
+ ptr[n] = 0;
+ return(ptr);
+}
+
+void SLmake_lut (unsigned char *lut, unsigned char *range, unsigned char reverse)
+{
+ register unsigned char *l = lut, *lmax = lut + 256;
+ int i, r1, r2;
+
+ while (l < lmax) *l++ = reverse;
+ reverse = !reverse;
+
+ r1 = *range++;
+ while (r1)
+ {
+ r2 = *range++;
+ if ((r2 == '-') && (*range != 0))
+ {
+ r2 = *range++;
+ for (i = r1; i <= r2; i++) lut[i] = reverse;
+ r1 = *range++;
+ continue;
+ }
+ lut[r1] = reverse;
+ r1 = r2;
+ }
+}
+
+char *SLmalloc (unsigned int len)
+{
+ char *p;
+
+ p = (char *) SLMALLOC_FUN (len);
+ if (p == NULL)
+ SLang_Error = SL_MALLOC_ERROR;
+
+ return p;
+}
+
+void SLfree (char *p)
+{
+ if (p != NULL) SLFREE_FUN (p);
+}
+
+char *SLrealloc (char *p, unsigned int len)
+{
+ if (len == 0)
+ {
+ SLfree (p);
+ return NULL;
+ }
+
+ if (p == NULL) p = SLmalloc (len);
+ else
+ {
+ p = (char *)SLREALLOC_FUN (p, len);
+ if (p == NULL)
+ SLang_Error = SL_MALLOC_ERROR;
+ }
+ return p;
+}
+
+char *SLcalloc (unsigned int nelems, unsigned int len)
+{
+ char *p;
+
+ len = nelems * len;
+ p = SLmalloc (len);
+ if (p != NULL) SLMEMSET (p, 0, len);
+ return p;
+}
+
+/* p and ch may point to the same buffer */
+char *_SLexpand_escaped_char(char *p, char *ch)
+{
+ int i = 0;
+ int max = 0, num, base = 0;
+ char ch1;
+
+ ch1 = *p++;
+
+ switch (ch1)
+ {
+ default: num = ch1; break;
+ case 'n': num = '\n'; break;
+ case 't': num = '\t'; break;
+ case 'v': num = '\v'; break;
+ case 'b': num = '\b'; break;
+ case 'r': num = '\r'; break;
+ case 'f': num = '\f'; break;
+ case 'E': case 'e': num = 27; break;
+ case 'a': num = 7;
+ break;
+
+ /* octal */
+ case '0': case '1': case '2': case '3':
+ case '4': case '5': case '6': case '7':
+ max = '7';
+ base = 8; i = 2; num = ch1 - '0';
+ break;
+
+ case 'd': /* decimal -- S-Lang extension */
+ base = 10;
+ i = 3;
+ max = '9';
+ num = 0;
+ break;
+
+ case 'x': /* hex */
+ base = 16;
+ max = '9';
+ i = 2;
+ num = 0;
+ break;
+ }
+
+ while (i--)
+ {
+ ch1 = *p;
+
+ if ((ch1 <= max) && (ch1 >= '0'))
+ {
+ num = base * num + (ch1 - '0');
+ }
+ else if (base == 16)
+ {
+ ch1 |= 0x20;
+ if ((ch1 < 'a') || ((ch1 > 'f'))) break;
+ num = base * num + 10 + (ch1 - 'a');
+ }
+ else break;
+ p++;
+ }
+
+ *ch = (char) num;
+ return p;
+}
+
+/* s and t could represent the same space */
+void SLexpand_escaped_string (register char *s, register char *t,
+ register char *tmax)
+{
+ char ch;
+
+ while (t < tmax)
+ {
+ ch = *t++;
+ if (ch == '\\')
+ {
+ t = _SLexpand_escaped_char (t, &ch);
+ }
+ *s++ = ch;
+ }
+ *s = 0;
+}
+
+int SLextract_list_element (char *list, unsigned int nth, char delim,
+ char *elem, unsigned int buflen)
+{
+ char *el, *elmax;
+ char ch;
+
+ while (nth > 0)
+ {
+ while ((0 != (ch = *list)) && (ch != delim))
+ list++;
+
+ if (ch == 0) return -1;
+
+ list++;
+ nth--;
+ }
+
+ el = elem;
+ elmax = el + (buflen - 1);
+
+ while ((0 != (ch = *list)) && (ch != delim) && (el < elmax))
+ *el++ = *list++;
+ *el = 0;
+
+ return 0;
+}
+
+#ifndef HAVE_VSNPRINTF
+int _SLvsnprintf (char *buf, unsigned int buflen, char *fmt, va_list ap)
+{
+#if 1
+ unsigned int len;
+
+ /* On some systems vsprintf returns useless information. So, punt */
+ vsprintf (buf, fmt, ap);
+ len = strlen (buf);
+ if (len >= buflen)
+ {
+ SLang_exit_error ("\
+Your system lacks the vsnprintf system call and vsprintf overflowed a buffer.\n\
+The integrity of this program has been violated.\n");
+ return EOF; /* NOT reached */
+ }
+ return (int)len;
+#else
+ int status;
+
+ status = vsprintf (buf, fmt, ap);
+ if (status >= (int) buflen)
+ {
+ /* If we are lucky, we will get this far. The real solution is to
+ * provide a working version of vsnprintf
+ */
+ SLang_exit_error ("\
+Your system lacks the vsnprintf system call and vsprintf overflowed a buffer.\n\
+The integrity of this program has been violated.\n");
+ return EOF; /* NOT reached */
+ }
+ return status;
+#endif
+}
+#endif
+
+#ifndef HAVE_SNPRINTF
+int _SLsnprintf (char *buf, unsigned int buflen, char *fmt, ...)
+{
+ int status;
+
+ va_list ap;
+
+ va_start (ap, fmt);
+ status = _SLvsnprintf (buf, buflen, fmt, ap);
+ va_end (ap);
+
+ return status;
+}
+#endif
+
+typedef struct _Cleanup_Function_Type
+{
+ struct _Cleanup_Function_Type *next;
+ void (*f)(void);
+}
+Cleanup_Function_Type;
+
+static Cleanup_Function_Type *Cleanup_Function_List;
+
+static void cleanup_slang (void)
+{
+ while (Cleanup_Function_List != NULL)
+ {
+ Cleanup_Function_Type *next = Cleanup_Function_List->next;
+ (*Cleanup_Function_List->f)();
+ SLFREE_FUN ((char *) Cleanup_Function_List);
+ Cleanup_Function_List = next;
+ }
+}
+
+#ifndef HAVE_ATEXIT
+# ifdef HAVE_ON_EXIT
+static void on_exit_cleanup_slang (int arg_unused)
+{
+ (void) arg_unused;
+ cleanup_slang ();
+}
+# endif
+#endif
+
+int SLang_add_cleanup_function (void (*f)(void))
+{
+ Cleanup_Function_Type *l;
+
+ l = (Cleanup_Function_Type *) SLMALLOC_FUN (sizeof (Cleanup_Function_Type));
+ if (l == NULL)
+ return -1;
+
+ l->f = f;
+ l->next = Cleanup_Function_List;
+
+ if (Cleanup_Function_List == NULL)
+ {
+#ifdef HAVE_ATEXIT
+ (void) atexit (cleanup_slang);
+#else
+# ifdef HAVE_ON_EXIT
+ (void) on_exit (on_exit_cleanup_slang, 0);
+# endif
+#endif
+ }
+ Cleanup_Function_List = l;
+ return 0;
+}
+
diff --git a/mdk-stage1/slang/slnspace.c b/mdk-stage1/slang/slnspace.c
new file mode 100644
index 000000000..174ba7c81
--- /dev/null
+++ b/mdk-stage1/slang/slnspace.c
@@ -0,0 +1,242 @@
+/* -*- mode: C; mode: fold; -*- */
+/* slnspace.c --- Name Space implementation */
+/* Copyright (c) 1992, 1999, 2001 John E. Davis
+ * This file is part of the S-Lang library.
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Perl Artistic License.
+ */
+
+#include "slinclud.h"
+
+#include "slang.h"
+#include "_slang.h"
+
+static SLang_NameSpace_Type *Namespace_Tables;
+
+static SLang_NameSpace_Type *find_name_table (char *name)
+{
+ SLang_NameSpace_Type *table_list;
+
+ table_list = Namespace_Tables;
+ while (table_list != NULL)
+ {
+ if (0 == strcmp (table_list->name, name))
+ break;
+ table_list = table_list->next;
+ }
+ return table_list;
+}
+
+SLang_NameSpace_Type *_SLns_find_namespace (char *name)
+{
+ SLang_NameSpace_Type *table_list;
+
+ table_list = Namespace_Tables;
+ while (table_list != NULL)
+ {
+ if ((table_list->namespace_name != NULL)
+ && (0 == strcmp (table_list->namespace_name, name)))
+ break;
+ table_list = table_list->next;
+ }
+ return table_list;
+}
+
+SLang_NameSpace_Type *_SLns_allocate_namespace (char *name, unsigned int size)
+{
+ SLang_NameSpace_Type *table_list;
+ SLang_Name_Type **nt;
+
+ if (NULL != (table_list = find_name_table (name)))
+ return table_list;
+
+ if (NULL == (name = SLang_create_slstring (name)))
+ return NULL;
+
+ if (NULL == (table_list = (SLang_NameSpace_Type *)
+ SLmalloc (sizeof (SLang_NameSpace_Type))))
+ {
+ SLang_free_slstring (name);
+ return NULL;
+ }
+
+ if (NULL == (nt = (SLang_Name_Type **) SLmalloc (sizeof (SLang_Name_Type *) * size)))
+ {
+ SLang_free_slstring (name);
+ SLfree ((char *)table_list);
+ return NULL;
+ }
+
+ memset ((char *)nt, 0, size * sizeof (SLang_Name_Type *));
+ memset ((char *) table_list, 0, sizeof (SLang_NameSpace_Type));
+
+ table_list->name = name;
+ table_list->table = nt;
+ table_list->table_size = size;
+
+ table_list->next = Namespace_Tables;
+ Namespace_Tables = table_list;
+
+ return table_list;
+}
+
+int _SLns_set_namespace_name (SLang_NameSpace_Type *t, char *name)
+{
+ SLang_NameSpace_Type *t1;
+
+ t1 = _SLns_find_namespace (name);
+ if (t1 == NULL)
+ t1 = t;
+
+ if ((t != t1) || (*name == 0))
+ {
+ SLang_verror (SL_INTRINSIC_ERROR, "Namespace \"%s\" already exists",
+ name);
+ return -1;
+ }
+
+ if (NULL == (name = SLang_create_slstring (name)))
+ return -1;
+
+ SLang_free_slstring (t->namespace_name); /* NULL ok */
+ t->namespace_name = name;
+
+ return 0;
+}
+
+SLang_Array_Type *_SLnspace_apropos (SLang_NameSpace_Type *ns, char *pat, unsigned int what)
+{
+ SLang_Array_Type *at;
+ unsigned int table_size;
+ SLang_Name_Type *t, **table;
+ int num_matches;
+ unsigned int i;
+ SLRegexp_Type rexp;
+ unsigned char rbuf[512];
+ unsigned int two;
+
+ at = NULL;
+
+ if ((ns == NULL)
+ || ((table = ns->table) == NULL))
+ return NULL;
+
+ memset ((char *) &rexp, 0, sizeof (SLRegexp_Type));
+ rexp.case_sensitive = 1;
+ rexp.buf = rbuf;
+ rexp.buf_len = sizeof (rbuf);
+ rexp.pat = (unsigned char *)pat;
+
+ if (0 != SLang_regexp_compile (&rexp))
+ {
+ SLang_verror (SL_INVALID_PARM, "Invalid regular expression: %s", pat);
+ return NULL;
+ }
+
+ table_size = ns->table_size;
+
+ two = 2;
+ while (two != 0)
+ {
+ two--;
+
+ num_matches = 0;
+ for (i = 0; i < table_size; i++)
+ {
+ t = table[i];
+ while (t != NULL)
+ {
+ unsigned int flags;
+ char *name = t->name;
+
+ switch (t->name_type)
+ {
+ case SLANG_GVARIABLE:
+ flags = 8;
+ break;
+
+ case SLANG_ICONSTANT:
+ case SLANG_DCONSTANT:
+ case SLANG_RVARIABLE:
+ case SLANG_IVARIABLE:
+ flags = 4;
+ break;
+
+ case SLANG_INTRINSIC:
+ case SLANG_MATH_UNARY:
+ case SLANG_APP_UNARY:
+ flags = 1;
+ break;
+
+ case SLANG_FUNCTION:
+ flags = 2;
+ break;
+
+ default:
+ flags = 0;
+ break;
+ }
+
+ if ((flags & what)
+ && (NULL != SLang_regexp_match ((unsigned char *)name, strlen (name), &rexp)))
+ {
+ if (at != NULL)
+ {
+ if (-1 == SLang_set_array_element (at, &num_matches, (VOID_STAR)&name))
+ goto return_error;
+ }
+ num_matches++;
+ }
+ t = t->next;
+ }
+ }
+
+ if (at == NULL)
+ {
+ at = SLang_create_array (SLANG_STRING_TYPE, 0, NULL, &num_matches, 1);
+ if (at == NULL)
+ goto return_error;
+ }
+ }
+
+ return at;
+
+ return_error:
+ SLang_free_array (at);
+ return NULL;
+}
+
+SLang_NameSpace_Type *SLns_create_namespace (char *namespace_name)
+{
+ SLang_NameSpace_Type *ns;
+ static int num;
+ char name[64];
+
+ if (namespace_name == NULL)
+ namespace_name = "Global";
+
+ ns = _SLns_find_namespace (namespace_name);
+ if (ns != NULL)
+ return ns;
+
+ sprintf (name, " *** internal ns <%d> *** ", num);
+
+ if (NULL == (ns = _SLns_allocate_namespace (name, SLSTATIC_HASH_TABLE_SIZE)))
+ return NULL;
+
+ num++;
+ if (-1 == _SLns_set_namespace_name (ns, namespace_name))
+ {
+ SLns_delete_namespace (ns);
+ return NULL;
+ }
+
+ return ns;
+}
+
+void SLns_delete_namespace (SLang_NameSpace_Type *ns)
+{
+ (void) ns;
+ /* V2.0 */
+}
diff --git a/mdk-stage1/slang/slospath.c b/mdk-stage1/slang/slospath.c
new file mode 100644
index 000000000..644931e81
--- /dev/null
+++ b/mdk-stage1/slang/slospath.c
@@ -0,0 +1,73 @@
+/* Pathname intrinsic functions */
+/* Copyright (c) 1999, 2001 John E. Davis
+ * This file is part of the S-Lang library.
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Perl Artistic License.
+ */
+
+#include "slinclud.h"
+
+#include "slang.h"
+#include "_slang.h"
+
+static void path_concat (char *a, char *b)
+{
+ SLang_push_malloced_string (SLpath_dircat (a,b));
+}
+
+static void path_extname (char *path)
+{
+#ifdef VMS
+ char *p;
+#endif
+
+ path = SLpath_extname (path);
+#ifndef VMS
+ SLang_push_string (path);
+#else
+ p = strchr (path, ';');
+ if (p == NULL)
+ (void)SLang_push_string (p);
+ else
+ (void)SLang_push_malloced_string (SLmake_nstring (path, (unsigned int)(p - path)));
+#endif
+}
+
+static void path_basename (char *path)
+{
+ (void) SLang_push_string (SLpath_basename (path));
+}
+
+static void path_dirname (char *path)
+{
+ (void) SLang_push_malloced_string (SLpath_dirname (path));
+}
+
+static void path_sans_extname (char *path)
+{
+ (void) SLang_push_malloced_string (SLpath_pathname_sans_extname (path));
+}
+
+
+
+static SLang_Intrin_Fun_Type Path_Name_Table [] =
+{
+ MAKE_INTRINSIC_SS("path_concat", path_concat, SLANG_VOID_TYPE),
+ MAKE_INTRINSIC_S("path_extname", path_extname, SLANG_VOID_TYPE),
+ MAKE_INTRINSIC_S("path_dirname", path_dirname, SLANG_VOID_TYPE),
+ MAKE_INTRINSIC_S("path_basename", path_basename, SLANG_VOID_TYPE),
+ MAKE_INTRINSIC_S("path_sans_extname", path_sans_extname, SLANG_VOID_TYPE),
+ MAKE_INTRINSIC_S("path_is_absolute", SLpath_is_absolute_path, SLANG_INT_TYPE),
+ SLANG_END_INTRIN_FUN_TABLE
+};
+
+int SLang_init_ospath (void)
+{
+ if (-1 == SLadd_intrin_fun_table(Path_Name_Table, "__OSPATH__"))
+ return -1;
+
+ return 0;
+}
+
+
diff --git a/mdk-stage1/slang/slpack.c b/mdk-stage1/slang/slpack.c
new file mode 100644
index 000000000..53ef63643
--- /dev/null
+++ b/mdk-stage1/slang/slpack.c
@@ -0,0 +1,785 @@
+/* Pack objects as a binary string */
+/* Copyright (c) 1998, 1999, 2001 John E. Davis
+ * This file is part of the S-Lang library.
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Perl Artistic License.
+ */
+#include "slinclud.h"
+
+#include <ctype.h>
+
+#include "slang.h"
+#include "_slang.h"
+
+#ifndef isdigit
+# define isdigit(c) (((c)>='0')&&((c)<= '9'))
+#endif
+#ifndef isspace
+# define isspace(c) (((c)==' ') || ((c)=='\t') || ((c)=='\n'))
+#endif
+
+/* format description:
+ *
+ * s = string (null padded)
+ * S = string (space padded)
+ * c = signed char
+ * C = unsigned char
+ * h = short
+ * H = unsigned short
+ * i = int
+ * I = unsigned int
+ * l = long
+ * L = unsigned long
+ * j = 16 bit signed integer (short)
+ * J = 16 bit unsigned integer (short)
+ * k = 32 bit signed integer (long)
+ * K = 32 bit unsigned integer (long)
+ * f = float (native format)
+ * F = 32 bit double
+ * d = double (native format)
+ * D = 64 bit double
+ * x = null pad byte
+ * > = big-endian mode
+ * < = little-endian mode
+ * = = native mode
+ */
+
+#define NATIVE_ORDER 0
+#define BIGENDIAN_ORDER 1
+#define LILENDIAN_ORDER 2
+static int Native_Byte_Order = NATIVE_ORDER;
+
+typedef struct
+{
+ char format_type;
+ unsigned char data_type;
+ unsigned int repeat;
+ unsigned int sizeof_type;
+ char pad;
+ int byteorder;
+ int is_scalar;
+}
+Format_Type;
+
+static int get_int_type_for_size (unsigned int size, unsigned char *s, unsigned char *u)
+{
+ if (sizeof (int) == size)
+ {
+ if (s != NULL) *s = SLANG_INT_TYPE;
+ if (u != NULL) *u = SLANG_UINT_TYPE;
+ return 0;
+ }
+
+ if (sizeof (short) == size)
+ {
+ if (s != NULL) *s = SLANG_SHORT_TYPE;
+ if (u != NULL) *u = SLANG_USHORT_TYPE;
+ return 1;
+ }
+
+ if (sizeof (long) == size)
+ {
+ if (s != NULL) *s = SLANG_LONG_TYPE;
+ if (u != NULL) *u = SLANG_ULONG_TYPE;
+ return 1;
+ }
+
+ if (s != NULL) *s = 0;
+ if (u != NULL) *u = 0;
+ SLang_verror (SL_NOT_IMPLEMENTED,
+ "This OS does not support a %u byte int", size);
+ return -1;
+}
+
+static int get_float_type_for_size (unsigned int size, unsigned char *s)
+{
+ if (sizeof (float) == size)
+ {
+ *s = SLANG_FLOAT_TYPE;
+ return 0;
+ }
+
+ if (sizeof (double) == size)
+ {
+ *s = SLANG_DOUBLE_TYPE;
+ return 0;
+ }
+
+ SLang_verror (SL_NOT_IMPLEMENTED,
+ "This OS does not support a %u byte float", size);
+ return -1;
+}
+
+static int parse_a_format (char **format, Format_Type *ft)
+{
+ char *f;
+ char ch;
+ unsigned repeat;
+
+ f = *format;
+
+ while (((ch = *f++) != 0)
+ && isspace (ch))
+ ;
+
+ switch (ch)
+ {
+ default:
+ ft->byteorder = NATIVE_ORDER;
+ break;
+
+ case '=':
+ ft->byteorder = NATIVE_ORDER;
+ ch = *f++;
+ break;
+
+ case '>':
+ ft->byteorder = BIGENDIAN_ORDER;
+ ch = *f++;
+ break;
+
+ case '<':
+ ft->byteorder = LILENDIAN_ORDER;
+ ch = *f++;
+ break;
+ }
+
+ if (ch == 0)
+ {
+ f--;
+ *format = f;
+ return 0;
+ }
+
+ ft->format_type = ch;
+ ft->repeat = 1;
+
+ if (isdigit (*f))
+ {
+ repeat = (unsigned int) (*f - '0');
+ f++;
+
+ while (isdigit (*f))
+ {
+ unsigned int repeat10 = 10 * repeat + (unsigned int)(*f - '0');
+
+ /* Check overflow */
+ if (repeat != repeat10 / 10)
+ {
+ SLang_verror (SL_OVERFLOW,
+ "Repeat count too large in [un]pack format");
+ return -1;
+ }
+ repeat = repeat10;
+ f++;
+ }
+ ft->repeat = repeat;
+ }
+
+ *format = f;
+
+ ft->is_scalar = 1;
+ ft->pad = 0;
+
+ switch (ft->format_type)
+ {
+ default:
+ SLang_verror (SL_NOT_IMPLEMENTED,
+ "[un]pack format character '%c' not supported", ft->format_type);
+ return -1;
+
+ case 'D':
+ ft->sizeof_type = 8;
+ if (-1 == get_float_type_for_size (8, &ft->data_type))
+ return -1;
+ break;
+
+ case 'd':
+ ft->data_type = SLANG_DOUBLE_TYPE;
+ ft->sizeof_type = sizeof (double);
+ break;
+
+ case 'F':
+ ft->sizeof_type = 4;
+ if (-1 == get_float_type_for_size (4, &ft->data_type))
+ return -1;
+ break;
+ case 'f':
+ ft->data_type = SLANG_FLOAT_TYPE;
+ ft->sizeof_type = sizeof (float);
+ break;
+
+ case 'h':
+ ft->data_type = SLANG_SHORT_TYPE;
+ ft->sizeof_type = sizeof (short);
+ break;
+ case 'H':
+ ft->data_type = SLANG_USHORT_TYPE;
+ ft->sizeof_type = sizeof (unsigned short);
+ break;
+ case 'i':
+ ft->data_type = SLANG_INT_TYPE;
+ ft->sizeof_type = sizeof (int);
+ break;
+ case 'I':
+ ft->data_type = SLANG_UINT_TYPE;
+ ft->sizeof_type = sizeof (unsigned int);
+ break;
+ case 'l':
+ ft->data_type = SLANG_LONG_TYPE;
+ ft->sizeof_type = sizeof (long);
+ break;
+ case 'L':
+ ft->data_type = SLANG_ULONG_TYPE;
+ ft->sizeof_type = sizeof (unsigned long);
+ break;
+
+ /* 16 bit ints */
+ case 'j':
+ ft->sizeof_type = 2;
+ if (-1 == get_int_type_for_size (2, &ft->data_type, NULL))
+ return -1;
+ break;
+ case 'J':
+ ft->sizeof_type = 2;
+ if (-1 == get_int_type_for_size (2, NULL, &ft->data_type))
+ return -1;
+ break;
+
+ /* 32 bit ints */
+ case 'k':
+ ft->sizeof_type = 4;
+ if (-1 == get_int_type_for_size (4, &ft->data_type, NULL))
+ return -1;
+ break;
+ case 'K':
+ ft->sizeof_type = 4;
+ if (-1 == get_int_type_for_size (4, NULL, &ft->data_type))
+ return -1;
+ break;
+
+ case 'x':
+ ft->sizeof_type = 1;
+ ft->data_type = 0;
+ break;
+
+ case 'c':
+ ft->sizeof_type = 1;
+ ft->data_type = SLANG_CHAR_TYPE;
+ break;
+
+ case 'C':
+ ft->data_type = SLANG_UCHAR_TYPE;
+ ft->sizeof_type = 1;
+ break;
+
+ case 'S':
+ case 'A':
+ ft->pad = ' ';
+ case 'a':
+ case 's':
+ ft->data_type = SLANG_BSTRING_TYPE;
+ ft->sizeof_type = 1;
+ ft->is_scalar = 0;
+ break;
+ }
+ return 1;
+}
+
+static int compute_size_for_format (char *format, unsigned int *num_bytes)
+{
+ unsigned int size;
+ Format_Type ft;
+ int status;
+
+ *num_bytes = size = 0;
+
+ while (1 == (status = parse_a_format (&format, &ft)))
+ size += ft.repeat * ft.sizeof_type;
+
+ *num_bytes = size;
+ return status;
+}
+
+static void byte_swap64 (unsigned char *ss, unsigned int n) /*{{{*/
+{
+ unsigned char *p, *pmax, ch;
+
+ if (n == 0) return;
+ p = (unsigned char *) ss;
+ pmax = p + 8 * n;
+ while (p < pmax)
+ {
+ ch = *p;
+ *p = *(p + 7);
+ *(p + 7) = ch;
+
+ ch = *(p + 6);
+ *(p + 6) = *(p + 1);
+ *(p + 1) = ch;
+
+ ch = *(p + 5);
+ *(p + 5) = *(p + 2);
+ *(p + 2) = ch;
+
+ ch = *(p + 4);
+ *(p + 4) = *(p + 3);
+ *(p + 3) = ch;
+
+ p += 8;
+ }
+}
+
+/*}}}*/
+static void byte_swap32 (unsigned char *ss, unsigned int n) /*{{{*/
+{
+ unsigned char *p, *pmax, ch;
+
+ p = (unsigned char *) ss;
+ pmax = p + 4 * n;
+ while (p < pmax)
+ {
+ ch = *p;
+ *p = *(p + 3);
+ *(p + 3) = ch;
+
+ ch = *(p + 1);
+ *(p + 1) = *(p + 2);
+ *(p + 2) = ch;
+ p += 4;
+ }
+}
+
+/*}}}*/
+static void byte_swap16 (unsigned char *p, unsigned int nread) /*{{{*/
+{
+ unsigned char *pmax, ch;
+
+ pmax = p + 2 * nread;
+ while (p < pmax)
+ {
+ ch = *p;
+ *p = *(p + 1);
+ *(p + 1) = ch;
+ p += 2;
+ }
+}
+
+/*}}}*/
+
+static int byteswap (int order, unsigned char *b, unsigned int size, unsigned int num)
+{
+ if (Native_Byte_Order == order)
+ return 0;
+
+ switch (size)
+ {
+ case 2:
+ byte_swap16 (b, num);
+ break;
+ case 4:
+ byte_swap32 (b, num);
+ break;
+ case 8:
+ byte_swap64 (b, num);
+ break;
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+static void check_native_byte_order (void)
+{
+ unsigned short x;
+
+ if (Native_Byte_Order != NATIVE_ORDER)
+ return;
+
+ x = 0xFF;
+ if (*(unsigned char *)&x == 0xFF)
+ Native_Byte_Order = LILENDIAN_ORDER;
+ else
+ Native_Byte_Order = BIGENDIAN_ORDER;
+}
+
+static SLang_BString_Type *
+pack_according_to_format (char *format, unsigned int nitems)
+{
+ unsigned int size, num;
+ unsigned char *buf, *b;
+ SLang_BString_Type *bs;
+ Format_Type ft;
+
+ buf = NULL;
+
+ if (-1 == compute_size_for_format (format, &size))
+ goto return_error;
+
+ if (NULL == (buf = (unsigned char *) SLmalloc (size + 1)))
+ goto return_error;
+
+ b = buf;
+
+ while (1 == parse_a_format (&format, &ft))
+ {
+ unsigned char *ptr;
+ unsigned int repeat;
+
+ repeat = ft.repeat;
+ if (ft.data_type == 0)
+ {
+ memset ((char *) b, ft.pad, repeat);
+ b += repeat;
+ continue;
+ }
+
+ if (ft.is_scalar)
+ {
+ unsigned char *bstart;
+ num = repeat;
+
+ bstart = b;
+ while (repeat != 0)
+ {
+ unsigned int nelements;
+ SLang_Array_Type *at;
+
+ if (nitems == 0)
+ {
+ SLang_verror (SL_INVALID_PARM,
+ "Not enough items for pack format");
+ goto return_error;
+ }
+
+ if (-1 == SLang_pop_array_of_type (&at, ft.data_type))
+ goto return_error;
+
+ nelements = at->num_elements;
+ if (repeat < nelements)
+ nelements = repeat;
+ repeat -= nelements;
+
+ nelements = nelements * ft.sizeof_type;
+ memcpy ((char *)b, (char *)at->data, nelements);
+
+ b += nelements;
+ SLang_free_array (at);
+ nitems--;
+ }
+
+ if (ft.byteorder != NATIVE_ORDER)
+ byteswap (ft.byteorder, bstart, ft.sizeof_type, num);
+
+ continue;
+ }
+
+ /* Otherwise we have a string */
+ if (-1 == SLang_pop_bstring (&bs))
+ goto return_error;
+
+ ptr = SLbstring_get_pointer (bs, &num);
+ if (repeat < num) num = repeat;
+ memcpy ((char *)b, (char *)ptr, num);
+ b += num;
+ repeat -= num;
+ memset ((char *)b, ft.pad, repeat);
+ SLbstring_free (bs);
+ b += repeat;
+ nitems--;
+ }
+
+ *b = 0;
+ bs = SLbstring_create_malloced (buf, size, 0);
+ if (bs == NULL)
+ goto return_error;
+
+ SLdo_pop_n (nitems);
+ return bs;
+
+ return_error:
+ SLdo_pop_n (nitems);
+ if (buf != NULL)
+ SLfree ((char *) buf);
+
+ return NULL;
+}
+
+void _SLpack (void)
+{
+ SLang_BString_Type *bs;
+ char *fmt;
+ int nitems;
+
+ check_native_byte_order ();
+
+ nitems = SLang_Num_Function_Args;
+ if (nitems <= 0)
+ {
+ SLang_verror (SL_SYNTAX_ERROR,
+ "pack: not enough arguments");
+ return;
+ }
+
+ if ((-1 == SLreverse_stack (nitems))
+ || (-1 == SLang_pop_slstring (&fmt)))
+ bs = NULL;
+ else
+ {
+ bs = pack_according_to_format (fmt, (unsigned int)nitems - 1);
+ SLang_free_slstring (fmt);
+ }
+
+ SLang_push_bstring (bs);
+ SLbstring_free (bs);
+}
+
+void _SLunpack (char *format, SLang_BString_Type *bs)
+{
+ Format_Type ft;
+ unsigned char *b;
+ unsigned int len;
+ unsigned int num_bytes;
+
+ check_native_byte_order ();
+
+ if (-1 == compute_size_for_format (format, &num_bytes))
+ return;
+
+ b = SLbstring_get_pointer (bs, &len);
+ if (b == NULL)
+ return;
+
+ if (len < num_bytes)
+ {
+ SLang_verror (SL_INVALID_PARM,
+ "unpack format %s is too large for input string",
+ format);
+ return;
+ }
+
+ while (1 == parse_a_format (&format, &ft))
+ {
+ char *str, *s;
+
+ if (ft.repeat == 0)
+ continue;
+
+ if (ft.data_type == 0)
+ { /* skip padding */
+ b += ft.repeat;
+ continue;
+ }
+
+ if (ft.is_scalar)
+ {
+ SLang_Array_Type *at;
+ int dims;
+
+ if (ft.repeat == 1)
+ {
+ SLang_Class_Type *cl;
+
+ cl = _SLclass_get_class (ft.data_type);
+ memcpy ((char *)cl->cl_transfer_buf, (char *)b, ft.sizeof_type);
+ if (ft.byteorder != NATIVE_ORDER)
+ byteswap (ft.byteorder, (unsigned char *)cl->cl_transfer_buf, ft.sizeof_type, 1);
+
+ if (-1 == (cl->cl_apush (ft.data_type, cl->cl_transfer_buf)))
+ return;
+ b += ft.sizeof_type;
+ continue;
+ }
+
+ dims = (int) ft.repeat;
+ at = SLang_create_array (ft.data_type, 0, NULL, &dims, 1);
+ if (at == NULL)
+ return;
+
+ num_bytes = ft.repeat * ft.sizeof_type;
+ memcpy ((char *)at->data, (char *)b, num_bytes);
+ if (ft.byteorder != NATIVE_ORDER)
+ byteswap (ft.byteorder, (unsigned char *)at->data, ft.sizeof_type, ft.repeat);
+
+ if (-1 == SLang_push_array (at, 1))
+ return;
+
+ b += num_bytes;
+ continue;
+ }
+
+ len = ft.repeat;
+ str = SLmalloc (len + 1);
+ if (str == NULL)
+ return;
+
+ memcpy ((char *) str, (char *)b, len);
+ str [len] = 0;
+
+ if (ft.pad == ' ')
+ {
+ unsigned int new_len;
+
+ s = str + len;
+ while (s > str)
+ {
+ s--;
+ if ((*s != ' ') && (*s != 0))
+ {
+ s++;
+ break;
+ }
+ *s = 0;
+ }
+ new_len = (unsigned int) (s - str);
+
+ if (new_len != len)
+ {
+ s = SLrealloc (str, new_len + 1);
+ if (s == NULL)
+ {
+ SLfree (str);
+ return;
+ }
+ str = s;
+ len = new_len;
+ }
+ }
+
+ /* Avoid a bstring if possible */
+ s = SLmemchr (str, 0, len);
+ if (s == NULL)
+ {
+ if (-1 == SLang_push_malloced_string (str))
+ return;
+ }
+ else
+ {
+ SLang_BString_Type *new_bs;
+
+ new_bs = SLbstring_create_malloced ((unsigned char *)str, len, 1);
+ if (new_bs == NULL)
+ return;
+
+ if (-1 == SLang_push_bstring (new_bs))
+ {
+ SLfree (str);
+ return;
+ }
+ SLbstring_free (new_bs);
+ }
+
+ b += ft.repeat;
+ }
+}
+
+unsigned int _SLpack_compute_size (char *format)
+{
+ unsigned int n;
+
+ n = 0;
+ (void) compute_size_for_format (format, &n);
+ return n;
+}
+
+void _SLpack_pad_format (char *format)
+{
+ unsigned int len, max_len;
+ Format_Type ft;
+ char *buf, *b;
+
+ check_native_byte_order ();
+
+ /* Just check the syntax */
+ if (-1 == compute_size_for_format (format, &max_len))
+ return;
+
+ /* This should be sufficient to handle any needed xyy padding characters.
+ * I cannot see how this will be overrun
+ */
+ max_len = 4 * (strlen (format) + 1);
+ if (NULL == (buf = SLmalloc (max_len + 1)))
+ return;
+
+ b = buf;
+ len = 0;
+ while (1 == parse_a_format (&format, &ft))
+ {
+ struct { char a; short b; } s_h;
+ struct { char a; int b; } s_i;
+ struct { char a; long b; } s_l;
+ struct { char a; float b; } s_f;
+ struct { char a; double b; } s_d;
+ unsigned int pad;
+
+ if (ft.repeat == 0)
+ continue;
+
+ if (ft.data_type == 0)
+ { /* pad */
+ sprintf (b, "x%u", ft.repeat);
+ b += strlen (b);
+ len += ft.repeat;
+ continue;
+ }
+
+ switch (ft.data_type)
+ {
+ default:
+ case SLANG_STRING_TYPE:
+ case SLANG_BSTRING_TYPE:
+ case SLANG_CHAR_TYPE:
+ case SLANG_UCHAR_TYPE:
+ pad = 0;
+ break;
+
+ case SLANG_SHORT_TYPE:
+ case SLANG_USHORT_TYPE:
+ pad = ((unsigned int) ((char *)&s_h.b - (char *)&s_h.a));
+ break;
+
+ case SLANG_INT_TYPE:
+ case SLANG_UINT_TYPE:
+ pad = ((unsigned int) ((char *)&s_i.b - (char *)&s_i.a));
+ break;
+
+ case SLANG_LONG_TYPE:
+ case SLANG_ULONG_TYPE:
+ pad = ((unsigned int) ((char *)&s_l.b - (char *)&s_l.a));
+ break;
+
+ case SLANG_FLOAT_TYPE:
+ pad = ((unsigned int) ((char *)&s_f.b - (char *)&s_f.a));
+ break;
+
+ case SLANG_DOUBLE_TYPE:
+ pad = ((unsigned int) ((char *)&s_d.b - (char *)&s_d.a));
+ break;
+ }
+
+ /* Pad to a length that is an integer multiple of pad. */
+ if (pad)
+ pad = pad * ((len + pad - 1)/pad) - len;
+
+ if (pad)
+ {
+ sprintf (b, "x%u", pad);
+ b += strlen (b);
+ len += pad;
+ }
+
+ *b++ = ft.format_type;
+ if (ft.repeat > 1)
+ {
+ sprintf (b, "%u", ft.repeat);
+ b += strlen (b);
+ }
+
+ len += ft.repeat * ft.sizeof_type;
+ }
+ *b = 0;
+
+ (void) SLang_push_malloced_string (buf);
+}
diff --git a/mdk-stage1/slang/slparse.c b/mdk-stage1/slang/slparse.c
new file mode 100644
index 000000000..bc709d1fb
--- /dev/null
+++ b/mdk-stage1/slang/slparse.c
@@ -0,0 +1,1970 @@
+/* Copyright (c) 1998, 1999, 2001 John E. Davis
+ * This file is part of the S-Lang library.
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Perl Artistic License.
+ */
+
+#include "slinclud.h"
+
+#include "slang.h"
+#include "_slang.h"
+
+static SLang_Load_Type *LLT;
+int _SLang_Compile_Line_Num_Info;
+
+static void free_token (_SLang_Token_Type *t)
+{
+ register unsigned int nrefs = t->num_refs;
+
+ if (nrefs == 0)
+ return;
+
+ if (nrefs == 1)
+ {
+ if (t->free_sval_flag)
+ {
+ if (t->type == BSTRING_TOKEN)
+ SLbstring_free (t->v.b_val);
+ else
+ _SLfree_hashed_string (t->v.s_val, strlen (t->v.s_val), t->hash);
+ t->v.s_val = NULL;
+ }
+ }
+
+ t->num_refs = nrefs - 1;
+}
+
+static void init_token (_SLang_Token_Type *t)
+{
+ memset ((char *) t, 0, sizeof (_SLang_Token_Type));
+#if _SLANG_HAS_DEBUG_CODE
+ t->line_number = -1;
+#endif
+}
+
+/* Allow room for one push back of a token. This is necessary for
+ * multiple assignment.
+ */
+static unsigned int Use_Next_Token;
+static _SLang_Token_Type Next_Token;
+#if _SLANG_HAS_DEBUG_CODE
+static int Last_Line_Number = -1;
+#endif
+
+static int unget_token (_SLang_Token_Type *ctok)
+{
+ if (SLang_Error)
+ return -1;
+ if (Use_Next_Token != 0)
+ {
+ _SLparse_error ("unget_token failed", ctok, 0);
+ return -1;
+ }
+
+ Use_Next_Token++;
+ Next_Token = *ctok;
+ init_token (ctok);
+ return 0;
+}
+
+static int get_token (_SLang_Token_Type *ctok)
+{
+ if (ctok->num_refs)
+ free_token (ctok);
+
+ if (Use_Next_Token)
+ {
+ Use_Next_Token--;
+ *ctok = Next_Token;
+ return ctok->type;
+ }
+
+ return _SLget_token (ctok);
+}
+
+static int compile_token (_SLang_Token_Type *t)
+{
+#if _SLANG_HAS_DEBUG_CODE
+ if (_SLang_Compile_Line_Num_Info
+ && (t->line_number != Last_Line_Number)
+ && (t->line_number != -1))
+ {
+ _SLang_Token_Type tok;
+ tok.type = LINE_NUM_TOKEN;
+ tok.v.long_val = Last_Line_Number = t->line_number;
+ (*_SLcompile_ptr) (&tok);
+ }
+#endif
+ (*_SLcompile_ptr) (t);
+ return 0;
+}
+
+typedef struct
+{
+#define USE_PARANOID_MAGIC 0
+#if USE_PARANOID_MAGIC
+ unsigned long magic;
+#endif
+ _SLang_Token_Type *stack;
+ unsigned int len;
+ unsigned int size;
+}
+Token_List_Type;
+
+#define MAX_TOKEN_LISTS 16
+static Token_List_Type Token_List_Stack [MAX_TOKEN_LISTS];
+static unsigned int Token_List_Stack_Depth = 0;
+static Token_List_Type *Token_List = NULL;
+
+static void init_token_list (Token_List_Type *t)
+{
+ t->size = 0;
+ t->len = 0;
+ t->stack = NULL;
+#if USE_PARANOID_MAGIC
+ t->magic = 0xABCDEF12;
+#endif
+}
+
+static void free_token_list (Token_List_Type *t)
+{
+ _SLang_Token_Type *s;
+
+ if (t == NULL)
+ return;
+#if USE_PARANOID_MAGIC
+ if (t->magic != 0xABCDEF12)
+ {
+ SLang_doerror ("Magic error.");
+ return;
+ }
+#endif
+ s = t->stack;
+ if (s != NULL)
+ {
+ _SLang_Token_Type *smax = s + t->len;
+ while (s != smax)
+ {
+ if (s->num_refs) free_token (s);
+ s++;
+ }
+
+ SLfree ((char *) t->stack);
+ }
+
+ memset ((char *) t, 0, sizeof (Token_List_Type));
+}
+
+static Token_List_Type *push_token_list (void)
+{
+ if (Token_List_Stack_Depth == MAX_TOKEN_LISTS)
+ {
+ _SLparse_error ("Token list stack size exceeded", NULL, 0);
+ return NULL;
+ }
+
+ Token_List = Token_List_Stack + Token_List_Stack_Depth;
+ Token_List_Stack_Depth++;
+ init_token_list (Token_List);
+ return Token_List;
+}
+
+static int pop_token_list (int do_free)
+{
+ if (Token_List_Stack_Depth == 0)
+ {
+ if (SLang_Error == 0)
+ _SLparse_error ("Token list stack underflow", NULL, 0);
+ return -1;
+ }
+ Token_List_Stack_Depth--;
+
+ if (do_free) free_token_list (Token_List);
+
+ if (Token_List_Stack_Depth != 0)
+ Token_List = Token_List_Stack + (Token_List_Stack_Depth - 1);
+ else
+ Token_List = NULL;
+
+ return 0;
+}
+
+static int check_token_list_space (Token_List_Type *t, unsigned int delta_size)
+{
+ _SLang_Token_Type *st;
+ unsigned int len;
+#if USE_PARANOID_MAGIC
+ if (t->magic != 0xABCDEF12)
+ {
+ SLang_doerror ("Magic error.");
+ return -1;
+ }
+#endif
+ len = t->len + delta_size;
+ if (len <= t->size) return 0;
+
+ if (delta_size < 4)
+ {
+ delta_size = 4;
+ len = t->len + delta_size;
+ }
+
+ st = (_SLang_Token_Type *) SLrealloc((char *) t->stack,
+ len * sizeof(_SLang_Token_Type));
+ if (st == NULL)
+ {
+ _SLparse_error ("Malloc error", NULL, 0);
+ return -1;
+ }
+
+ memset ((char *) (st + t->len), 0, delta_size);
+
+ t->stack = st;
+ t->size = len;
+ return 0;
+}
+
+static int append_token (_SLang_Token_Type *t)
+{
+ if (-1 == check_token_list_space (Token_List, 1))
+ return -1;
+
+ Token_List->stack [Token_List->len] = *t;
+ Token_List->len += 1;
+ t->num_refs = 0; /* stealing it */
+ return 0;
+}
+
+static int append_token_of_type (unsigned char t)
+{
+ _SLang_Token_Type *tok;
+
+ if (-1 == check_token_list_space (Token_List, 1))
+ return -1;
+
+ /* The memset when the list was created ensures that the other fields
+ * are properly initialized.
+ */
+ tok = Token_List->stack + Token_List->len;
+ init_token (tok);
+ tok->type = t;
+ Token_List->len += 1;
+ return 0;
+}
+
+static _SLang_Token_Type *get_last_token (void)
+{
+ unsigned int len;
+
+ if ((Token_List == NULL)
+ || (0 == (len = Token_List->len)))
+ return NULL;
+
+ len--;
+ return Token_List->stack + len;
+}
+
+/* This function does NOT free the list. */
+static int compile_token_list_with_fun (int dir, Token_List_Type *list,
+ int (*f)(_SLang_Token_Type *))
+{
+ _SLang_Token_Type *t0, *t1;
+
+ if (list == NULL)
+ return -1;
+
+ if (f == NULL)
+ f = compile_token;
+
+ t0 = list->stack;
+ t1 = t0 + list->len;
+
+ if (dir < 0)
+ {
+ /* backwards */
+
+ while ((SLang_Error == 0) && (t1 > t0))
+ {
+ t1--;
+ (*f) (t1);
+ }
+ return 0;
+ }
+
+ /* forward */
+ while ((SLang_Error == 0) && (t0 < t1))
+ {
+ (*f) (t0);
+ t0++;
+ }
+ return 0;
+}
+
+static int compile_token_list (void)
+{
+ if (Token_List == NULL)
+ return -1;
+
+ compile_token_list_with_fun (1, Token_List, NULL);
+ pop_token_list (1);
+ return 0;
+}
+
+/* Take all elements in the list from pos2 to the end and exchange them
+ * with the elements at pos1, e.g.,
+ * ...ABCDEabc ==> ...abcABCDE
+ * where pos1 denotes A and pos2 denotes a.
+ */
+static int token_list_element_exchange (unsigned int pos1, unsigned int pos2)
+{
+ _SLang_Token_Type *s, *s1, *s2;
+ unsigned int len, nloops;
+
+ if (Token_List == NULL)
+ return -1;
+
+ s = Token_List->stack;
+ len = Token_List->len;
+
+ if ((s == NULL) || (len == 0)
+ || (pos2 >= len))
+ return -1;
+
+ /* This may not be the most efficient algorithm but the number to swap
+ * is most-likely going to be small, e.g, 3
+ * The algorithm is to rotate the list. The particular rotation
+ * direction was chosen to make insert_token fast.
+ * It works like:
+ * @ ABCabcde --> BCabcdeA --> CabcdeAB --> abcdefAB
+ * which is optimal for Abcdef sequence produced by function calls.
+ *
+ * Profiling indicates that nloops is almost always 1, whereas the inner
+ * loop can loop many times (e.g., 9 times).
+ */
+
+ s2 = s + (len - 1);
+ s1 = s + pos1;
+ nloops = pos2 - pos1;
+
+ while (nloops)
+ {
+ _SLang_Token_Type save;
+
+ s = s1;
+ save = *s;
+
+ while (s < s2)
+ {
+ *s = *(s + 1);
+ s++;
+ }
+ *s = save;
+
+ nloops--;
+ }
+ return 0;
+}
+
+#if 0
+static int insert_token (_SLang_Token_Type *t, unsigned int pos)
+{
+ if (-1 == append_token (t))
+ return -1;
+
+ return token_list_element_exchange (pos, Token_List->len - 1);
+}
+#endif
+static void compile_token_of_type (unsigned char t)
+{
+ _SLang_Token_Type tok;
+
+#if _SLANG_HAS_DEBUG_CODE
+ tok.line_number = -1;
+#endif
+ tok.type = t;
+ compile_token(&tok);
+}
+
+static void statement (_SLang_Token_Type *);
+static void compound_statement (_SLang_Token_Type *);
+static void expression_with_parenthesis (_SLang_Token_Type *);
+static void handle_semicolon (_SLang_Token_Type *);
+static void statement_list (_SLang_Token_Type *);
+static void variable_list (_SLang_Token_Type *, unsigned char);
+static void struct_declaration (_SLang_Token_Type *);
+static void define_function_args (_SLang_Token_Type *);
+static void typedef_definition (_SLang_Token_Type *);
+static void function_args_expression (_SLang_Token_Type *, int);
+static void expression (_SLang_Token_Type *);
+static void expression_with_commas (_SLang_Token_Type *, int);
+static void simple_expression (_SLang_Token_Type *);
+static void unary_expression (_SLang_Token_Type *);
+static void postfix_expression (_SLang_Token_Type *);
+static int check_for_lvalue (unsigned char, _SLang_Token_Type *);
+/* static void primary_expression (_SLang_Token_Type *); */
+static void block (_SLang_Token_Type *);
+static void inline_array_expression (_SLang_Token_Type *);
+static void array_index_expression (_SLang_Token_Type *);
+static void do_multiple_assignment (_SLang_Token_Type *);
+static void try_multiple_assignment (_SLang_Token_Type *);
+#if 0
+static void not_implemented (char *what)
+{
+ char err [256];
+ sprintf (err, "Expression not implemented: %s", what);
+ _SLparse_error (err, NULL, 0);
+}
+#endif
+static void rpn_parse_line (_SLang_Token_Type *tok)
+{
+ do
+ {
+ /* multiple RPN tokens possible when the file looks like:
+ * . <end of line>
+ * . <end of line>
+ */
+ if (tok->type != RPN_TOKEN)
+ compile_token (tok);
+ free_token (tok);
+ }
+ while (EOF_TOKEN != _SLget_rpn_token (tok));
+}
+
+static int get_identifier_token (_SLang_Token_Type *tok)
+{
+ if (IDENT_TOKEN == get_token (tok))
+ return IDENT_TOKEN;
+
+ _SLparse_error ("Expecting identifier", tok, 0);
+ return tok->type;
+}
+
+static void define_function (_SLang_Token_Type *ctok, unsigned char type)
+{
+ _SLang_Token_Type fname;
+
+ switch (type)
+ {
+ case STATIC_TOKEN:
+ type = DEFINE_STATIC_TOKEN;
+ break;
+
+ case PUBLIC_TOKEN:
+ type = DEFINE_PUBLIC_TOKEN;
+ break;
+
+ case PRIVATE_TOKEN:
+ type = DEFINE_PRIVATE_TOKEN;
+ }
+
+ init_token (&fname);
+ if (IDENT_TOKEN != get_identifier_token (&fname))
+ {
+ free_token (&fname);
+ return;
+ }
+
+ compile_token_of_type(OPAREN_TOKEN);
+ get_token (ctok);
+ define_function_args (ctok);
+ compile_token_of_type(FARG_TOKEN);
+
+ if (ctok->type == OBRACE_TOKEN)
+ compound_statement(ctok);
+
+ else if (ctok->type != SEMICOLON_TOKEN)
+ {
+ _SLparse_error("Expecting {", ctok, 0);
+ free_token (&fname);
+ return;
+ }
+
+ fname.type = type;
+ compile_token (&fname);
+ free_token (&fname);
+}
+
+/* statement:
+ * compound-statement
+ * if ( expression ) statement
+ * if ( expression ) statement else statement
+ * !if ( expression ) statement
+ * loop ( expression ) statement
+ * _for ( expression ) statement
+ * foreach ( expression ) statement
+ * foreach (expression ) using (expression-list) statement
+ * while ( expression ) statement
+ * do statement while (expression) ;
+ * for ( expressionopt ; expressionopt ; expressionopt ) statement
+ * ERROR_BLOCK statement
+ * EXIT_BLOCK statement
+ * USER_BLOCK0 statement
+ * USER_BLOCK1 statement
+ * USER_BLOCK2 statement
+ * USER_BLOCK3 statement
+ * USER_BLOCK4 statement
+ * forever statement
+ * break ;
+ * continue ;
+ * return expressionopt ;
+ * variable variable-list ;
+ * struct struct-decl ;
+ * define identifier function-args ;
+ * define identifier function-args compound-statement
+ * switch ( expression ) statement
+ * rpn-line
+ * at-line
+ * push ( expression )
+ * ( expression ) = expression ;
+ * expression ;
+ * expression :
+ */
+
+/* Note: This function does not return with a new token. It is up to the
+ * calling routine to handle that.
+ */
+static void statement (_SLang_Token_Type *ctok)
+{
+ unsigned char type;
+
+ if (SLang_Error)
+ return;
+
+ LLT->parse_level += 1;
+
+ switch (ctok->type)
+ {
+ case OBRACE_TOKEN:
+ compound_statement (ctok);
+ break;
+
+ case IF_TOKEN:
+ case IFNOT_TOKEN:
+ type = ctok->type;
+ get_token (ctok);
+ expression_with_parenthesis (ctok);
+ block (ctok);
+
+ if (ELSE_TOKEN != get_token (ctok))
+ {
+ compile_token_of_type (type);
+ unget_token (ctok);
+ break;
+ }
+ get_token (ctok);
+ block (ctok);
+ if (type == IF_TOKEN) type = ELSE_TOKEN; else type = NOTELSE_TOKEN;
+ compile_token_of_type (type);
+ break;
+
+ /* case IFNOT_TOKEN: */
+ case LOOP_TOKEN:
+ case _FOR_TOKEN:
+ type = ctok->type;
+ get_token (ctok);
+ expression_with_parenthesis (ctok);
+ block (ctok);
+ compile_token_of_type (type);
+ break;
+
+ case FOREACH_TOKEN:
+ get_token (ctok);
+ expression_with_parenthesis (ctok);
+
+ if (NULL == push_token_list ())
+ break;
+
+ append_token_of_type (ARG_TOKEN);
+ if (ctok->type == USING_TOKEN)
+ {
+ if (OPAREN_TOKEN != get_token (ctok))
+ {
+ _SLparse_error ("Expected 'using ('", ctok, 0);
+ break;
+ }
+ get_token (ctok);
+ function_args_expression (ctok, 0);
+ }
+ append_token_of_type (EARG_TOKEN);
+
+ compile_token_list ();
+
+ block (ctok);
+ compile_token_of_type (FOREACH_TOKEN);
+ break;
+
+ case WHILE_TOKEN:
+ get_token (ctok);
+ compile_token_of_type (OBRACE_TOKEN);
+ expression_with_parenthesis (ctok);
+ compile_token_of_type (CBRACE_TOKEN);
+ block (ctok);
+ compile_token_of_type (WHILE_TOKEN);
+ break;
+
+ case DO_TOKEN:
+ get_token (ctok);
+ block (ctok);
+
+ if (WHILE_TOKEN != get_token (ctok))
+ {
+ _SLparse_error("Expecting while", ctok, 0);
+ break;
+ }
+
+ get_token (ctok);
+
+ compile_token_of_type (OBRACE_TOKEN);
+ expression_with_parenthesis (ctok);
+ compile_token_of_type (CBRACE_TOKEN);
+ compile_token_of_type (DOWHILE_TOKEN);
+ handle_semicolon (ctok);
+ break;
+
+ case FOR_TOKEN:
+
+ /* Look for (exp_opt ; exp_opt ; exp_opt ) */
+
+ if (OPAREN_TOKEN != get_token (ctok))
+ {
+ _SLparse_error("Expecting (.", ctok, 0);
+ break;
+ }
+
+ if (NULL == push_token_list ())
+ break;
+
+ append_token_of_type (OBRACE_TOKEN);
+ if (SEMICOLON_TOKEN != get_token (ctok))
+ {
+ expression (ctok);
+ if (ctok->type != SEMICOLON_TOKEN)
+ {
+ _SLparse_error("Expecting ;", ctok, 0);
+ break;
+ }
+ }
+ append_token_of_type (CBRACE_TOKEN);
+
+ append_token_of_type (OBRACE_TOKEN);
+ if (SEMICOLON_TOKEN != get_token (ctok))
+ {
+ expression (ctok);
+ if (ctok->type != SEMICOLON_TOKEN)
+ {
+ _SLparse_error("Expecting ;", ctok, 0);
+ break;
+ }
+ }
+ append_token_of_type (CBRACE_TOKEN);
+
+ append_token_of_type (OBRACE_TOKEN);
+ if (CPAREN_TOKEN != get_token (ctok))
+ {
+ expression (ctok);
+ if (ctok->type != CPAREN_TOKEN)
+ {
+ _SLparse_error("Expecting ).", ctok, 0);
+ break;
+ }
+ }
+ append_token_of_type (CBRACE_TOKEN);
+
+ compile_token_list ();
+
+ get_token (ctok);
+ block (ctok);
+ compile_token_of_type (FOR_TOKEN);
+ break;
+
+ case ERRBLK_TOKEN:
+ case EXITBLK_TOKEN:
+ case USRBLK0_TOKEN:
+ case USRBLK1_TOKEN:
+ case USRBLK2_TOKEN:
+ case USRBLK3_TOKEN:
+ case USRBLK4_TOKEN:
+ case FOREVER_TOKEN:
+ type = ctok->type;
+ get_token (ctok);
+ block (ctok);
+ compile_token_of_type (type);
+ break;
+
+ case BREAK_TOKEN:
+ case CONT_TOKEN:
+ compile_token_of_type (ctok->type);
+ get_token (ctok);
+ handle_semicolon (ctok);
+ break;
+
+ case RETURN_TOKEN:
+ if (SEMICOLON_TOKEN != get_token (ctok))
+ {
+ if (NULL == push_token_list ())
+ break;
+
+ expression (ctok);
+
+ if (ctok->type != SEMICOLON_TOKEN)
+ {
+ _SLparse_error ("Expecting ;", ctok, 0);
+ break;
+ }
+ compile_token_list ();
+ }
+ compile_token_of_type (RETURN_TOKEN);
+ handle_semicolon (ctok);
+ break;
+
+ case STATIC_TOKEN:
+ case PRIVATE_TOKEN:
+ case PUBLIC_TOKEN:
+ type = ctok->type;
+ get_token (ctok);
+ if (ctok->type == VARIABLE_TOKEN)
+ {
+ get_token (ctok);
+ variable_list (ctok, type);
+ handle_semicolon (ctok);
+ break;
+ }
+ if (ctok->type == DEFINE_TOKEN)
+ {
+ define_function (ctok, type);
+ break;
+ }
+ _SLparse_error ("Expecting 'variable' or 'define'", ctok, 0);
+ break;
+
+ case VARIABLE_TOKEN:
+ get_token (ctok);
+ variable_list (ctok, OBRACKET_TOKEN);
+ handle_semicolon (ctok);
+ break;
+
+ case TYPEDEF_TOKEN:
+ get_token (ctok);
+ if (NULL == push_token_list ())
+ break;
+ typedef_definition (ctok);
+ compile_token_list ();
+
+ handle_semicolon (ctok);
+ break;
+
+ case DEFINE_TOKEN:
+ define_function (ctok, DEFINE_TOKEN);
+ break;
+
+ case SWITCH_TOKEN:
+ get_token (ctok);
+ expression_with_parenthesis (ctok);
+
+ while ((SLang_Error == 0)
+ && (OBRACE_TOKEN == ctok->type))
+ {
+ compile_token_of_type (OBRACE_TOKEN);
+ compound_statement (ctok);
+ compile_token_of_type (CBRACE_TOKEN);
+ get_token (ctok);
+ }
+ compile_token_of_type (SWITCH_TOKEN);
+ unget_token (ctok);
+ break;
+
+ case EOF_TOKEN:
+ break;
+#if 0
+ case PUSH_TOKEN:
+ get_token (ctok);
+ expression_list_with_parenthesis (ctok);
+ handle_semicolon (ctok);
+ break;
+#endif
+
+ case SEMICOLON_TOKEN:
+ handle_semicolon (ctok);
+ break;
+
+ case RPN_TOKEN:
+ if (POUND_TOKEN == get_token (ctok))
+ _SLcompile_byte_compiled ();
+ else if (ctok->type != EOF_TOKEN)
+ rpn_parse_line (ctok);
+ break;
+
+ case OPAREN_TOKEN: /* multiple assignment */
+ try_multiple_assignment (ctok);
+ if (ctok->type == COLON_TOKEN)
+ compile_token_of_type (COLON_TOKEN);
+ else handle_semicolon (ctok);
+ break;
+
+ default:
+
+ if (NULL == push_token_list ())
+ break;
+
+ expression (ctok);
+ compile_token_list ();
+
+ if (ctok->type == COLON_TOKEN)
+ compile_token_of_type (COLON_TOKEN);
+ else handle_semicolon (ctok);
+ break;
+ }
+
+ LLT->parse_level -= 1;
+}
+
+static void block (_SLang_Token_Type *ctok)
+{
+ compile_token_of_type (OBRACE_TOKEN);
+ statement (ctok);
+ compile_token_of_type (CBRACE_TOKEN);
+}
+
+/*
+ * statement-list:
+ * statement
+ * statement-list statement
+ */
+static void statement_list (_SLang_Token_Type *ctok)
+{
+ while ((SLang_Error == 0)
+ && (ctok->type != CBRACE_TOKEN)
+ && (ctok->type != EOF_TOKEN))
+ {
+ statement(ctok);
+ get_token (ctok);
+ }
+}
+
+/* compound-statement:
+ * { statement-list }
+ */
+static void compound_statement (_SLang_Token_Type *ctok)
+{
+ /* ctok->type is OBRACE_TOKEN here */
+ get_token (ctok);
+ statement_list(ctok);
+ if (CBRACE_TOKEN != ctok->type)
+ {
+ _SLparse_error ("Expecting '}'", ctok, 0);
+ return;
+ }
+}
+
+/* This function is only called from statement. */
+static void expression_with_parenthesis (_SLang_Token_Type *ctok)
+{
+ if (ctok->type != OPAREN_TOKEN)
+ {
+ _SLparse_error("Expecting (", ctok, 0);
+ return;
+ }
+
+ if (NULL == push_token_list ())
+ return;
+
+ get_token (ctok);
+ expression (ctok);
+
+ if (ctok->type != CPAREN_TOKEN)
+ _SLparse_error("Expecting )", ctok, 0);
+
+ compile_token_list ();
+
+ get_token (ctok);
+}
+
+static void handle_semicolon (_SLang_Token_Type *ctok)
+{
+ if ((ctok->type == SEMICOLON_TOKEN)
+ || (ctok->type == EOF_TOKEN))
+ return;
+
+ _SLparse_error ("Expecting ;", ctok, 0);
+}
+
+void _SLparse_start (SLang_Load_Type *llt)
+{
+ _SLang_Token_Type ctok;
+ SLang_Load_Type *save_llt;
+ unsigned int save_use_next_token;
+ _SLang_Token_Type save_next_token;
+ Token_List_Type *save_list;
+#if _SLANG_HAS_DEBUG_CODE
+ int save_last_line_number = Last_Line_Number;
+
+ Last_Line_Number = -1;
+#endif
+ save_use_next_token = Use_Next_Token;
+ save_next_token = Next_Token;
+ save_list = Token_List;
+ save_llt = LLT;
+ LLT = llt;
+
+ init_token (&Next_Token);
+ Use_Next_Token = 0;
+ init_token (&ctok);
+ get_token (&ctok);
+
+ llt->parse_level = 0;
+ statement_list (&ctok);
+
+ if ((SLang_Error == 0)
+ && (ctok.type != EOF_TOKEN))
+ _SLparse_error ("Parse ended prematurely", &ctok, 0);
+
+
+ if (SLang_Error)
+ {
+ if (SLang_Error < 0) /* severe error */
+ save_list = NULL;
+
+ while (Token_List != save_list)
+ {
+ if (-1 == pop_token_list (1))
+ break; /* ??? when would this happen? */
+ }
+ }
+
+ free_token (&ctok);
+ LLT = save_llt;
+ if (Use_Next_Token)
+ free_token (&Next_Token);
+ Use_Next_Token = save_use_next_token;
+ Next_Token = save_next_token;
+#if _SLANG_HAS_DEBUG_CODE
+ Last_Line_Number = save_last_line_number;
+#endif
+}
+
+/* variable-list:
+ * variable-decl
+ * variable-decl variable-list
+ *
+ * variable-decl:
+ * identifier
+ * identifier = simple-expression
+ */
+static void variable_list (_SLang_Token_Type *name_token, unsigned char variable_type)
+{
+ int declaring;
+ _SLang_Token_Type tok;
+
+ if (name_token->type != IDENT_TOKEN)
+ {
+ _SLparse_error ("Expecting a variable name", name_token, 0);
+ return;
+ }
+
+ declaring = 0;
+ do
+ {
+ if (declaring == 0)
+ {
+ declaring = 1;
+ compile_token_of_type (variable_type);
+ }
+
+ compile_token (name_token);
+
+ init_token (&tok);
+ if (ASSIGN_TOKEN == get_token (&tok))
+ {
+ compile_token_of_type (CBRACKET_TOKEN);
+ declaring = 0;
+
+ get_token (&tok);
+
+ push_token_list ();
+ simple_expression (&tok);
+ compile_token_list ();
+
+ name_token->type = _SCALAR_ASSIGN_TOKEN;
+ compile_token (name_token);
+ }
+
+ free_token (name_token);
+ *name_token = tok;
+ }
+ while ((name_token->type == COMMA_TOKEN)
+ && (IDENT_TOKEN == get_token (name_token)));
+
+ if (declaring) compile_token_of_type (CBRACKET_TOKEN);
+}
+
+/* struct-declaration:
+ * struct { struct-field-list };
+ *
+ * struct-field-list:
+ * struct-field-name , struct-field-list
+ * struct-field-name
+ *
+ * Generates code: "field-name-1" ... "field-name-N" N STRUCT_TOKEN
+ */
+static void struct_declaration (_SLang_Token_Type *ctok)
+{
+ int n;
+ _SLang_Token_Type num_tok;
+
+ if (ctok->type != OBRACE_TOKEN)
+ {
+ _SLparse_error ("Expecting {", ctok, 0);
+ return;
+ }
+
+ n = 0;
+ while (IDENT_TOKEN == get_token (ctok))
+ {
+ n++;
+ ctok->type = STRING_TOKEN;
+ append_token (ctok);
+ if (COMMA_TOKEN != get_token (ctok))
+ break;
+ }
+
+ if (ctok->type != CBRACE_TOKEN)
+ {
+ _SLparse_error ("Expecting }", ctok, 0);
+ return;
+ }
+ if (n == 0)
+ {
+ _SLparse_error ("struct requires at least 1 field", ctok, 0);
+ return;
+ }
+
+ init_token (&num_tok);
+ num_tok.type = INT_TOKEN;
+ num_tok.v.long_val = n;
+ append_token (&num_tok);
+ append_token_of_type (STRUCT_TOKEN);
+
+ get_token (ctok);
+}
+
+/* struct-declaration:
+ * typedef struct { struct-field-list } Type_Name;
+ *
+ * struct-field-list:
+ * struct-field-name , struct-field-list
+ * struct-field-name
+ *
+ * Generates code: "field-name-1" ... "field-name-N" N STRUCT_TOKEN typedef
+ */
+static void typedef_definition (_SLang_Token_Type *t)
+{
+
+ if (t->type != STRUCT_TOKEN)
+ {
+ _SLparse_error ("Expecting `struct'", t, 0);
+ return;
+ }
+ get_token (t);
+
+ struct_declaration (t);
+ if (t->type != IDENT_TOKEN)
+ {
+ _SLparse_error ("Expecting identifier", t, 0);
+ return;
+ }
+
+ t->type = STRING_TOKEN;
+ append_token (t);
+ append_token_of_type (TYPEDEF_TOKEN);
+
+ get_token (t);
+}
+
+/* function-args:
+ * ( args-dec-opt )
+ *
+ * args-decl-opt:
+ * identifier
+ * args-decl , identifier
+ */
+static void define_function_args (_SLang_Token_Type *ctok)
+{
+ if (CPAREN_TOKEN == get_token (ctok))
+ {
+ get_token (ctok);
+ return;
+ }
+
+ compile_token_of_type(OBRACKET_TOKEN);
+
+ while ((SLang_Error == 0)
+ && (ctok->type == IDENT_TOKEN))
+ {
+ compile_token (ctok);
+ if (COMMA_TOKEN != get_token (ctok))
+ break;
+
+ get_token (ctok);
+ }
+
+ if (CPAREN_TOKEN != ctok->type)
+ {
+ _SLparse_error("Expecting )", ctok, 0);
+ return;
+ }
+ compile_token_of_type(CBRACKET_TOKEN);
+
+ get_token (ctok);
+}
+
+void try_multiple_assignment (_SLang_Token_Type *ctok)
+{
+ /* This is called with ctok->type == OPAREN_TOKEN. We have no idea
+ * what follows this. There are various possibilities such as:
+ * @ () = x;
+ * @ ( expression ) = x;
+ * @ ( expression ) ;
+ * @ ( expression ) OP expression;
+ * @ ( expression ) [expression] = expression;
+ * and only the first two constitute a multiple assignment. The last
+ * two forms create the difficulty.
+ *
+ * Here is the plan. First parse (expression) and then check next token.
+ * If it is an equal operator, then it will be parsed as a multiple
+ * assignment. In fact, that is the easy part.
+ *
+ * The hard part stems from the fact that by parsing (expression), we
+ * have effectly truncated the parse if (expression) is part of a binary
+ * or unary expression. Somehow, the parsing must be resumed. The trick
+ * here is to use a dummy literal that generates no code: NO_OP_LITERAL
+ * Using it, we just call 'expression' and proceed.
+ */
+
+ if (NULL == push_token_list ())
+ return;
+
+ get_token (ctok);
+
+ if (ctok->type != CPAREN_TOKEN)
+ {
+ expression_with_commas (ctok, 1);
+ if (ctok->type != CPAREN_TOKEN)
+ {
+ _SLparse_error ("Expecting )", ctok, 0);
+ return;
+ }
+ }
+
+ switch (get_token (ctok))
+ {
+ case ASSIGN_TOKEN:
+ case PLUSEQS_TOKEN:
+ case MINUSEQS_TOKEN:
+ case TIMESEQS_TOKEN:
+ case DIVEQS_TOKEN:
+ case BOREQS_TOKEN:
+ case BANDEQS_TOKEN:
+ do_multiple_assignment (ctok);
+ pop_token_list (1);
+ break;
+
+ default:
+ unget_token (ctok);
+ ctok->type = NO_OP_LITERAL;
+ expression (ctok);
+ compile_token_list ();
+ break;
+ }
+}
+
+/* Note: expression never gets compiled directly. Rather, it gets
+ * appended to the token list and then compiled by a calling
+ * routine.
+ */
+
+/* expression:
+ * simple_expression
+ * simple-expression , expression
+ * <none>
+ */
+static void expression_with_commas (_SLang_Token_Type *ctok, int save_comma)
+{
+ while (SLang_Error == 0)
+ {
+ if (ctok->type != COMMA_TOKEN)
+ {
+ if (ctok->type == CPAREN_TOKEN)
+ return;
+
+ simple_expression (ctok);
+
+ if (ctok->type != COMMA_TOKEN)
+ break;
+ }
+ if (save_comma) append_token (ctok);
+ get_token (ctok);
+ }
+}
+
+static void expression (_SLang_Token_Type *ctok)
+{
+ expression_with_commas (ctok, 0);
+}
+
+/* priority levels of binary operations */
+static unsigned char Binop_Level[] =
+{
+/* ADD_TOKEN */ 2,
+/* SUB_TOKEN */ 2,
+/* MUL_TOKEN */ 1,
+/* DIV_TOKEN */ 1,
+/* LT_TOKEN */ 4,
+/* LE_TOKEN */ 4,
+/* GT_TOKEN */ 4,
+/* GE_TOKEN */ 4,
+/* EQ_TOKEN */ 5,
+/* NE_TOKEN */ 5,
+/* AND_TOKEN */ 9,
+/* OR_TOKEN */ 10,
+/* MOD_TOKEN */ 1,
+/* BAND_TOKEN */ 6,
+/* SHL_TOKEN */ 3,
+/* SHR_TOKEN */ 3,
+/* BXOR_TOKEN */ 7,
+/* BOR_TOKEN */ 8,
+/* POUND_TOKEN */ 1 /* Matrix Multiplication */
+};
+
+/* % Note: simple-expression groups operators OP1 at same level. The
+ * % actual implementation will not do this.
+ * simple-expression:
+ * unary-expression
+ * binary-expression BINARY-OP unary-expression
+ * andelse xxelse-expression-list
+ * orelse xxelse-expression-list
+ *
+ * xxelse-expression-list:
+ * { expression }
+ * xxelse-expression-list { expression }
+ * binary-expression:
+ * unary-expression
+ * unary-expression BINARY-OP binary-expression
+ */
+static void simple_expression (_SLang_Token_Type *ctok)
+{
+ unsigned char type;
+ unsigned char op_stack [64];
+ unsigned char level_stack [64];
+ unsigned char level;
+ unsigned int op_num;
+
+ switch (ctok->type)
+ {
+ case ANDELSE_TOKEN:
+ case ORELSE_TOKEN:
+ type = ctok->type;
+ if (OBRACE_TOKEN != get_token (ctok))
+ {
+ _SLparse_error ("Expecting '{'", ctok, 0);
+ return;
+ }
+
+ while (ctok->type == OBRACE_TOKEN)
+ {
+ append_token (ctok);
+ get_token (ctok);
+ expression (ctok);
+ if (CBRACE_TOKEN != ctok->type)
+ {
+ _SLparse_error("Expecting }", ctok, 0);
+ return;
+ }
+ append_token (ctok);
+ get_token (ctok);
+ }
+ append_token_of_type (type);
+ return;
+
+ /* avoid unary-expression if possible */
+ case STRING_TOKEN:
+ append_token (ctok);
+ get_token (ctok);
+ break;
+
+ default:
+ unary_expression (ctok);
+ break;
+ }
+
+ if (SEMICOLON_TOKEN == (type = ctok->type))
+ return;
+
+ op_num = 0;
+
+ while ((SLang_Error == 0)
+ && (IS_BINARY_OP(type)))
+ {
+ level = Binop_Level[type - FIRST_BINARY_OP];
+
+ while ((op_num > 0) && (level_stack [op_num - 1] <= level))
+ append_token_of_type (op_stack [--op_num]);
+
+ if (op_num >= sizeof (op_stack) - 1)
+ {
+ _SLparse_error ("Binary op stack overflow", ctok, 0);
+ return;
+ }
+
+ op_stack [op_num] = type;
+ level_stack [op_num] = level;
+ op_num++;
+
+ get_token (ctok);
+ unary_expression (ctok);
+ type = ctok->type;
+ }
+
+ while (op_num > 0)
+ append_token_of_type(op_stack[--op_num]);
+}
+
+/* unary-expression:
+ * postfix-expression
+ * ++ postfix-expression
+ * -- postfix-expression
+ * case unary-expression
+ * OP3 unary-expression
+ * (OP3: + - ~ & not @)
+ *
+ * Note: This grammar permits: case case case WHATEVER
+ */
+static void unary_expression (_SLang_Token_Type *ctok)
+{
+ unsigned char save_unary_ops [16];
+ unsigned int num_unary_ops;
+ unsigned char type;
+ _SLang_Token_Type *last_token;
+
+ num_unary_ops = 0;
+ while (SLang_Error == 0)
+ {
+ type = ctok->type;
+
+ switch (type)
+ {
+ case PLUSPLUS_TOKEN:
+ case MINUSMINUS_TOKEN:
+ get_token (ctok);
+ postfix_expression (ctok);
+ check_for_lvalue (type, NULL);
+ goto out_of_switch;
+
+ case ADD_TOKEN:
+ get_token (ctok); /* skip it-- it's unary here */
+ break;
+
+ case SUB_TOKEN:
+ (void) get_token (ctok);
+ if (IS_INTEGER_TOKEN (ctok->type))
+ {
+ ctok->v.long_val = -ctok->v.long_val;
+ break;
+ }
+
+ if (num_unary_ops == 16)
+ goto stack_overflow_error;
+ save_unary_ops [num_unary_ops++] = CHS_TOKEN;
+ break;
+
+ case DEREF_TOKEN:
+ case BNOT_TOKEN:
+ case NOT_TOKEN:
+ case CASE_TOKEN:
+ if (num_unary_ops == 16)
+ goto stack_overflow_error;
+
+ save_unary_ops [num_unary_ops++] = type;
+ get_token (ctok);
+ break;
+
+ /* Try to avoid ->postfix_expression->primary_expression
+ * subroutine calls.
+ */
+ case STRING_TOKEN:
+ append_token (ctok);
+ get_token (ctok);
+ goto out_of_switch;
+
+ default:
+ postfix_expression (ctok);
+ goto out_of_switch;
+ }
+ }
+
+ out_of_switch:
+ if (num_unary_ops == 0)
+ return;
+
+ if ((DEREF_TOKEN == save_unary_ops[num_unary_ops - 1])
+ && (NULL != (last_token = get_last_token ()))
+ && (IS_ASSIGN_TOKEN(last_token->type)))
+ {
+ /* FIXME: Priority=medium
+ * This needs generalized so that things like @a.y = 1 will work properly.
+ */
+ if ((num_unary_ops != 1)
+ || (last_token->type != _SCALAR_ASSIGN_TOKEN))
+ {
+ SLang_verror (SL_NOT_IMPLEMENTED,
+ "Only derefence assignments to simple variables are possible");
+ return;
+ }
+
+ last_token->type += (_DEREF_ASSIGN_TOKEN - _SCALAR_ASSIGN_TOKEN);
+ return;
+ }
+
+ while (num_unary_ops)
+ {
+ num_unary_ops--;
+ append_token_of_type (save_unary_ops [num_unary_ops]);
+ }
+ return;
+
+ stack_overflow_error:
+ _SLparse_error ("Too many unary operators.", ctok, 0);
+}
+
+static int combine_namespace_tokens (_SLang_Token_Type *a, _SLang_Token_Type *b)
+{
+ char *sa, *sb, *sc;
+ unsigned int lena, lenb;
+ unsigned long hash;
+
+ /* This is somewhat of a hack. Combine the TWO identifier names
+ * (NAMESPACE) and (name) into the form NAMESPACE->name. Then when the
+ * byte compiler compiles the object it will not be found. It will then
+ * check for this hack and make the appropriate namespace lookup.
+ */
+
+ sa = a->v.s_val;
+ sb = b->v.s_val;
+
+ lena = strlen (sa);
+ lenb = strlen (sb);
+
+ sc = SLmalloc (lena + lenb + 3);
+ if (sc == NULL)
+ return -1;
+
+ strcpy (sc, sa);
+ strcpy (sc + lena, "->");
+ strcpy (sc + lena + 2, sb);
+
+ sb = _SLstring_make_hashed_string (sc, lena + lenb + 2, &hash);
+ SLfree (sc);
+ if (sb == NULL)
+ return -1;
+
+ /* I can free this string because no other token should be referencing it.
+ * (num_refs == 1).
+ */
+ _SLfree_hashed_string (sa, lena, a->hash);
+ a->v.s_val = sb;
+ a->hash = hash;
+
+ return 0;
+}
+
+static void append_identifier_token (_SLang_Token_Type *ctok)
+{
+ _SLang_Token_Type *last_token;
+
+ append_token (ctok);
+
+ if (NAMESPACE_TOKEN != get_token (ctok))
+ return;
+
+ if (IDENT_TOKEN != get_token (ctok))
+ {
+ _SLparse_error ("Expecting name-space identifier", ctok, 0);
+ return;
+ }
+
+ last_token = get_last_token ();
+ if (-1 == combine_namespace_tokens (last_token, ctok))
+ return;
+
+ (void) get_token (ctok);
+}
+
+static int get_identifier_expr_token (_SLang_Token_Type *ctok)
+{
+ _SLang_Token_Type next_token;
+
+ if (IDENT_TOKEN != get_identifier_token (ctok))
+ return -1;
+
+ init_token (&next_token);
+ if (NAMESPACE_TOKEN != get_token (&next_token))
+ {
+ unget_token (&next_token);
+ return IDENT_TOKEN;
+ }
+
+ if (IDENT_TOKEN != get_identifier_token (&next_token))
+ {
+ free_token (&next_token);
+ return -1;
+ }
+
+ if (-1 == combine_namespace_tokens (ctok, &next_token))
+ {
+ free_token (&next_token);
+ return -1;
+ }
+ free_token (&next_token);
+ return IDENT_TOKEN;
+}
+
+/* postfix-expression:
+ * primary-expression
+ * postfix-expression [ expression ]
+ * postfix-expression ( function-args-expression )
+ * postfix-expression . identifier
+ * postfix-expression ^ unary-expression
+ * postfix-expression ++
+ * postfix-expression --
+ * postfix-expression = simple-expression
+ * postfix-expression += simple-expression
+ * postfix-expression -= simple-expression
+ *
+ * primary-expression:
+ * literal
+ * identifier-expr
+ * ( expression_opt )
+ * [ inline-array-expression ]
+ * &identifier-expr
+ * struct-definition
+ * __tmp(identifier-expr)
+ *
+ * identifier-expr:
+ * identifier
+ * identifier->identifier
+ */
+static void postfix_expression (_SLang_Token_Type *ctok)
+{
+ unsigned int start_pos, end_pos;
+ unsigned char type;
+
+ if (Token_List == NULL)
+ return;
+
+ start_pos = Token_List->len;
+
+ switch (ctok->type)
+ {
+ case IDENT_TOKEN:
+ append_identifier_token (ctok);
+ break;
+
+ case CHAR_TOKEN:
+ case SHORT_TOKEN:
+ case INT_TOKEN:
+ case LONG_TOKEN:
+ case UCHAR_TOKEN:
+ case USHORT_TOKEN:
+ case UINT_TOKEN:
+ case ULONG_TOKEN:
+ case STRING_TOKEN:
+ case BSTRING_TOKEN:
+#ifdef SLANG_HAS_FLOAT
+ case DOUBLE_TOKEN:
+ case FLOAT_TOKEN:
+#endif
+#ifdef SLANG_HAS_COMPLEX
+ case COMPLEX_TOKEN:
+#endif
+ append_token (ctok);
+ get_token (ctok);
+ break;
+
+ case OPAREN_TOKEN:
+ if (CPAREN_TOKEN != get_token (ctok))
+ {
+ expression (ctok);
+ if (ctok->type != CPAREN_TOKEN)
+ _SLparse_error("Expecting )", ctok, 0);
+ }
+ get_token (ctok);
+ break;
+
+ case BAND_TOKEN:
+ if (IDENT_TOKEN != get_identifier_expr_token (ctok))
+ break;
+
+ ctok->type = _REF_TOKEN;
+ append_token (ctok);
+ get_token (ctok);
+ break;
+
+ case OBRACKET_TOKEN:
+ get_token (ctok);
+ inline_array_expression (ctok);
+ break;
+
+ case NO_OP_LITERAL:
+ /* This token was introduced by try_multiple_assignment. There,
+ * a new token_list was pushed and (expression) was evaluated.
+ * NO_OP_LITERAL represents the result of expression. However,
+ * we need to tweak the start_pos variable to point to the beginning
+ * of the token list to complete the equivalence.
+ */
+ start_pos = 0;
+ get_token (ctok);
+ break;
+
+ case STRUCT_TOKEN:
+ get_token (ctok);
+ struct_declaration (ctok);
+ break;
+
+ case TMP_TOKEN:
+ get_token (ctok);
+ if (ctok->type == OPAREN_TOKEN)
+ {
+ if (IDENT_TOKEN == get_identifier_expr_token (ctok))
+ {
+ ctok->type = TMP_TOKEN;
+ append_token (ctok);
+ get_token (ctok);
+ if (ctok->type == CPAREN_TOKEN)
+ {
+ get_token (ctok);
+ break;
+ }
+ }
+ }
+ _SLparse_error ("Expecting form __tmp(NAME)", ctok, 0);
+ break;
+
+ default:
+ if (IS_INTERNAL_FUNC(ctok->type))
+ {
+ append_token (ctok);
+ get_token (ctok);
+ }
+ else
+ _SLparse_error("Expecting a PRIMARY", ctok, 0);
+ }
+
+ while (SLang_Error == 0)
+ {
+ end_pos = Token_List->len;
+ type = ctok->type;
+ switch (type)
+ {
+ case OBRACKET_TOKEN: /* X[args] ==> [args] X ARRAY */
+ get_token (ctok);
+ append_token_of_type (ARG_TOKEN);
+ if (ctok->type != CBRACKET_TOKEN)
+ array_index_expression (ctok);
+
+ if (ctok->type != CBRACKET_TOKEN)
+ {
+ _SLparse_error ("Expecting ']'", ctok, 0);
+ return;
+ }
+ get_token (ctok);
+ /* append_token_of_type (EARG_TOKEN); -- ARRAY_TOKEN implicitely does this */
+ token_list_element_exchange (start_pos, end_pos);
+ append_token_of_type (ARRAY_TOKEN);
+ break;
+
+ case OPAREN_TOKEN:
+ /* f(args) ==> args f */
+ if (CPAREN_TOKEN != get_token (ctok))
+ {
+ function_args_expression (ctok, 1);
+ token_list_element_exchange (start_pos, end_pos);
+ }
+ else get_token (ctok);
+ break;
+
+ case DOT_TOKEN:
+ /* S.a ==> "a" S DOT
+ * This means that if S is X[b], then X[b].a ==> a b X ARRAY DOT
+ * and f(a).X[b].c ==> "c" b "X" a f . ARRAY .
+ * Also, f(a).X[b] = g(x); ==> x g b "X" a f .
+ */
+ if (IDENT_TOKEN != get_identifier_token (ctok))
+ return;
+
+ ctok->type = DOT_TOKEN;
+ append_token (ctok);
+ get_token (ctok);
+ break;
+
+ case PLUSPLUS_TOKEN:
+ case MINUSMINUS_TOKEN:
+ check_for_lvalue (type, NULL);
+ get_token (ctok);
+ break;
+
+ case ASSIGN_TOKEN:
+ case PLUSEQS_TOKEN:
+ case MINUSEQS_TOKEN:
+ case TIMESEQS_TOKEN:
+ case DIVEQS_TOKEN:
+ case BOREQS_TOKEN:
+ case BANDEQS_TOKEN:
+ check_for_lvalue (type, NULL);
+ get_token (ctok);
+ simple_expression (ctok);
+ token_list_element_exchange (start_pos, end_pos);
+ break;
+
+ case POW_TOKEN:
+ get_token (ctok);
+ unary_expression (ctok);
+ append_token_of_type (POW_TOKEN);
+ break;
+
+ default:
+ return;
+ }
+ }
+}
+
+static void function_args_expression (_SLang_Token_Type *ctok, int handle_num_args)
+{
+ unsigned char last_type, this_type;
+
+ if (handle_num_args) append_token_of_type (ARG_TOKEN);
+
+ last_type = COMMA_TOKEN;
+
+ while (SLang_Error == 0)
+ {
+ this_type = ctok->type;
+
+ switch (this_type)
+ {
+ case COMMA_TOKEN:
+ if (last_type == COMMA_TOKEN)
+ append_token_of_type (_NULL_TOKEN);
+ get_token (ctok);
+ break;
+
+ case CPAREN_TOKEN:
+ if (last_type == COMMA_TOKEN)
+ append_token_of_type (_NULL_TOKEN);
+ if (handle_num_args) append_token_of_type (EARG_TOKEN);
+ get_token (ctok);
+ return;
+
+ default:
+ simple_expression (ctok);
+ if ((ctok->type != COMMA_TOKEN)
+ && (ctok->type != CPAREN_TOKEN))
+ {
+ _SLparse_error ("Expecting ')'", ctok, 0);
+ break;
+ }
+ }
+ last_type = this_type;
+ }
+}
+
+static int check_for_lvalue (unsigned char eqs_type, _SLang_Token_Type *ctok)
+{
+ unsigned char type;
+
+ if ((ctok == NULL)
+ && (NULL == (ctok = get_last_token ())))
+ return -1;
+
+ type = ctok->type;
+
+ eqs_type -= ASSIGN_TOKEN;
+
+ if (type == IDENT_TOKEN)
+ eqs_type += _SCALAR_ASSIGN_TOKEN;
+ else if (type == ARRAY_TOKEN)
+ eqs_type += _ARRAY_ASSIGN_TOKEN;
+ else if (type == DOT_TOKEN)
+ eqs_type += _STRUCT_ASSIGN_TOKEN;
+ else
+ {
+ _SLparse_error ("Expecting LVALUE", ctok, 0);
+ return -1;
+ }
+
+ ctok->type = eqs_type;
+ return 0;
+}
+
+static void array_index_expression (_SLang_Token_Type *ctok)
+{
+ unsigned int num_commas;
+
+ num_commas = 0;
+ while (1)
+ {
+ switch (ctok->type)
+ {
+ case COLON_TOKEN:
+ if (num_commas)
+ _SLparse_error ("Misplaced ':'", ctok, 0);
+ return;
+
+ case TIMES_TOKEN:
+ append_token_of_type (_INLINE_WILDCARD_ARRAY_TOKEN);
+ get_token (ctok);
+ break;
+
+ case COMMA_TOKEN:
+ _SLparse_error ("Misplaced ','", ctok, 0);
+ return;
+
+ default:
+ simple_expression (ctok);
+ }
+
+ if (ctok->type != COMMA_TOKEN)
+ return;
+ num_commas++;
+ get_token (ctok);
+ }
+}
+
+/* inline-array-expression:
+ * array_index_expression
+ * simple_expression : simple_expression
+ * simple_expression : simple_expression : simple_expression
+ */
+static void inline_array_expression (_SLang_Token_Type *ctok)
+{
+ int num_colons = 0;
+
+ append_token_of_type (ARG_TOKEN);
+
+ if (ctok->type == COLON_TOKEN) /* [:...] */
+ append_token_of_type (_NULL_TOKEN);
+ else if (ctok->type != CBRACKET_TOKEN)
+ array_index_expression (ctok);
+
+ if (ctok->type == COLON_TOKEN)
+ {
+ num_colons++;
+ if ((COLON_TOKEN == get_token (ctok))
+ || (ctok->type == CBRACKET_TOKEN))
+ append_token_of_type (_NULL_TOKEN);
+ else
+ simple_expression (ctok);
+
+ if (ctok->type == COLON_TOKEN)
+ {
+ num_colons++;
+ get_token (ctok);
+ simple_expression (ctok);
+ }
+ }
+
+ if (ctok->type != CBRACKET_TOKEN)
+ {
+ _SLparse_error ("Expecting ']'", ctok, 0);
+ return;
+ }
+
+ /* append_token_of_type (EARG_TOKEN); */
+ if (num_colons)
+ append_token_of_type (_INLINE_IMPLICIT_ARRAY_TOKEN);
+ else
+ append_token_of_type (_INLINE_ARRAY_TOKEN);
+ get_token (ctok);
+}
+
+static void do_multiple_assignment (_SLang_Token_Type *ctok)
+{
+ _SLang_Token_Type *s;
+ unsigned int i, k, len;
+ unsigned char assign_type;
+
+ assign_type = ctok->type;
+
+ /* The LHS token list has already been pushed. Here we do the RHS
+ * so push to another token list, process it, then come back to
+ * LHS for assignment.
+ */
+ if (NULL == push_token_list ())
+ return;
+
+ get_token (ctok);
+ expression (ctok);
+ compile_token_list ();
+
+ if (SLang_Error)
+ return;
+
+ /* Finally compile the LHS of the assignment expression
+ * that has been saved.
+ */
+ s = Token_List->stack;
+ len = Token_List->len;
+
+ if (len == 0)
+ {
+ compile_token_of_type (POP_TOKEN);
+ return;
+ }
+
+ while (len > 0)
+ {
+ /* List is of form:
+ * a , b, c d e, f , g , , , h ,
+ * The missing expressions will be replaced by a POP
+ * ,,a
+ */
+
+ /* Start from back looking for a COMMA */
+ k = len - 1;
+ if (s[k].type == COMMA_TOKEN)
+ {
+ compile_token_of_type (POP_TOKEN);
+ len = k;
+ continue;
+ }
+
+ if (-1 == check_for_lvalue (assign_type, s + k))
+ return;
+
+ i = 0;
+ while (1)
+ {
+ if (s[k].type == COMMA_TOKEN)
+ {
+ i = k + 1;
+ break;
+ }
+
+ if (k == 0)
+ break;
+
+ k--;
+ }
+
+ while (i < len)
+ {
+ compile_token (s + i);
+ i++;
+ }
+
+ len = k;
+ }
+
+ if (s[0].type == COMMA_TOKEN)
+ compile_token_of_type (POP_TOKEN);
+}
+
diff --git a/mdk-stage1/slang/slpath.c b/mdk-stage1/slang/slpath.c
new file mode 100644
index 000000000..831bd34df
--- /dev/null
+++ b/mdk-stage1/slang/slpath.c
@@ -0,0 +1,344 @@
+/* Pathname and filename functions */
+/* Copyright (c) 1998, 1999, 2001 John E. Davis
+ * This file is part of the S-Lang library.
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Perl Artistic License.
+ */
+
+#include "slinclud.h"
+
+#ifdef HAVE_IO_H
+# include <io.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <signal.h>
+#include <time.h>
+
+#include <errno.h>
+#include <string.h>
+
+#include "slang.h"
+#include "_slang.h"
+
+/* In this file, all file names are assumed to be specified in the Unix
+ * format, or in the native format.
+ *
+ * Aboout VMS:
+ * VMS pathnames are a mess. In general, they look like
+ * node::device:[dir.dir]file.ext;version
+ * and I do not know of a well-defined Unix representation for them. So,
+ * I am going to punt and encourage users to stick to the native
+ * representation.
+ */
+
+#if defined(IBMPC_SYSTEM)
+# define PATH_SEP '\\'
+# define DRIVE_SPECIFIER ':'
+# define SEARCH_PATH_DELIMITER ';'
+# define THIS_DIR_STRING "."
+#else
+# if defined(VMS)
+# define PATH_SEP ']'
+# define DRIVE_SPECIFIER ':'
+# define SEARCH_PATH_DELIMITER ' '
+# define THIS_DIR_STRING "[]" /* Is this correct?? */
+# else
+# define PATH_SEP '/'
+# define UNIX_PATHNAMES_OK
+# define SEARCH_PATH_DELIMITER ':'
+# define THIS_DIR_STRING "."
+# endif
+#endif
+
+#ifdef UNIX_PATHNAMES_OK
+# define IS_PATH_SEP(x) ((x) == PATH_SEP)
+#else
+# define IS_PATH_SEP(x) (((x) == PATH_SEP) || ((x) == '/'))
+#endif
+
+/* If file is /a/b/c/basename, this function returns a pointer to basename */
+char *SLpath_basename (char *file)
+{
+ char *b;
+
+ if (file == NULL) return NULL;
+ b = file + strlen (file);
+
+ while (b != file)
+ {
+ b--;
+ if (IS_PATH_SEP(*b))
+ return b + 1;
+#ifdef DRIVE_SPECIFIER
+ if (*b == DRIVE_SPECIFIER)
+ return b + 1;
+#endif
+ }
+
+ return b;
+}
+
+/* Returns a malloced string */
+char *SLpath_pathname_sans_extname (char *file)
+{
+ char *b;
+
+ file = SLmake_string (file);
+ if (file == NULL)
+ return NULL;
+
+ b = file + strlen (file);
+
+ while (b != file)
+ {
+ b--;
+ if (*b == '.')
+ {
+ *b = 0;
+ return file;
+ }
+ }
+
+ return file;
+}
+
+/* If path looks like: A/B/C/D/whatever, it returns A/B/C/D as a malloced
+ * string.
+ */
+char *SLpath_dirname (char *file)
+{
+ char *b;
+
+ if (file == NULL) return NULL;
+ b = file + strlen (file);
+
+ while (b != file)
+ {
+ b--;
+ if (IS_PATH_SEP(*b))
+ {
+ if (b == file) b++;
+ break;
+ }
+
+#ifdef DRIVE_SPECIFIER
+ if (*b == DRIVE_SPECIFIER)
+ {
+ b++;
+ break;
+ }
+#endif
+ }
+
+ if (b == file)
+ return SLmake_string (THIS_DIR_STRING);
+
+ return SLmake_nstring (file, (unsigned int) (b - file));
+}
+
+/* Note: VMS filenames also contain version numbers. The caller will have
+ * to deal with that.
+ *
+ * The extension includes the '.'. If no extension is present, "" is returned.
+ */
+char *SLpath_extname (char *file)
+{
+ char *b;
+
+ if (NULL == (file = SLpath_basename (file)))
+ return NULL;
+
+ b = file + strlen (file);
+ while (b != file)
+ {
+ b--;
+ if (*b == '.')
+ return b;
+ }
+
+ if (*b == '.')
+ return b;
+
+ /* Do not return a literal "" */
+ return file + strlen (file);
+}
+
+#ifdef IBMPC_SYSTEM
+static void convert_slashes (char *f)
+{
+ while (*f)
+ {
+ if (*f == '/') *f = PATH_SEP;
+ f++;
+ }
+}
+#endif
+
+int SLpath_is_absolute_path (char *name)
+{
+#ifdef UNIX_PATHNAMES_OK
+ return (*name == '/');
+#else
+ if (IS_PATH_SEP (*name))
+ return 1;
+
+# ifdef DRIVE_SPECIFIER
+ /* Look for a drive specifier */
+ while (*name)
+ {
+ if (*name == DRIVE_SPECIFIER)
+ return 1;
+
+ name++;
+ }
+# endif
+
+ return 0;
+#endif
+}
+
+/* This returns a MALLOCED string */
+char *SLpath_dircat (char *dir, char *name)
+{
+ unsigned int len, dirlen;
+ char *file;
+#ifndef VMS
+ int requires_fixup;
+#endif
+
+ if (name == NULL)
+ name = "";
+
+ if ((dir == NULL) || (SLpath_is_absolute_path (name)))
+ dir = "";
+
+ /* Both VMS and MSDOS have default directories associated with each drive.
+ * That is, the meaning of something like C:X depends upon more than just
+ * the syntax of the string. Since this concept has more power under VMS
+ * it will be honored here. However, I am going to treat C:X as C:\X
+ * under MSDOS.
+ *
+ * Note!!!
+ * VMS has problems of its own regarding path names, so I am simply
+ * going to strcat. Hopefully the VMS RTL is smart enough to deal with
+ * the result.
+ */
+ dirlen = strlen (dir);
+#ifndef VMS
+ requires_fixup = (dirlen && (0 == IS_PATH_SEP(dir[dirlen - 1])));
+#endif
+
+ len = dirlen + strlen (name) + 2;
+ if (NULL == (file = SLmalloc (len)))
+ return NULL;
+
+ strcpy (file, dir);
+
+#ifndef VMS
+ if (requires_fixup)
+ file[dirlen++] = PATH_SEP;
+#endif
+
+ strcpy (file + dirlen, name);
+
+#if defined(IBMPC_SYSTEM)
+ convert_slashes (file);
+#endif
+
+ return file;
+}
+
+int SLpath_file_exists (char *file)
+{
+ struct stat st;
+ int m;
+
+#if defined(__os2__) && !defined(S_IFMT)
+/* IBM VA3 doesn't declare S_IFMT */
+# define S_IFMT (S_IFDIR | S_IFCHR | S_IFREG)
+#endif
+
+#ifdef _S_IFDIR
+# ifndef S_IFDIR
+# define S_IFDIR _S_IFDIR
+# endif
+#endif
+
+#ifndef S_ISDIR
+# ifdef S_IFDIR
+# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
+# else
+# define S_ISDIR(m) 0
+# endif
+#endif
+
+ if (file == NULL)
+ return -1;
+
+ if (stat(file, &st) < 0) return 0;
+ m = st.st_mode;
+
+ if (S_ISDIR(m)) return (2);
+ return 1;
+}
+
+char *SLpath_find_file_in_path (char *path, char *name)
+{
+ unsigned int max_path_len;
+ unsigned int this_path_len;
+ char *file, *dir;
+ char *p;
+ unsigned int nth;
+
+ if ((path == NULL) || (*path == 0)
+ || (name == NULL) || (*name == 0))
+ return NULL;
+
+ max_path_len = 0;
+ this_path_len = 0;
+ p = path;
+ while (*p != 0)
+ {
+ if (*p++ == SEARCH_PATH_DELIMITER)
+ {
+ if (this_path_len > max_path_len) max_path_len = this_path_len;
+ this_path_len = 0;
+ }
+ else this_path_len++;
+ }
+ if (this_path_len > max_path_len) max_path_len = this_path_len;
+ max_path_len++;
+
+ if (NULL == (dir = SLmalloc (max_path_len)))
+ return NULL;
+
+ nth = 0;
+ while (-1 != SLextract_list_element (path, nth, SEARCH_PATH_DELIMITER,
+ dir, max_path_len))
+ {
+ nth++;
+ if (*dir == 0)
+ continue;
+
+ if (NULL == (file = SLpath_dircat (dir, name)))
+ {
+ SLfree (dir);
+ return NULL;
+ }
+
+ if (1 == SLpath_file_exists (file))
+ {
+ SLfree (dir);
+ return file;
+ }
+
+ SLfree (file);
+ }
+
+ SLfree (dir);
+ return NULL;
+}
+
diff --git a/mdk-stage1/slang/slposdir.c b/mdk-stage1/slang/slposdir.c
new file mode 100644
index 000000000..33799e574
--- /dev/null
+++ b/mdk-stage1/slang/slposdir.c
@@ -0,0 +1,1057 @@
+/* file intrinsics for S-Lang */
+/* Copyright (c) 1992, 1999, 2001 John E. Davis
+ * This file is part of the S-Lang library.
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Perl Artistic License.
+ */
+
+#include "slinclud.h"
+
+#if defined(__unix__) || (defined (__os2__) && defined (__EMX__))
+# include <sys/types.h>
+#endif
+
+#ifdef HAVE_IO_H
+# include <io.h> /* for chmod */
+#endif
+
+#if defined(__BORLANDC__)
+# include <process.h>
+# include <dos.h>
+#endif
+
+#ifdef HAVE_FCNTL_H
+# include <fcntl.h>
+#endif
+#ifdef HAVE_SYS_FCNTL_H
+# include <sys/fcntl.h>
+#endif
+
+#ifdef __unix__
+# include <sys/file.h>
+#endif
+
+#if defined(__BORLANDC__)
+# include <dir.h>
+#endif
+
+#if defined(_MSC_VER)
+# include <io.h>
+#endif
+
+#if defined(__DECC) && defined(VMS)
+# include <unixio.h>
+# include <unixlib.h>
+#endif
+
+#ifdef VMS
+# include <stat.h>
+#else
+# include <sys/stat.h>
+#endif
+
+#if defined(VMS)
+# define USE_LISTDIR_INTRINSIC 0
+#else
+# define USE_LISTDIR_INTRINSIC 1
+#endif
+
+#if USE_LISTDIR_INTRINSIC
+
+#if defined(__WIN32__)
+# include <windows.h>
+#else
+# if defined(__OS2__) && defined(__IBMC__)
+# define INCL_DOS
+# define INCL_ERRORS
+# include <os2.h>
+# include <direct.h>
+# include <ctype.h>
+# else
+# ifdef HAVE_DIRENT_H
+# include <dirent.h>
+# else
+# ifdef HAVE_DIRECT_H
+# include <direct.h>
+# else
+# define dirent direct
+# define NEED_D_NAMLEN
+# if HAVE_SYS_NDIR_H
+# include <sys/ndir.h>
+# endif
+# if HAVE_SYS_DIR_H
+# include <sys/dir.h>
+# endif
+# if HAVE_NDIR_H
+# include <ndir.h>
+# endif
+# endif
+# endif
+# endif
+#endif
+
+#endif /* USE_LISTDIR_INTRINSIC */
+
+#include <errno.h>
+
+#include "slang.h"
+#include "_slang.h"
+
+static int push_stat_struct (struct stat *st, int opt_attrs)
+{
+ char *field_names [12];
+ unsigned char field_types[12];
+ VOID_STAR field_values [12];
+ int int_values [12];
+ unsigned int i;
+
+ field_names [0] = "st_dev"; int_values [0] = (int) st->st_dev;
+ field_names [1] = "st_ino"; int_values [1] = (int) st->st_ino;
+ field_names [2] = "st_mode"; int_values [2] = (int) st->st_mode;
+ field_names [3] = "st_nlink"; int_values [3] = (int) st->st_nlink;
+ field_names [4] = "st_uid"; int_values [4] = (int) st->st_uid;
+ field_names [5] = "st_gid"; int_values [5] = (int) st->st_gid;
+ field_names [6] = "st_rdev"; int_values [6] = (int) st->st_rdev;
+ field_names [7] = "st_size"; int_values [7] = (int) st->st_size;
+ field_names [8] = "st_atime"; int_values [8] = (int) st->st_atime;
+ field_names [9] = "st_mtime"; int_values [9] = (int) st->st_mtime;
+ field_names [10] = "st_ctime"; int_values [10] = (int) st->st_ctime;
+
+ field_names [11] = "st_opt_attrs"; int_values[11] = opt_attrs;
+
+ for (i = 0; i < 12; i++)
+ {
+ field_types [i] = SLANG_INT_TYPE;
+ field_values [i] = (VOID_STAR) (int_values + i);
+ }
+
+ return SLstruct_create_struct (12, field_names, field_types, field_values);
+}
+
+static void stat_cmd (char *file)
+{
+ struct stat st;
+ int status;
+ int opt_attrs;
+
+ status = stat (file, &st);
+
+#if defined(__MSDOS__) || defined(__WIN32__)
+ if (status == -1)
+ {
+ unsigned int len = strlen (file);
+ if (len && ((file[len-1] == '\\') || (file[len-1] == '/')))
+ {
+ file = SLmake_nstring (file, len-1);
+ if (file == NULL)
+ return;
+
+ status = stat (file, &st);
+ SLfree (file);
+ }
+ }
+#endif
+ if (status == -1)
+ {
+ _SLerrno_errno = errno;
+ SLang_push_null ();
+ return;
+ }
+
+#ifdef __WIN32__
+ opt_attrs = GetFileAttributes (file);
+#else
+ opt_attrs = 0;
+#endif
+
+ push_stat_struct (&st, opt_attrs);
+}
+
+static void lstat_cmd (char *file)
+{
+#ifdef HAVE_LSTAT
+ struct stat st;
+ int opt_attrs;
+
+ if (-1 == lstat (file, &st))
+ {
+ _SLerrno_errno = errno;
+ SLang_push_null ();
+ return;
+ }
+
+#ifdef __WIN32__
+ opt_attrs = GetFileAttributes (file);
+#else
+ opt_attrs = 0;
+#endif
+
+ push_stat_struct (&st, opt_attrs);
+#else
+ stat_cmd (file);
+#endif
+}
+
+/* Well, it appears that on some systems, these are not defined. Here I
+ * provide them. These are derived from the Linux stat.h file.
+ */
+
+#ifdef __os2__
+# ifdef __IBMC__
+/* IBM VA3 doesn't declare S_IFMT */
+# define S_IFMT (S_IFDIR | S_IFCHR | S_IFREG)
+# endif
+#endif
+
+#ifndef S_ISLNK
+# ifdef S_IFLNK
+# define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
+# else
+# define S_ISLNK(m) 0
+# endif
+#endif
+
+#ifndef S_ISREG
+# ifdef S_IFREG
+# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
+# else
+# define S_ISREG(m) 0
+# endif
+#endif
+
+#ifndef S_ISDIR
+# ifdef S_IFDIR
+# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
+# else
+# define S_ISDIR(m) 0
+# endif
+#endif
+
+#ifndef S_ISCHR
+# ifdef S_IFCHR
+# define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
+# else
+# define S_ISCHR(m) 0
+# endif
+#endif
+
+#ifndef S_ISBLK
+# ifdef S_IFBLK
+# define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK)
+# else
+# define S_ISBLK(m) 0
+# endif
+#endif
+
+#ifndef S_ISFIFO
+# ifdef S_IFIFO
+# define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO)
+# else
+# define S_ISFIFO(m) 0
+# endif
+#endif
+
+#ifndef S_ISSOCK
+# ifdef S_IFSOCK
+# define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
+# else
+# define S_ISSOCK(m) 0
+# endif
+#endif
+
+static char stat_is_cmd (char *what, int *mode_ptr)
+{
+ int ret;
+ int st_mode = *mode_ptr;
+
+ if (!strcmp (what, "sock")) ret = S_ISSOCK(st_mode);
+ else if (!strcmp (what, "fifo")) ret = S_ISFIFO(st_mode);
+ else if (!strcmp (what, "blk")) ret = S_ISBLK(st_mode);
+ else if (!strcmp (what, "chr")) ret = S_ISCHR(st_mode);
+ else if (!strcmp (what, "dir")) ret = S_ISDIR(st_mode);
+ else if (!strcmp (what, "reg")) ret = S_ISREG(st_mode);
+ else if (!strcmp (what, "lnk")) ret = S_ISLNK(st_mode);
+ else
+ {
+ SLang_verror (SL_INVALID_PARM, "stat_is: Unrecognized type: %s", what);
+ return -1;
+ }
+
+ return (char) (ret != 0);
+}
+
+#ifdef HAVE_READLINK
+static void readlink_cmd (char *s)
+{
+ char buf[2048];
+ int n;
+
+ n = readlink (s, buf, sizeof (buf)-1);
+ if (n == -1)
+ {
+ _SLerrno_errno = errno;
+ s = NULL;
+ }
+ else
+ {
+ buf[n] = 0;
+ s = buf;
+ }
+
+ (void) SLang_push_string (s);
+}
+#endif
+
+static int chmod_cmd (char *file, int *mode)
+{
+ if (-1 == chmod(file, (mode_t) *mode))
+ {
+ _SLerrno_errno = errno;
+ return -1;
+ }
+ return 0;
+}
+
+#ifdef HAVE_CHOWN
+static int chown_cmd (char *file, int *owner, int *group)
+{
+ int ret;
+
+ if (-1 == (ret = chown(file, (uid_t) *owner, (gid_t) *group)))
+ _SLerrno_errno = errno;
+ return ret;
+}
+#endif
+
+/* add trailing slash to dir */
+static void fixup_dir (char *dir)
+{
+#ifndef VMS
+ int n;
+
+ if ((n = strlen(dir)) > 1)
+ {
+ n--;
+#if defined(IBMPC_SYSTEM)
+ if ( dir[n] != '/' && dir[n] != '\\' )
+ strcat(dir, "\\" );
+#else
+ if (dir[n] != '/' )
+ strcat(dir, "/" );
+#endif
+ }
+#endif /* !VMS */
+}
+
+static void slget_cwd (void)
+{
+ char cwd[1024];
+ char *p;
+
+#ifndef HAVE_GETCWD
+ p = getwd (cwd);
+#else
+# if defined (__EMX__)
+ p = _getcwd2(cwd, 1022); /* includes drive specifier */
+# else
+ p = getcwd(cwd, 1022); /* djggp includes drive specifier */
+# endif
+#endif
+
+ if (p == NULL)
+ {
+ _SLerrno_errno = errno;
+ SLang_push_null ();
+ return;
+ }
+
+#ifndef VMS
+#ifdef __GO32__
+ /* You never know about djgpp since it favors unix */
+ {
+ char ch;
+ p = cwd;
+ while ((ch = *p) != 0)
+ {
+ if (ch == '/') *p = '\\';
+ p++;
+ }
+ }
+#endif
+ fixup_dir (cwd);
+#endif
+ SLang_push_string (cwd);
+}
+
+static int chdir_cmd (char *s)
+{
+ int ret;
+
+ while (-1 == (ret = chdir (s)))
+ {
+#ifdef EINTR
+ if (errno == EINTR)
+ continue;
+#endif
+ _SLerrno_errno = errno;
+ break;
+ }
+ return ret;
+}
+
+#ifdef VMS
+static int remove_cmd (char *);
+/* If the file looks like xxx, then change it to xxx.dir. If
+ * it looks like A:[B.xxx] then change it to A:[B]xxx.dir.
+ */
+
+static char *vms_convert_dirspec_to_vms_dir (char *str)
+{
+ char *s;
+ char *version;
+ unsigned int len;
+ char *dot;
+
+ len = strlen (str);
+
+ version = strchr (str, ';');
+ if (version == NULL)
+ version = str + len;
+ /* version points to the version of the input string */
+
+
+ if (NULL == (s = SLmalloc (len + 8)))/* allow extra space to work with */
+ return NULL;
+
+ len = (unsigned int) (version - str);
+ strncpy (s, str, len);
+ s[len] = 0;
+ str = s;
+
+ /* Lowercase the whole thing */
+ while (*s != 0)
+ {
+ *s = LOWER_CASE(*s);
+ s++;
+ }
+
+ if ((s > str)
+ && (s[-1] != ']'))
+ {
+ if ((s >= str + 4)
+ && (0 == strcmp (s - 4, ".dir")))
+ s -= 4;
+ goto add_dir_version;
+ }
+
+ /* Check for one of two possibilities:
+ *
+ * dev:[x] --> dev:x
+ * dev:[a.x] --> dev:[a]x
+ */
+
+ if (NULL == (dot = strchr (str, '.')))
+ {
+ /* First possibility */
+ if (NULL == (s = strchr (str, '[')))
+ return str; /* let someone else figure this out */
+ while (s[1] != ']')
+ {
+ s[0] = s[1];
+ s++;
+ }
+ *s = 0;
+ goto add_dir_version;
+ }
+
+ while (NULL != (s = strchr (dot + 1, '.')))
+ dot = s;
+
+ *dot = ']';
+ s = str + (len - 1);
+
+ /* Drop */
+
+ add_dir_version:
+ strcpy (s, ".dir");
+ strcpy (s+4, version);
+ return str;
+}
+#endif
+
+static int rmdir_cmd (char *s)
+{
+#ifdef VMS
+ int status;
+
+ if (NULL == (s = vms_convert_dirspec_to_vms_dir (s)))
+ return -1;
+
+ status = remove_cmd (s);
+ SLfree (s);
+
+ return status;
+
+#else
+ int ret;
+
+ while (-1 == (ret = rmdir (s)))
+ {
+#ifdef EINTR
+ if (errno == EINTR)
+ continue;
+#endif
+ _SLerrno_errno = errno;
+ break;
+ }
+ return ret;
+#endif
+}
+
+static int remove_cmd (char *s)
+{
+ int ret;
+#ifdef VMS
+# define REMOVE delete
+#else
+# ifdef REAL_UNIX_SYSTEM
+# define REMOVE unlink
+# else
+# define REMOVE remove
+# endif
+#endif
+
+ while (-1 == (ret = REMOVE (s)))
+ {
+#ifdef EINTR
+ if (errno == EINTR)
+ continue;
+#endif
+ _SLerrno_errno = errno;
+ break;
+ }
+ return ret;
+}
+
+static int rename_cmd (char *oldpath, char *newpath)
+{
+ int ret;
+ while (-1 == (ret = rename (oldpath, newpath)))
+ {
+#ifdef EINTR
+ if (errno == EINTR)
+ continue;
+#endif
+ _SLerrno_errno = errno;
+ break;
+ }
+ return ret;
+}
+
+static int mkdir_cmd (char *s, int *mode_ptr)
+{
+ int ret;
+
+ (void) mode_ptr;
+ errno = 0;
+
+#if defined (__MSDOS__) && !defined(__GO32__)
+# define MKDIR(x,y) mkdir(x)
+#else
+# if defined (__os2__) && !defined (__EMX__)
+# define MKDIR(x,y) mkdir(x)
+# else
+# if defined (__WIN32__) && !defined (__CYGWIN32__)
+# define MKDIR(x,y) mkdir(x)
+# else
+# define MKDIR mkdir
+# endif
+# endif
+#endif
+
+ while (-1 == (ret = MKDIR(s, *mode_ptr)))
+ {
+#ifdef EINTR
+ if (errno == EINTR)
+ continue;
+#endif
+ _SLerrno_errno = errno;
+ break;
+ }
+ return ret;
+}
+
+#ifdef HAVE_MKFIFO
+static int mkfifo_cmd (char *path, int *mode)
+{
+ if (-1 == mkfifo (path, *mode))
+ {
+ _SLerrno_errno = errno;
+ return -1;
+ }
+ return 0;
+}
+#endif
+
+#if USE_LISTDIR_INTRINSIC
+
+static void free_dir_list (char **list, unsigned int num)
+{
+ unsigned int i;
+
+ if (list == NULL)
+ return;
+
+ for (i = 0; i < num; i++)
+ SLang_free_slstring (list[i]);
+ SLfree ((char *) list);
+}
+
+#if defined(__WIN32__) || defined(__os2__) && defined(__IBMC__)
+static int build_dirlist (char *file, char *opt, char ***listp, unsigned int *nump, unsigned int *maxnum)
+{
+# ifdef __WIN32__
+ DWORD status;
+ HANDLE h;
+ WIN32_FIND_DATA fd;
+# else
+ APIRET rc;
+ FILESTATUS3 status;
+ HDIR h;
+ FILEFINDBUF3 fd;
+ ULONG cFileNames;
+# endif
+ char *pat;
+ unsigned int len;
+ char **list;
+ unsigned int num;
+ unsigned int max_num;
+ int hok;
+
+ /* If an option is present, assume ok to list hidden files. Later
+ * I will formalize this.
+ */
+ hok = (opt != NULL);
+
+# ifdef __WIN32__
+ status = GetFileAttributes (file);
+# else
+ rc = DosQueryPathInfo(file, FIL_STANDARD, &status, sizeof(FILESTATUS3));
+# endif
+
+
+# ifdef __WIN32__
+ if (status == (DWORD)-1)
+ {
+ _SLerrno_errno = ENOENT;
+ return -1;
+ }
+ if (0 == (status & FILE_ATTRIBUTE_DIRECTORY))
+ {
+ _SLerrno_errno = ENOTDIR;
+ return -1;
+ }
+# else
+ if ((rc != 0) || (status.attrFile & FILE_DIRECTORY) == 0)
+ {
+ /* ENOTDIR isn't defined in VA3. */
+ _SLerrno_errno = ENOENT;
+ return -1;
+ }
+# endif
+
+ len = strlen (file);
+ pat = SLmalloc (len + 3);
+ if (pat == NULL)
+ return -1;
+
+ strcpy (pat, file);
+ file = pat;
+ while (*file != 0)
+ {
+ if (*file == '/') *file = '\\';
+ file++;
+ }
+
+ if (len && (pat[len-1] != '\\'))
+ {
+ pat[len] = '\\';
+ len++;
+ }
+ pat[len++] = '*';
+ pat[len] = 0;
+
+ num = 0;
+ max_num = 50;
+ list = (char **)SLmalloc (max_num * sizeof(char *));
+ if (list == NULL)
+ {
+ SLfree (pat);
+ return -1;
+ }
+
+# ifdef __WIN32__
+ h = FindFirstFile(pat, &fd);
+ if (h == INVALID_HANDLE_VALUE)
+ {
+ if (ERROR_NO_MORE_FILES != GetLastError())
+ {
+ SLfree (pat);
+ SLfree ((char *)list);
+ return -1;
+ }
+ }
+# else
+ h = HDIR_CREATE;
+ cFileNames = 1;
+ rc = DosFindFirst(pat, &h, FILE_READONLY | FILE_DIRECTORY |
+ FILE_ARCHIVED, &fd, sizeof(fd), &cFileNames, FIL_STANDARD);
+ if (rc != 0)
+ {
+ if (rc != ERROR_NO_MORE_FILES)
+ {
+ SLfree (pat);
+ SLfree ((char *)list);
+ return -1;
+ }
+ }
+# endif
+ else while (1)
+ {
+ /* Do not include hidden files in the list. Also, do not
+ * include "." and ".." entries.
+ */
+#ifdef __WIN32__
+ file = fd.cFileName;
+#else
+ file = fd.achName;
+#endif
+ if (
+#ifdef __WIN32__
+ (hok || (0 == (fd.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)))
+#else
+ (hok || (0 == (fd.attrFile & FILE_HIDDEN)))
+#endif
+ && ((*file != '.')
+ || ((0 != strcmp (file, "."))
+ && (0 != strcmp (file, "..")))))
+ {
+ if (num == max_num)
+ {
+ char **new_list;
+
+ max_num += 100;
+ new_list = (char **)SLrealloc ((char *)list, max_num * sizeof (char *));
+ if (new_list == NULL)
+ goto return_error;
+
+ list = new_list;
+ }
+
+ file = SLang_create_slstring (file);
+ if (file == NULL)
+ goto return_error;
+
+ list[num] = file;
+ num++;
+ }
+
+#ifdef __WIN32__
+ if (FALSE == FindNextFile(h, &fd))
+ {
+ if (ERROR_NO_MORE_FILES == GetLastError())
+ {
+ FindClose (h);
+ break;
+ }
+
+ _SLerrno_errno = errno;
+ FindClose (h);
+ goto return_error;
+ }
+#else
+ cFileNames = 1;
+ rc = DosFindNext(h, &fd, sizeof(fd), &cFileNames);
+ if (rc != 0)
+ {
+ if (rc == ERROR_NO_MORE_FILES)
+ {
+ DosFindClose (h);
+ break;
+ }
+
+ _SLerrno_errno = errno;
+ DosFindClose (h);
+ goto return_error;
+ }
+#endif
+ }
+
+ SLfree (pat);
+ *maxnum = max_num;
+ *nump = num;
+ *listp = list;
+ return 0;
+
+ return_error:
+ free_dir_list (list, num);
+ SLfree (pat);
+ return -1;
+}
+
+#else /* NOT __WIN32__ */
+
+static int build_dirlist (char *dir, char *opt, char ***listp, unsigned int *nump, unsigned int *maxnum)
+{
+ DIR *dp;
+ struct dirent *ep;
+ unsigned int num_files;
+ unsigned int max_num_files;
+ char **list;
+
+ (void) opt;
+
+ if (NULL == (dp = opendir (dir)))
+ {
+ _SLerrno_errno = errno;
+ return -1;
+ }
+
+ num_files = max_num_files = 0;
+ list = NULL;
+ while (NULL != (ep = readdir (dp)))
+ {
+ unsigned int len;
+ char *name;
+
+ name = ep->d_name;
+# ifdef NEED_D_NAMLEN
+ len = ep->d_namlen;
+# else
+ len = strlen (name);
+# endif
+ if ((*name == '.') && (len <= 2))
+ {
+ if (len == 1) continue;
+ if (name [1] == '.') continue;
+ }
+
+ if (num_files == max_num_files)
+ {
+ char **new_list;
+
+ max_num_files += 100;
+ if (NULL == (new_list = (char **) SLrealloc ((char *)list, max_num_files * sizeof(char *))))
+ goto return_error;
+
+ list = new_list;
+ }
+
+ if (NULL == (list[num_files] = SLang_create_nslstring (name, len)))
+ goto return_error;
+
+ num_files++;
+ }
+
+ closedir (dp);
+ *nump = num_files;
+ *maxnum = max_num_files;
+ *listp = list;
+ return 0;
+
+ return_error:
+ if (dp != NULL)
+ closedir (dp);
+ free_dir_list (list, num_files);
+ return -1;
+}
+# endif /* NOT __WIN32__ */
+
+static void listdir_cmd (char *dir, char *opt)
+{
+ SLang_Array_Type *at;
+ unsigned int num_files;
+ unsigned int max_num_files;
+ int inum_files;
+ char **list;
+
+ if (-1 == build_dirlist (dir, opt, &list, &num_files, &max_num_files))
+ {
+ SLang_push_null ();
+ return;
+ }
+ /* If max_num_files == 0, then num_files == 0 and list == NULL.
+ * The realloc step below will malloc list for us.
+ */
+ if (num_files + 1 < max_num_files)
+ {
+ char **new_list;
+ if (NULL == (new_list = (char **) SLrealloc ((char *)list, (num_files + 1)* sizeof(char*))))
+ {
+ free_dir_list (list, num_files);
+ SLang_push_null ();
+ return;
+ }
+ list = new_list;
+ }
+
+ inum_files = (int) num_files;
+ if (NULL == (at = SLang_create_array (SLANG_STRING_TYPE, 0, (VOID_STAR) list, &inum_files, 1)))
+ {
+ free_dir_list (list, num_files);
+ SLang_push_null ();
+ return;
+ }
+
+ /* Allow the array to free this list if push fails */
+ if (-1 == SLang_push_array (at, 1))
+ SLang_push_null ();
+}
+
+static void listdir_cmd_wrap (void)
+{
+ char *s, *sopt;
+
+ sopt = NULL;
+ switch (SLang_Num_Function_Args)
+ {
+ case 2:
+ if (-1 == SLang_pop_slstring (&sopt))
+ return;
+ case 1:
+ if (-1 == SLang_pop_slstring (&s))
+ {
+ SLang_free_slstring (sopt);
+ return;
+ }
+ break;
+ default:
+ SLang_verror (SL_INVALID_PARM, "usage: listdir (string, [opt-string]");
+ return;
+ }
+
+ listdir_cmd (s, sopt);
+ SLang_free_slstring (s);
+ SLang_free_slstring (sopt);
+}
+
+#endif /* USE_LISTDIR_INTRINSIC */
+
+#ifdef HAVE_UMASK
+static int umask_cmd (int *u)
+{
+ return umask (*u);
+}
+#endif
+
+static SLang_Intrin_Fun_Type PosixDir_Name_Table [] =
+{
+#ifdef HAVE_READLINK
+ MAKE_INTRINSIC_S("readlink", readlink_cmd, SLANG_VOID_TYPE),
+#endif
+ MAKE_INTRINSIC_S("lstat_file", lstat_cmd, SLANG_VOID_TYPE),
+ MAKE_INTRINSIC_S("stat_file", stat_cmd, SLANG_VOID_TYPE),
+ MAKE_INTRINSIC_SI("stat_is", stat_is_cmd, SLANG_CHAR_TYPE),
+#ifdef HAVE_MKFIFO
+ MAKE_INTRINSIC_SI("mkfifo", mkfifo_cmd, SLANG_INT_TYPE),
+#endif
+#ifdef HAVE_CHOWN
+ MAKE_INTRINSIC_SII("chown", chown_cmd, SLANG_INT_TYPE),
+#endif
+ MAKE_INTRINSIC_SI("chmod", chmod_cmd, SLANG_INT_TYPE),
+#ifdef HAVE_UMASK
+ MAKE_INTRINSIC_I("umask", umask_cmd, SLANG_INT_TYPE),
+#endif
+ MAKE_INTRINSIC_0("getcwd", slget_cwd, SLANG_VOID_TYPE),
+ MAKE_INTRINSIC_SI("mkdir", mkdir_cmd, SLANG_INT_TYPE),
+ MAKE_INTRINSIC_S("chdir", chdir_cmd, SLANG_INT_TYPE),
+ MAKE_INTRINSIC_S("rmdir", rmdir_cmd, SLANG_INT_TYPE),
+ MAKE_INTRINSIC_S("remove", remove_cmd, SLANG_INT_TYPE),
+ MAKE_INTRINSIC_SS("rename", rename_cmd, SLANG_INT_TYPE),
+#if USE_LISTDIR_INTRINSIC
+ MAKE_INTRINSIC("listdir", listdir_cmd_wrap, SLANG_VOID_TYPE, 0),
+#endif
+ SLANG_END_INTRIN_FUN_TABLE
+};
+
+static SLang_IConstant_Type PosixDir_Consts [] =
+{
+#ifndef S_IRWXU
+# define S_IRWXU 00700
+#endif
+ MAKE_ICONSTANT("S_IRWXU", S_IRWXU),
+#ifndef S_IRUSR
+# define S_IRUSR 00400
+#endif
+ MAKE_ICONSTANT("S_IRUSR", S_IRUSR),
+#ifndef S_IWUSR
+# define S_IWUSR 00200
+#endif
+ MAKE_ICONSTANT("S_IWUSR", S_IWUSR),
+#ifndef S_IXUSR
+# define S_IXUSR 00100
+#endif
+ MAKE_ICONSTANT("S_IXUSR", S_IXUSR),
+#ifndef S_IRWXG
+# define S_IRWXG 00070
+#endif
+ MAKE_ICONSTANT("S_IRWXG", S_IRWXG),
+#ifndef S_IRGRP
+# define S_IRGRP 00040
+#endif
+ MAKE_ICONSTANT("S_IRGRP", S_IRGRP),
+#ifndef S_IWGRP
+# define S_IWGRP 00020
+#endif
+ MAKE_ICONSTANT("S_IWGRP", S_IWGRP),
+#ifndef S_IXGRP
+# define S_IXGRP 00010
+#endif
+ MAKE_ICONSTANT("S_IXGRP", S_IXGRP),
+#ifndef S_IRWXO
+# define S_IRWXO 00007
+#endif
+ MAKE_ICONSTANT("S_IRWXO", S_IRWXO),
+#ifndef S_IROTH
+# define S_IROTH 00004
+#endif
+ MAKE_ICONSTANT("S_IROTH", S_IROTH),
+#ifndef S_IWOTH
+# define S_IWOTH 00002
+#endif
+ MAKE_ICONSTANT("S_IWOTH", S_IWOTH),
+#ifndef S_IXOTH
+# define S_IXOTH 00001
+#endif
+ MAKE_ICONSTANT("S_IXOTH", S_IXOTH),
+#ifdef __WIN32__
+ MAKE_ICONSTANT("FILE_ATTRIBUTE_ARCHIVE", FILE_ATTRIBUTE_ARCHIVE),
+ MAKE_ICONSTANT("FILE_ATTRIBUTE_COMPRESSED", FILE_ATTRIBUTE_COMPRESSED),
+ MAKE_ICONSTANT("FILE_ATTRIBUTE_NORMAL", FILE_ATTRIBUTE_NORMAL),
+ MAKE_ICONSTANT("FILE_ATTRIBUTE_DIRECTORY", FILE_ATTRIBUTE_DIRECTORY),
+ MAKE_ICONSTANT("FILE_ATTRIBUTE_HIDDEN", FILE_ATTRIBUTE_HIDDEN),
+ MAKE_ICONSTANT("FILE_ATTRIBUTE_READONLY", FILE_ATTRIBUTE_READONLY),
+ MAKE_ICONSTANT("FILE_ATTRIBUTE_SYSTEM", FILE_ATTRIBUTE_SYSTEM),
+ MAKE_ICONSTANT("FILE_ATTRIBUTE_TEMPORARY", FILE_ATTRIBUTE_TEMPORARY),
+#endif
+ SLANG_END_ICONST_TABLE
+};
+
+static int Initialized;
+
+int SLang_init_posix_dir (void)
+{
+ if (Initialized)
+ return 0;
+
+ if ((-1 == SLadd_intrin_fun_table(PosixDir_Name_Table, "__POSIX_DIR__"))
+ || (-1 == SLadd_iconstant_table (PosixDir_Consts, NULL))
+ || (-1 == _SLerrno_init ()))
+ return -1;
+
+ Initialized = 1;
+
+ return 0;
+}
+
diff --git a/mdk-stage1/slang/slposio.c b/mdk-stage1/slang/slposio.c
new file mode 100644
index 000000000..ab1e9f689
--- /dev/null
+++ b/mdk-stage1/slang/slposio.c
@@ -0,0 +1,568 @@
+/* This module implements an interface to posix system calls */
+/* file stdio intrinsics for S-Lang */
+/* Copyright (c) 1992, 1999, 2001 John E. Davis
+ * This file is part of the S-Lang library.
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Perl Artistic License.
+ */
+
+#include "slinclud.h"
+
+#if defined(__unix__) || (defined (__os2__) && defined (__EMX__))
+# include <sys/types.h>
+#endif
+
+#ifdef HAVE_FCNTL_H
+# include <fcntl.h>
+#endif
+#ifdef HAVE_SYS_FCNTL_H
+# include <sys/fcntl.h>
+#endif
+
+#ifdef __unix__
+# include <sys/file.h>
+#endif
+
+#ifdef HAVE_IO_H
+# include <io.h>
+#endif
+
+#if defined(__BORLANDC__)
+# include <dir.h>
+#endif
+
+#if defined(__DECC) && defined(VMS)
+# include <unixio.h>
+# include <unixlib.h>
+#endif
+
+#ifdef VMS
+# include <stat.h>
+#else
+# include <sys/stat.h>
+#endif
+
+#include <errno.h>
+
+#include "slang.h"
+#include "_slang.h"
+
+struct _SLFile_FD_Type
+{
+ char *name;
+ unsigned int num_refs; /* reference counting */
+ int fd;
+ SLang_MMT_Type *stdio_mmt; /* fdopen'd stdio object */
+
+ /* methods */
+ int (*close)(int);
+ int (*read) (int, char *, unsigned int *);
+ int (*write)(int, char *, unsigned int *);
+};
+
+static int close_method (int fd)
+{
+ return close (fd);
+}
+
+static int write_method (int fd, char *buf, unsigned int *nump)
+{
+ int num;
+
+ if (-1 == (num = write (fd, buf, *nump)))
+ {
+ *nump = 0;
+ return -1;
+ }
+
+ *nump = (unsigned int) num;
+ return 0;
+}
+
+static int read_method (int fd, char *buf, unsigned int *nump)
+{
+ int num;
+
+ num = read (fd, buf, *nump);
+ if (num == -1)
+ {
+ *nump = 0;
+ return -1;
+ }
+ *nump = (unsigned int) num;
+ return 0;
+}
+
+static int check_fd (int fd)
+{
+ if (fd == -1)
+ {
+#ifdef EBADF
+ _SLerrno_errno = EBADF;
+#endif
+ return -1;
+ }
+
+ return 0;
+}
+
+static int posix_close (SLFile_FD_Type *f)
+{
+ if (-1 == check_fd (f->fd))
+ return -1;
+
+ if ((f->close != NULL)
+ && (-1 == f->close (f->fd)))
+ {
+ _SLerrno_errno = errno;
+ return -1;
+ }
+
+ if (f->stdio_mmt != NULL)
+ {
+ SLang_free_mmt (f->stdio_mmt);
+ f->stdio_mmt = NULL;
+ }
+
+ f->fd = -1;
+ return 0;
+}
+
+/* Usage: Uint write (f, buf); */
+static void posix_write (SLFile_FD_Type *f, SLang_BString_Type *bstr)
+{
+ unsigned int len;
+ char *p;
+
+ if ((-1 == check_fd (f->fd))
+ || (NULL == (p = (char *)SLbstring_get_pointer (bstr, &len))))
+ {
+ SLang_push_integer (-1);
+ return;
+ }
+
+ if (-1 == f->write (f->fd, p, &len))
+ {
+ _SLerrno_errno = errno;
+ SLang_push_integer (-1);
+ return;
+ }
+
+ (void) SLang_push_uinteger (len);
+}
+
+/* Usage: nn = read (f, &buf, n); */
+static void posix_read (SLFile_FD_Type *f, SLang_Ref_Type *ref, unsigned int *nbytes)
+{
+ unsigned int len;
+ char *b;
+ SLang_BString_Type *bstr;
+
+ b = NULL;
+
+ len = *nbytes;
+ if ((-1 == check_fd (f->fd))
+ || (NULL == (b = SLmalloc (len + 1))))
+ goto return_error;
+
+ if (-1 == f->read (f->fd, b, &len))
+ {
+ _SLerrno_errno = errno;
+ goto return_error;
+ }
+
+ if (len != *nbytes)
+ {
+ char *b1 = SLrealloc (b, len + 1);
+ if (b1 == NULL)
+ goto return_error;
+ b = b1;
+ }
+
+ bstr = SLbstring_create_malloced ((unsigned char *) b, len, 0);
+ if (bstr != NULL)
+ {
+ if ((-1 != SLang_assign_to_ref (ref, SLANG_BSTRING_TYPE, (VOID_STAR)&bstr))
+ && (-1 != SLang_push_uinteger (len)))
+ return;
+
+ SLbstring_free (bstr);
+ b = NULL;
+ /* drop */
+ }
+
+ return_error:
+ if (b != NULL) SLfree ((char *)b);
+ (void) SLang_assign_to_ref (ref, SLANG_NULL_TYPE, NULL);
+ (void) SLang_push_integer (-1);
+}
+
+SLFile_FD_Type *SLfile_create_fd (char *name, int fd)
+{
+ SLFile_FD_Type *f;
+
+ if (NULL == (f = (SLFile_FD_Type *) SLmalloc (sizeof (SLFile_FD_Type))))
+ return NULL;
+
+ memset ((char *) f, 0, sizeof (SLFile_FD_Type));
+ if (NULL == (f->name = SLang_create_slstring (name)))
+ {
+ SLfree ((char *)f);
+ return NULL;
+ }
+
+ f->fd = fd;
+ f->num_refs = 1;
+
+ f->close = close_method;
+ f->read = read_method;
+ f->write = write_method;
+
+ return f;
+}
+
+SLFile_FD_Type *SLfile_dup_fd (SLFile_FD_Type *f0)
+{
+ SLFile_FD_Type *f;
+ int fd0, fd;
+
+ if (f0 == NULL)
+ return NULL;
+ fd0 = f0->fd;
+ if (-1 == check_fd (fd0))
+ return NULL;
+
+ while (-1 == (fd = dup (fd0)))
+ {
+#ifdef EINTR
+ if (errno == EINTR)
+ continue;
+#endif
+ _SLerrno_errno = errno;
+ return NULL;
+ }
+
+ if (NULL == (f = SLfile_create_fd (f0->name, fd)))
+ {
+ f0->close (fd);
+ return NULL;
+ }
+
+ return f;
+}
+
+int SLfile_get_fd (SLFile_FD_Type *f, int *fd)
+{
+ if (f == NULL)
+ return -1;
+
+ *fd = f->fd;
+ if (-1 == check_fd (*fd))
+ return -1;
+
+ return 0;
+}
+
+void SLfile_free_fd (SLFile_FD_Type *f)
+{
+ if (f == NULL)
+ return;
+
+ if (f->num_refs > 1)
+ {
+ f->num_refs -= 1;
+ return;
+ }
+
+ if (f->fd != -1)
+ {
+ if (f->close != NULL)
+ (void) f->close (f->fd);
+
+ f->fd = -1;
+ }
+
+ if (f->stdio_mmt != NULL)
+ SLang_free_mmt (f->stdio_mmt);
+
+ SLfree ((char *) f);
+}
+
+static int pop_string_int (char **s, int *i)
+{
+ *s = NULL;
+ if ((-1 == SLang_pop_integer (i))
+ || (-1 == SLang_pop_slstring (s)))
+ return -1;
+
+ return 0;
+}
+
+static int pop_string_int_int (char **s, int *a, int *b)
+{
+ *s = NULL;
+ if ((-1 == SLang_pop_integer (b))
+ || (-1 == pop_string_int (s, a)))
+ return -1;
+
+ return 0;
+}
+
+static void posix_open (void)
+{
+ char *file;
+ int mode, flags;
+ SLFile_FD_Type *f;
+
+ switch (SLang_Num_Function_Args)
+ {
+ case 3:
+ if (-1 == pop_string_int_int (&file, &flags, &mode))
+ {
+ SLang_push_null ();
+ return;
+ }
+ break;
+
+ case 2:
+ default:
+ if (-1 == pop_string_int (&file, &flags))
+ return;
+ mode = 0777;
+ break;
+ }
+
+ f = SLfile_create_fd (file, -1);
+ if (f == NULL)
+ {
+ SLang_free_slstring (file);
+ SLang_push_null ();
+ return;
+ }
+ SLang_free_slstring (file);
+
+ if (-1 == (f->fd = open (f->name, flags, mode)))
+ {
+ _SLerrno_errno = errno;
+ SLfile_free_fd (f);
+ SLang_push_null ();
+ return;
+ }
+
+ if (-1 == SLfile_push_fd (f))
+ SLang_push_null ();
+ SLfile_free_fd (f);
+}
+
+static void posix_fileno (void)
+{
+ FILE *fp;
+ SLang_MMT_Type *mmt;
+ int fd;
+ SLFile_FD_Type *f;
+ char *name;
+
+ if (-1 == SLang_pop_fileptr (&mmt, &fp))
+ {
+ SLang_push_null ();
+ return;
+ }
+ name = SLang_get_name_from_fileptr (mmt);
+ fd = fileno (fp);
+
+ f = SLfile_create_fd (name, fd);
+ if (f != NULL)
+ f->close = NULL; /* prevent fd from being closed
+ * when it goes out of scope
+ */
+ SLang_free_mmt (mmt);
+
+ if (-1 == SLfile_push_fd (f))
+ SLang_push_null ();
+ SLfile_free_fd (f);
+}
+
+static void posix_fdopen (SLFile_FD_Type *f, char *mode)
+{
+ if (f->stdio_mmt == NULL)
+ {
+ if (-1 == _SLstdio_fdopen (f->name, f->fd, mode))
+ return;
+
+ if (NULL == (f->stdio_mmt = SLang_pop_mmt (SLANG_FILE_PTR_TYPE)))
+ return;
+ }
+
+ (void) SLang_push_mmt (f->stdio_mmt);
+}
+
+static long posix_lseek (SLFile_FD_Type *f, long ofs, int whence)
+{
+ long status;
+
+ if (-1 == (status = lseek (f->fd, ofs, whence)))
+ _SLerrno_errno = errno;
+
+ return status;
+}
+
+static int posix_isatty (void)
+{
+ int ret;
+ SLFile_FD_Type *f;
+
+ if (SLang_peek_at_stack () == SLANG_FILE_PTR_TYPE)
+ {
+ SLang_MMT_Type *mmt;
+ FILE *fp;
+
+ if (-1 == SLang_pop_fileptr (&mmt, &fp))
+ return 0; /* invalid descriptor */
+
+ ret = isatty (fileno (fp));
+ SLang_free_mmt (mmt);
+ return ret;
+ }
+
+ if (-1 == SLfile_pop_fd (&f))
+ return 0;
+
+ ret = isatty (f->fd);
+ SLfile_free_fd (f);
+
+ return ret;
+}
+
+static void posix_dup (SLFile_FD_Type *f)
+{
+ if ((NULL == (f = SLfile_dup_fd (f)))
+ || (-1 == SLfile_push_fd (f)))
+ SLang_push_null ();
+
+ SLfile_free_fd (f);
+}
+
+#define I SLANG_INT_TYPE
+#define V SLANG_VOID_TYPE
+#define F SLANG_FILE_FD_TYPE
+#define B SLANG_BSTRING_TYPE
+#define R SLANG_REF_TYPE
+#define U SLANG_UINT_TYPE
+#define S SLANG_STRING_TYPE
+#define L SLANG_LONG_TYPE
+static SLang_Intrin_Fun_Type Fd_Name_Table [] =
+{
+ MAKE_INTRINSIC_0("fileno", posix_fileno, V),
+ MAKE_INTRINSIC_0("isatty", posix_isatty, I),
+ MAKE_INTRINSIC_0("open", posix_open, V),
+ MAKE_INTRINSIC_3("read", posix_read, V, F, R, U),
+ MAKE_INTRINSIC_3("lseek", posix_lseek, L, F, L, I),
+ MAKE_INTRINSIC_2("fdopen", posix_fdopen, V, F, S),
+ MAKE_INTRINSIC_2("write", posix_write, V, F, B),
+ MAKE_INTRINSIC_1("dup_fd", posix_dup, V, F),
+ MAKE_INTRINSIC_1("close", posix_close, I, F),
+ SLANG_END_INTRIN_FUN_TABLE
+};
+#undef I
+#undef V
+#undef F
+#undef B
+#undef R
+#undef S
+#undef L
+#undef U
+
+static SLang_IConstant_Type PosixIO_Consts [] =
+{
+#ifdef O_RDONLY
+ MAKE_ICONSTANT("O_RDONLY", O_RDONLY),
+#endif
+#ifdef O_WRONLY
+ MAKE_ICONSTANT("O_WRONLY", O_WRONLY),
+#endif
+#ifdef O_RDWR
+ MAKE_ICONSTANT("O_RDWR", O_RDWR),
+#endif
+#ifdef O_APPEND
+ MAKE_ICONSTANT("O_APPEND", O_APPEND),
+#endif
+#ifdef O_CREAT
+ MAKE_ICONSTANT("O_CREAT", O_CREAT),
+#endif
+#ifdef O_EXCL
+ MAKE_ICONSTANT("O_EXCL", O_EXCL),
+#endif
+#ifdef O_NOCTTY
+ MAKE_ICONSTANT("O_NOCTTY", O_NOCTTY),
+#endif
+#ifdef O_NONBLOCK
+ MAKE_ICONSTANT("O_NONBLOCK", O_NONBLOCK),
+#endif
+#ifdef O_TRUNC
+ MAKE_ICONSTANT("O_TRUNC", O_TRUNC),
+#endif
+#ifndef O_BINARY
+# define O_BINARY 0
+#endif
+ MAKE_ICONSTANT("O_BINARY", O_BINARY),
+#ifndef O_TEXT
+# define O_TEXT 0
+#endif
+ MAKE_ICONSTANT("O_TEXT", O_TEXT),
+
+ SLANG_END_ICONST_TABLE
+};
+
+int SLfile_push_fd (SLFile_FD_Type *f)
+{
+ if (f == NULL)
+ return SLang_push_null ();
+
+ f->num_refs += 1;
+
+ if (0 == SLclass_push_ptr_obj (SLANG_FILE_FD_TYPE, (VOID_STAR) f))
+ return 0;
+
+ f->num_refs -= 1;
+
+ return -1;
+}
+
+int SLfile_pop_fd (SLFile_FD_Type **f)
+{
+ return SLclass_pop_ptr_obj (SLANG_FILE_FD_TYPE, (VOID_STAR *) f);
+}
+
+static void destroy_fd_type (unsigned char type, VOID_STAR ptr)
+{
+ (void) type;
+ SLfile_free_fd (*(SLFile_FD_Type **) ptr);
+}
+
+static int fd_push (unsigned char type, VOID_STAR v)
+{
+ (void) type;
+ return SLfile_push_fd (*(SLFile_FD_Type **)v);
+}
+
+int SLang_init_posix_io (void)
+{
+ SLang_Class_Type *cl;
+
+ if (NULL == (cl = SLclass_allocate_class ("FD_Type")))
+ return -1;
+ cl->cl_destroy = destroy_fd_type;
+ (void) SLclass_set_push_function (cl, fd_push);
+
+ if (-1 == SLclass_register_class (cl, SLANG_FILE_FD_TYPE, sizeof (SLFile_FD_Type), SLANG_CLASS_TYPE_PTR))
+ return -1;
+
+ if ((-1 == SLadd_intrin_fun_table(Fd_Name_Table, "__POSIXIO__"))
+ || (-1 == SLadd_iconstant_table (PosixIO_Consts, NULL))
+ || (-1 == _SLerrno_init ()))
+ return -1;
+
+ return 0;
+}
+
diff --git a/mdk-stage1/slang/slprepr.c b/mdk-stage1/slang/slprepr.c
new file mode 100644
index 000000000..358eeb874
--- /dev/null
+++ b/mdk-stage1/slang/slprepr.c
@@ -0,0 +1,427 @@
+/* Copyright (c) 1996, 1999, 2001 John E. Davis
+ * This file is part of the S-Lang library.
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Perl Artistic License.
+ */
+
+/*--------------------------------*-C-*---------------------------------*
+ * File: slprepr.c
+ *
+ * preprocessing routines
+ */
+/*{{{ notes: */
+/*
+ * various preprocessing tokens supported
+ *
+ * #ifdef TOKEN1 TOKEN2 ...
+ * - True if any of TOKEN1 TOKEN2 ... are defined
+ *
+ * #ifndef TOKEN1 TOKEN2 ...
+ * - True if none of TOKEN1 TOKEN2 ... are defined
+ *
+ * #iftrue
+ * #ifnfalse
+ * - always True
+ *
+ * #iffalse
+ * #ifntrue
+ * - always False
+ *
+ * #if$ENV
+ * - True if the enviroment variable ENV is set
+ *
+ * #ifn$ENV
+ * - True if the enviroment variable ENV is not set
+ *
+ * #if$ENV TOKEN1 TOKEN2 ...
+ * - True if the contents of enviroment variable ENV match
+ * any of TOKEN1 TOKEN2 ...
+ *
+ * #ifn$ENV TOKEN1 TOKEN2 ...
+ * - True if the contents of enviroment variable ENV do not match
+ * any of TOKEN1 TOKEN2 ...
+ *
+ * NB: For $ENV, the tokens may contain wildcard characters:
+ * '?' - match any single character
+ * '*' - match any number of characters
+ *
+ * #elif...
+ * #else
+ * #endif
+ *
+ *
+ * mj olesen
+ *----------------------------------------------------------------------*/
+/*}}}*/
+/*{{{ includes: */
+#include "slinclud.h"
+
+#include "slang.h"
+#include "_slang.h"
+/*}}}*/
+
+int (*SLprep_exists_hook) (char *, char);
+int (*_SLprep_eval_hook) (char *);
+
+/*{{{ SLprep_open_prep (), SLprep_close_prep () */
+int SLprep_open_prep (SLPreprocess_Type *pt)
+{
+ pt->this_level = 0;
+ pt->exec_level = 0;
+ pt->prev_exec_level = 0;
+ pt->comment_char = '%';
+ pt->preprocess_char = '#';
+ pt->flags = 0;
+ return 0;
+}
+
+void SLprep_close_prep (SLPreprocess_Type *pt)
+{
+ (void) pt;
+}
+/*}}}*/
+
+/*{{{ SLwildcard () */
+/*----------------------------------------------------------------------*
+ * Does `string' match `pattern' ?
+ *
+ * '*' in pattern matches any sub-string (including the null string)
+ * '?' matches any single char.
+ *
+ * Code taken from that donated by Paul Hudson <paulh@harlequin.co.uk>
+ * to the fvwm project.
+ * It is public domain, no strings attached. No guarantees either.
+ *----------------------------------------------------------------------*/
+static int SLwildcard (char *pattern, char *string)
+{
+ if (pattern == NULL || *pattern == '\0' || !strcmp (pattern, "*"))
+ return 1;
+ else if (string == NULL)
+ return 0;
+
+ while (*pattern && *string) switch (*pattern)
+ {
+ case '?':
+ /* match any single character */
+ pattern++;
+ string++;
+ break;
+
+ case '*':
+ /* see if rest of pattern matches any trailing */
+ /* substring of the string. */
+ if (*++pattern == '\0')
+ return 1; /* trailing * must match rest */
+
+ while (*string)
+ {
+ if (SLwildcard (pattern, string)) return 1;
+ string++;
+ }
+ return 0;
+
+ /* break; */
+
+ default:
+ if (*pattern == '\\')
+ {
+ if (*++pattern == '\0')
+ pattern--; /* don't skip trailing backslash */
+ }
+ if (*pattern++ != *string++) return 0;
+ break;
+ }
+
+ return ((*string == '\0')
+ && ((*pattern == '\0') || !strcmp (pattern, "*")));
+}
+/*}}}*/
+
+#if defined(__16_BIT_SYSTEM__)
+# define MAX_DEFINES 10
+#else
+# define MAX_DEFINES 128
+#endif
+
+/* The extra one is for NULL termination */
+char *_SLdefines [MAX_DEFINES + 1];
+
+int SLdefine_for_ifdef (char *s) /*{{{*/
+{
+ unsigned int i;
+
+ for (i = 0; i < MAX_DEFINES; i++)
+ {
+ char *s1 = _SLdefines [i];
+
+ if (s1 == s)
+ return 0; /* already defined (hashed string) */
+
+ if (s1 != NULL)
+ continue;
+
+ s = SLang_create_slstring (s);
+ if (s == NULL)
+ return -1;
+
+ _SLdefines[i] = s;
+ return 0;
+ }
+ return -1;
+}
+/*}}}*/
+
+/*{{{ static functions */
+static int is_any_defined(char *buf, char comment) /*{{{*/
+{
+ char *sys;
+ unsigned int i;
+
+ while (1)
+ {
+ register char ch;
+
+ /* Skip whitespace */
+ while (((ch = *buf) == ' ') || (ch == '\t'))
+ buf++;
+
+ if ((ch == '\n') || (ch == 0) || (ch == comment))
+ return 0;
+
+ i = 0;
+ while (NULL != (sys = _SLdefines [i++]))
+ {
+ unsigned int n;
+
+ if (*sys != ch)
+ continue;
+
+ n = strlen (sys);
+ if (0 == strncmp (buf, sys, n))
+ {
+ char ch1 = *(buf + n);
+
+ if ((ch1 == '\n') || (ch1 == 0) ||
+ (ch1 == ' ') || (ch1 == '\t') || (ch1 == comment))
+ return 1;
+ }
+ }
+
+ /* Skip past word */
+ while (((ch = *buf) != ' ')
+ && (ch != '\n')
+ && (ch != 0)
+ && (ch != '\t')
+ && (ch != comment))
+ buf++;
+ }
+}
+/*}}}*/
+
+static unsigned char *tokenize (unsigned char *buf, char *token, unsigned int len)
+{
+ register char *token_end;
+
+ token_end = token + (len - 1); /* allow room for \0 */
+
+ while ((token < token_end) && (*buf > ' '))
+ *token++ = *buf++;
+
+ if (*buf > ' ') return NULL; /* token too long */
+
+ *token = '\0';
+
+ while ((*buf == ' ') || (*buf == '\t')) buf++;
+
+ return buf;
+}
+
+static int is_env_defined (char *buf, char comment) /*{{{*/
+{
+ char * env, token [32];
+
+ if ((*buf <= ' ') || (*buf == comment)) return 0; /* no token */
+
+ if (NULL == (buf = (char *) tokenize ((unsigned char *) buf,
+ token, sizeof (token))))
+ return 0;
+
+ if (NULL == (env = getenv (token)))
+ return 0; /* ENV not defined */
+
+ if ((*buf == '\0') || (*buf == '\n') || (*buf == comment))
+ return 1; /* no tokens, but getenv() worked */
+
+ do
+ {
+ buf = (char *) tokenize ((unsigned char *) buf, token, sizeof (token));
+ if (buf == NULL) return 0;
+
+ if (SLwildcard (token, env))
+ return 1;
+ }
+ while (*buf && (*buf != '\n') && (*buf != comment));
+
+ return 0;
+}
+/*}}}*/
+/*}}}*/
+
+int SLprep_line_ok (char *buf, SLPreprocess_Type *pt) /*{{{*/
+{
+ int level, prev_exec_level, exec_level;
+
+ if ((buf == NULL) || (pt == NULL)) return 1;
+
+ if (*buf != pt->preprocess_char)
+ {
+ if (pt->this_level != pt->exec_level)
+ return 0;
+
+ if (*buf == '\n') return pt->flags & SLPREP_BLANK_LINES_OK;
+ if (*buf == pt->comment_char) return pt->flags & SLPREP_COMMENT_LINES_OK;
+
+ return 1;
+ }
+
+ level = pt->this_level;
+ exec_level = pt->exec_level;
+ prev_exec_level = pt->prev_exec_level;
+
+ buf++;
+
+ /* Allow '#!' to pass. This could be a shell script with something
+ like '#! /local/bin/slang' */
+ if ((*buf == '!') && (pt->preprocess_char == '#'))
+ return 0;
+
+ /* Allow whitespace as in '# ifdef' */
+ while ((*buf == ' ') || (*buf == '\t')) buf++;
+ if (*buf < 'a') return (level == exec_level);
+
+ if (!strncmp(buf, "endif", 5))
+ {
+ if (level == exec_level)
+ {
+ exec_level--;
+ prev_exec_level = exec_level;
+ }
+ level--;
+ if (level < prev_exec_level) prev_exec_level = level;
+ goto done;
+ }
+
+ if ((buf[0] == 'e') && (buf[1] == 'l')) /* else, elifdef, ... */
+ {
+ if ((level == exec_level + 1)
+ && (prev_exec_level != level))
+ {
+ /* We are in position to execute */
+ buf += 2;
+ if ((buf[0] == 's') && (buf[1] == 'e'))
+ {
+ /* "else" */
+ exec_level = level;
+ goto done;
+ }
+
+ /* drop through to ifdef testing. First set variable
+ * to values appropriate for ifdef testing.
+ */
+ level--; /* now == to exec level */
+ }
+ else
+ {
+ if (level == exec_level)
+ {
+ exec_level--;
+ }
+ goto done;
+ }
+ }
+
+ if ((buf[0] == 'i') && (buf[1] == 'f'))
+ {
+ int truth;
+
+ if (level != exec_level)
+ {
+ /* Not interested */
+ level++;
+ goto done;
+ }
+
+ level++;
+
+ buf += 2;
+ if (buf[0] == 'n')
+ {
+ truth = 0;
+ buf++;
+ }
+ else truth = 1;
+
+ if (!strncmp (buf, "def", 3))
+ truth = (truth == is_any_defined(buf + 3, pt->comment_char));
+
+ else if (!strncmp (buf, "false", 5))
+ truth = !truth;
+
+ else if (*buf == '$')
+ truth = (truth == is_env_defined (buf + 1, pt->comment_char));
+
+ else if (!strncmp (buf, "exists", 6)
+ && (SLprep_exists_hook != NULL))
+ truth = (truth == (*SLprep_exists_hook)(buf + 6, pt->comment_char));
+
+ else if (!strncmp (buf, "eval", 4)
+ && (_SLprep_eval_hook != NULL))
+ truth = (truth == (*_SLprep_eval_hook) (buf + 4));
+
+ else if (0 != strncmp (buf, "true", 4))
+ return 1; /* let it bomb */
+
+ if (truth)
+ {
+ exec_level = level;
+ prev_exec_level = exec_level;
+ }
+ }
+ else return 1; /* let it bomb. */
+
+ done:
+
+ if (exec_level < 0) return 1;
+
+ pt->this_level = level;
+ pt->exec_level = exec_level;
+ pt->prev_exec_level = prev_exec_level;
+ return 0;
+}
+/*}}}*/
+
+/*{{{ main() - for testing only */
+#if 0
+int main ()
+{
+ char buf[1024];
+ SLPreprocess_Type pt;
+
+ SLprep_open_prep (&pt);
+
+ SLdefine_for_ifdef ("UNIX");
+
+ while (NULL != fgets (buf, sizeof (buf) - 1, stdin))
+ {
+ if (SLprep_line_ok (buf, &pt))
+ {
+ fputs (buf, stdout);
+ }
+ }
+
+ SLprep_close_prep (&pt);
+ return 0;
+}
+#endif
+/*}}}*/
diff --git a/mdk-stage1/slang/slproc.c b/mdk-stage1/slang/slproc.c
new file mode 100644
index 000000000..8b266f28f
--- /dev/null
+++ b/mdk-stage1/slang/slproc.c
@@ -0,0 +1,155 @@
+/* Process specific system calls */
+/* Copyright (c) 1992, 1999, 2001 John E. Davis
+ * This file is part of the S-Lang library.
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Perl Artistic License.
+ */
+
+#include "slinclud.h"
+
+#ifdef HAVE_IO_H
+# include <io.h> /* for chmod */
+#endif
+
+#ifdef HAVE_PROCESS_H
+# include <process.h> /* for getpid */
+#endif
+
+#if defined(__BORLANDC__)
+# include <dos.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <signal.h>
+#include <time.h>
+
+#include <errno.h>
+
+#include "slang.h"
+#include "_slang.h"
+
+#ifdef HAVE_KILL
+static int kill_cmd (int *pid, int *sig)
+{
+ int ret;
+
+ if (-1 == (ret = kill ((pid_t) *pid, *sig)))
+ _SLerrno_errno = errno;
+ return ret;
+}
+#endif
+
+static int getpid_cmd (void)
+{
+ return getpid ();
+}
+
+#ifdef HAVE_GETPPID
+static int getppid_cmd (void)
+{
+ return getppid ();
+}
+#endif
+
+#ifdef HAVE_GETGID
+static int getgid_cmd (void)
+{
+ return getgid ();
+}
+#endif
+
+#ifdef HAVE_GETEGID
+static int getegid_cmd (void)
+{
+ return getegid ();
+}
+#endif
+
+#ifdef HAVE_GETEUID
+static int geteuid_cmd (void)
+{
+ return geteuid ();
+}
+#endif
+
+#ifdef HAVE_GETUID
+static int getuid_cmd (void)
+{
+ return getuid ();
+}
+#endif
+
+#ifdef HAVE_SETGID
+static int setgid_cmd (int *gid)
+{
+ if (0 == setgid (*gid))
+ return 0;
+ _SLerrno_errno = errno;
+ return -1;
+}
+#endif
+
+#ifdef HAVE_SETPGID
+static int setpgid_cmd (int *pid, int *pgid)
+{
+ if (0 == setpgid (*pid, *pgid))
+ return 0;
+ _SLerrno_errno = errno;
+ return -1;
+}
+#endif
+
+#ifdef HAVE_SETUID
+static int setuid_cmd (int *uid)
+{
+ if (0 == setuid (*uid))
+ return 0;
+ _SLerrno_errno = errno;
+ return -1;
+}
+#endif
+
+static SLang_Intrin_Fun_Type Process_Name_Table[] =
+{
+ MAKE_INTRINSIC_0("getpid", getpid_cmd, SLANG_INT_TYPE),
+
+#ifdef HAVE_GETPPID
+ MAKE_INTRINSIC_0("getppid", getppid_cmd, SLANG_INT_TYPE),
+#endif
+#ifdef HAVE_GETGID
+ MAKE_INTRINSIC_0("getgid", getgid_cmd, SLANG_INT_TYPE),
+#endif
+#ifdef HAVE_GETEGID
+ MAKE_INTRINSIC_0("getegid", getegid_cmd, SLANG_INT_TYPE),
+#endif
+#ifdef HAVE_GETEUID
+ MAKE_INTRINSIC_0("geteuid", geteuid_cmd, SLANG_INT_TYPE),
+#endif
+#ifdef HAVE_GETUID
+ MAKE_INTRINSIC_0("getuid", getuid_cmd, SLANG_INT_TYPE),
+#endif
+#ifdef HAVE_SETGID
+ MAKE_INTRINSIC_I("setgid", setgid_cmd, SLANG_INT_TYPE),
+#endif
+#ifdef HAVE_SETPGID
+ MAKE_INTRINSIC_II("setpgid", setpgid_cmd, SLANG_INT_TYPE),
+#endif
+#ifdef HAVE_SETUID
+ MAKE_INTRINSIC_I("setuid", setuid_cmd, SLANG_INT_TYPE),
+#endif
+
+#ifdef HAVE_KILL
+ MAKE_INTRINSIC_II("kill", kill_cmd, SLANG_INT_TYPE),
+#endif
+ SLANG_END_INTRIN_FUN_TABLE
+};
+
+int SLang_init_posix_process (void)
+{
+ if ((-1 == SLadd_intrin_fun_table (Process_Name_Table, "__POSIX_PROCESS__"))
+ || (-1 == _SLerrno_init ()))
+ return -1;
+ return 0;
+}
diff --git a/mdk-stage1/slang/slregexp.c b/mdk-stage1/slang/slregexp.c
new file mode 100644
index 000000000..6592a5a63
--- /dev/null
+++ b/mdk-stage1/slang/slregexp.c
@@ -0,0 +1,935 @@
+/* ed style regular expressions */
+/* Copyright (c) 1992, 1999, 2001 John E. Davis
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Perl Artistic License.
+ */
+
+#include "slinclud.h"
+
+#include "slang.h"
+#include "_slang.h"
+
+#define SET_BIT(b, n) b[(unsigned int) (n) >> 3] |= 1 << ((unsigned int) (n) % 8)
+#define TEST_BIT(b, n) (b[(unsigned int)(n) >> 3] & (1 << ((unsigned int) (n) % 8)))
+#define LITERAL 1
+#define RANGE 2 /* [...] */
+#define ANY 3 /* . */
+#define BOL 4 /* ^ */
+#define EOL 5 /* $ */
+#define NTH_MATCH 6 /* \1 \2 ... \9 */
+#define OPAREN 7 /* \( */
+#define CPAREN 0x8 /* \) */
+#define ANY_DIGIT 0x9 /* \d */
+#define BOW 0xA /* \< */
+#define EOW 0xB /* \> */
+#if 0
+#define NOT_LITERAL 0xC /* \~ */
+#endif
+#define STAR 0x80 /* * */
+#define LEAST_ONCE 0x40 /* + */
+#define MAYBE_ONCE 0x20 /* ? */
+#define MANY 0x10 /* {n,m} */
+/* The rest are additions */
+#define YES_CASE (STAR | BOL)
+#define NO_CASE (STAR | EOL)
+
+#define UPPERCASE(x) (cs ? (x) : UPPER_CASE(x))
+#define LOWERCASE(x) (cs ? (x) : LOWER_CASE(x))
+
+static unsigned char Word_Chars[256];
+#define IS_WORD_CHAR(x) Word_Chars[(unsigned int) (x)]
+
+#if 0
+static int ctx->open_paren_number;
+static char Closed_Paren_Matches[10];
+
+static SLRegexp_Type *This_Reg;
+static unsigned char *This_Str;
+#endif
+
+typedef struct
+{
+ SLRegexp_Type *reg;
+ unsigned char *str;
+ unsigned int len;
+ char closed_paren_matches[10];
+ int open_paren_number;
+}
+Re_Context_Type;
+
+static unsigned char *do_nth_match (Re_Context_Type *ctx, int n, unsigned char *str, unsigned char *estr)
+{
+ unsigned char *bpos;
+
+ if (ctx->closed_paren_matches[n] == 0)
+ return NULL;
+
+ bpos = ctx->reg->beg_matches[n] + ctx->str;
+ n = ctx->reg->end_matches[n];
+ if (n == 0) return(str);
+ if (n > (int) (estr - str)) return (NULL);
+
+ /* This needs fixed for case sensitive match */
+ if (0 != strncmp((char *) str, (char *) bpos, (unsigned int) n)) return (NULL);
+ str += n;
+ return (str);
+}
+
+/* returns pointer to the end of regexp or NULL */
+static unsigned char *regexp_looking_at (Re_Context_Type *ctx, register unsigned char *str, unsigned char *estr, unsigned char *buf, register int cs)
+{
+ register unsigned char p, p1;
+ unsigned char *save_str, *tmpstr;
+ int n, n0, n1;
+ int save_num_open;
+ char save_closed_matches[10];
+
+ p = *buf++;
+
+ while (p != 0)
+ {
+ /* p1 = UPPERCASE(*buf); */
+ /* if (str < estr) c = UPPERCASE(*str); */
+
+ switch((unsigned char) p)
+ {
+ case BOW:
+ if ((str != ctx->str)
+ && ((str >= estr)
+ || IS_WORD_CHAR(*(str - 1))
+ || (0 == IS_WORD_CHAR(*str)))) return NULL;
+ break;
+
+ case EOW:
+ if ((str < estr)
+ && IS_WORD_CHAR (*str)) return NULL;
+ break;
+
+ case YES_CASE: cs = 1; break;
+ case NO_CASE: cs = 0; break;
+
+ case OPAREN:
+ ctx->open_paren_number++;
+ ctx->reg->beg_matches[ctx->open_paren_number] = (int) (str - ctx->str);
+ break;
+ case CPAREN:
+ n = ctx->open_paren_number;
+ while (n > 0)
+ {
+ if (ctx->closed_paren_matches[n] != 0)
+ {
+ n--;
+ continue;
+ }
+ ctx->closed_paren_matches[n] = 1;
+ ctx->reg->end_matches[n] = (unsigned int) (str - (ctx->str + ctx->reg->beg_matches[n]));
+ break;
+ }
+ break;
+#ifdef NOT_LITERAL
+ case NOT_LITERAL:
+ if ((str >= estr) || (*buf == UPPERCASE(*str))) return (NULL);
+ str++; buf++;
+ break;
+
+ case MAYBE_ONCE | NOT_LITERAL:
+ save_str = str;
+ if ((str < estr) && (*buf != UPPERCASE(*str))) str++;
+ buf++;
+ goto match_rest;
+
+ case NOT_LITERAL | LEAST_ONCE: /* match at least once */
+ if ((str >= estr) || (UPPERCASE(*str) == UPPERCASE(*buf))) return (NULL);
+ str++;
+ /* drop */
+ case STAR | NOT_LITERAL:
+ save_str = str; p1 = *buf;
+ while ((str < estr) && (UPPERCASE(*str) != p1)) str++;
+ buf++;
+ goto match_rest;
+
+ /* this type consists of the expression + two bytes that
+ determine number of matches to perform */
+ case MANY | NOT_LITERAL:
+ p1 = *buf; buf++;
+ n = n0 = (int) (unsigned char) *buf++;
+ /* minimum number to match--- could be 0 */
+ n1 = (int) (unsigned char) *buf++;
+ /* maximum number to match */
+
+ while (n && (str < estr) && (p1 != *str))
+ {
+ n--;
+ str++;
+ }
+ if (n) return (NULL);
+
+ save_str = str;
+ n = n1 - n0;
+ while (n && (str < estr) && (p1 != *str))
+ {
+ n--;
+ str++;
+ }
+ goto match_rest;
+#endif /* NOT_LITERAL */
+ case LITERAL:
+ if ((str >= estr) || (*buf != UPPERCASE(*str))) return (NULL);
+ str++; buf++;
+ break;
+
+ case MAYBE_ONCE | LITERAL:
+ save_str = str;
+ if ((str < estr) && (*buf == UPPERCASE(*str))) str++;
+ buf++;
+ goto match_rest;
+
+ case LITERAL | LEAST_ONCE: /* match at least once */
+ if ((str >= estr) || (UPPERCASE(*str) != UPPERCASE(*buf))) return (NULL);
+ str++;
+ /* drop */
+ case STAR | LITERAL:
+ save_str = str; p1 = *buf;
+ while ((str < estr) && (UPPERCASE(*str) == p1)) str++;
+ buf++;
+ goto match_rest;
+
+ /* this type consists of the expression + two bytes that
+ determine number of matches to perform */
+ case MANY | LITERAL:
+ p1 = *buf; buf++;
+ n = n0 = (int) (unsigned char) *buf++;
+ /* minimum number to match--- could be 0 */
+ n1 = (int) (unsigned char) *buf++;
+ /* maximum number to match */
+
+ while (n && (str < estr) && (p1 == *str))
+ {
+ n--;
+ str++;
+ }
+ if (n) return (NULL);
+
+ save_str = str;
+ n = n1 - n0;
+ while (n && (str < estr) && (p1 == *str))
+ {
+ n--;
+ str++;
+ }
+ goto match_rest;
+
+ case NTH_MATCH:
+ if ((str = do_nth_match(ctx, (int) (unsigned char) *buf, str, estr)) == NULL) return(NULL);
+ buf++;
+ break;
+
+ case MAYBE_ONCE | NTH_MATCH:
+ save_str = str;
+ tmpstr = do_nth_match (ctx, (int) (unsigned char) *buf, str, estr);
+ buf++;
+ if (tmpstr != NULL)
+ {
+ str = tmpstr;
+ goto match_rest;
+ }
+ continue;
+
+ case LEAST_ONCE | NTH_MATCH:
+ if ((str = do_nth_match(ctx, (int) (unsigned char) *buf, str, estr)) == NULL) return(NULL);
+ /* drop */
+ case STAR | NTH_MATCH:
+ save_str = str;
+ while (NULL != (tmpstr = do_nth_match(ctx, (int) (unsigned char) *buf, str, estr)))
+ {
+ str = tmpstr;
+ }
+ buf++;
+ goto match_rest;
+
+ case MANY | NTH_MATCH: return(NULL);
+ /* needs done */
+
+ case RANGE:
+ if (str >= estr) return (NULL);
+ if (TEST_BIT(buf, UPPERCASE(*str)) == 0) return (NULL);
+ buf += 32; str++;
+ break;
+
+ case MAYBE_ONCE | RANGE:
+ save_str = str;
+ if ((str < estr) && TEST_BIT(buf, UPPERCASE(*str))) str++;
+ buf += 32;
+ goto match_rest;
+
+ case LEAST_ONCE | RANGE:
+ if ((str >= estr) || (0 == TEST_BIT(buf, UPPERCASE(*str)))) return NULL;
+ str++;
+ /* drop */
+ case STAR | RANGE:
+ save_str = str;
+ while ((str < estr) && TEST_BIT(buf, UPPERCASE(*str))) str++;
+ buf += 32;
+ goto match_rest;
+
+ /* The first 32 bytes correspond to the range and the two
+ * following bytes indicate the min and max number of matches.
+ */
+ case MANY | RANGE:
+ /* minimum number to match--- could be 0 */
+ n = n0 = (int) (unsigned char) *(buf + 32);
+ /* maximum number to match */
+ n1 = (int) (unsigned char) *(buf + 33);
+
+ while (n && (str < estr) && (TEST_BIT(buf, UPPERCASE(*str))))
+ {
+ n--;
+ str++;
+ }
+ if (n) return (NULL);
+ save_str = str;
+ n = n1 - n0;
+ while (n && (str < estr) && (TEST_BIT(buf, UPPERCASE(*str))))
+ {
+ n--;
+ str++;
+ }
+ buf += 34; /* 32 + 2 */
+ goto match_rest;
+
+ case ANY_DIGIT:
+ if ((str >= estr) || (*str > '9') || (*str < '0')) return (NULL);
+ str++;
+ break;
+
+ case MAYBE_ONCE | ANY_DIGIT:
+ save_str = str;
+ if ((str < estr) && ((*str > '9') || (*str < '0'))) str++;
+ goto match_rest;
+
+ case LEAST_ONCE | ANY_DIGIT:
+ if ((str >= estr) || ((*str > '9') || (*str < '0'))) return NULL;
+ str++;
+ /* drop */
+ case STAR | ANY_DIGIT:
+ save_str = str;
+ while ((str < estr) && ((*str <= '9') && (*str >= '0'))) str++;
+ goto match_rest;
+
+ case MANY | ANY_DIGIT:
+ /* needs finished */
+ return (NULL);
+
+ case ANY:
+ if ((str >= estr) || (*str == '\n')) return (NULL);
+ str++;
+ break;
+
+ case MAYBE_ONCE | ANY:
+ save_str = str;
+ if ((str < estr) && (*str != '\n')) str++;
+ goto match_rest;
+
+ case LEAST_ONCE | ANY:
+ if ((str >= estr) || (*str == '\n')) return (NULL);
+ str++;
+ /* drop */
+ case STAR | ANY:
+ save_str = str;
+ while ((str < estr) && (*str != '\n')) str++;
+ goto match_rest;
+
+ case MANY | ANY:
+ return (NULL);
+ /* needs finished */
+
+ case EOL:
+ if ((str >= estr) || (*str == '\n')) return (str);
+ return(NULL);
+
+ default: return (NULL);
+ }
+ p = *buf++;
+ continue;
+
+ match_rest:
+ if (save_str == str)
+ {
+ p = *buf++;
+ continue;
+ }
+
+ /* if (p == EOL)
+ * {
+ * if (str < estr) return (NULL); else return (str);
+ * }
+ */
+
+ SLMEMCPY(save_closed_matches, ctx->closed_paren_matches, sizeof(save_closed_matches));
+ save_num_open = ctx->open_paren_number;
+ while (str >= save_str)
+ {
+ tmpstr = regexp_looking_at (ctx, str, estr, buf, cs);
+ if (tmpstr != NULL) return(tmpstr);
+ SLMEMCPY(ctx->closed_paren_matches, save_closed_matches, sizeof(ctx->closed_paren_matches));
+ ctx->open_paren_number = save_num_open;
+ str--;
+ }
+ return NULL;
+ }
+ if ((p != 0) && (p != EOL)) return (NULL); else return (str);
+}
+
+static void
+fixup_beg_end_matches (Re_Context_Type *ctx, SLRegexp_Type *r, unsigned char *str, unsigned char *epos)
+{
+ int i;
+
+ if (str == NULL)
+ {
+ r->beg_matches[0] = -1;
+ r->end_matches[0] = 0;
+ SLMEMSET(ctx->closed_paren_matches, 0, sizeof(ctx->closed_paren_matches));
+ }
+ else
+ {
+ r->beg_matches[0] = (int) (str - ctx->str);
+ r->end_matches[0] = (unsigned int) (epos - str);
+ }
+
+ for (i = 1; i < 10; i++)
+ {
+ if (ctx->closed_paren_matches [i] == 0)
+ {
+ r->beg_matches[i] = -1;
+ r->end_matches[i] = 0;
+ }
+ }
+}
+
+static void init_re_context (Re_Context_Type *ctx, SLRegexp_Type *reg,
+ unsigned char *str, unsigned int len)
+{
+ memset ((char *) ctx, 0, sizeof (Re_Context_Type));
+ ctx->reg = reg;
+ ctx->str = str;
+ ctx->len = len;
+}
+
+unsigned char *SLang_regexp_match(unsigned char *str,
+ unsigned int len, SLRegexp_Type *reg)
+{
+ register unsigned char c = 0, *estr = str + len;
+ int cs = reg->case_sensitive, lit = 0;
+ unsigned char *buf = reg->buf, *epos = NULL;
+ Re_Context_Type ctx_buf;
+
+ if (reg->min_length > len) return NULL;
+
+ init_re_context (&ctx_buf, reg, str, len);
+
+ if (*buf == BOL)
+ {
+ if (NULL == (epos = regexp_looking_at (&ctx_buf, str, estr, buf + 1, cs)))
+ str = NULL;
+
+ fixup_beg_end_matches (&ctx_buf, reg, str, epos);
+ return str;
+ }
+
+ if (*buf == NO_CASE)
+ {
+ buf++; cs = 0;
+ }
+
+ if (*buf == YES_CASE)
+ {
+ buf++; cs = 1;
+ }
+
+ if (*buf == LITERAL)
+ {
+ lit = 1;
+ c = *(buf + 1);
+ }
+ else if ((*buf == OPAREN) && (*(buf + 1) == LITERAL))
+ {
+ lit = 1;
+ c = *(buf + 2);
+ }
+
+ while (str < estr)
+ {
+ ctx_buf.open_paren_number = 0;
+ memset (ctx_buf.closed_paren_matches, 0, sizeof(ctx_buf.closed_paren_matches));
+ /* take care of leading chars */
+ if (lit)
+ {
+ while ((str < estr) && (c != UPPERCASE(*str))) str++;
+ if (str >= estr)
+ break; /* failed */
+ }
+
+ if (NULL != (epos = regexp_looking_at(&ctx_buf, str, estr, buf, cs)))
+ {
+ fixup_beg_end_matches (&ctx_buf, reg, str, epos);
+ return str;
+ }
+ str++;
+ }
+ fixup_beg_end_matches (&ctx_buf, reg, NULL, epos);
+ return NULL;
+}
+
+static unsigned char *convert_digit(unsigned char *pat, int *nn)
+{
+ int n = 0, m = 0;
+ unsigned char c;
+ while (c = (unsigned char) *pat, (c <= '9') && (c >= '0'))
+ {
+ pat++;
+ n = 10 * n + (c - '0');
+ m++;
+ }
+ if (m == 0)
+ {
+ return (NULL);
+ }
+ *nn = n;
+ return pat;
+}
+
+#define ERROR return (int) (pat - reg->pat)
+
+/* Returns 0 if successful or offset in pattern of error */
+int SLang_regexp_compile (SLRegexp_Type *reg)
+{
+ register unsigned char *buf, *ebuf, *pat;
+ unsigned char *last = NULL, *tmppat;
+ register unsigned char c;
+ int i, reverse = 0, n, cs;
+ int oparen = 0, nparen = 0;
+ /* substring stuff */
+ int count, last_count, this_max_mm = 0, max_mm = 0, ordinary_search,
+ no_osearch = 0, min_length = 0;
+ unsigned char *mm_p = NULL, *this_mm_p = NULL;
+ static int already_initialized;
+
+ reg->beg_matches[0] = reg->end_matches[0] = 0;
+ buf = reg->buf;
+ ebuf = (reg->buf + reg->buf_len) - 2; /* make some room */
+ pat = reg->pat;
+ cs = reg->case_sensitive;
+
+ if (already_initialized == 0)
+ {
+ SLang_init_case_tables ();
+#ifdef IBMPC_SYSTEM
+ SLmake_lut (Word_Chars, (unsigned char *) "_0-9a-zA-Z\200-\232\240-\245\341-\353", 0);
+#else
+ SLmake_lut (Word_Chars, (unsigned char *) "_0-9a-zA-Z\277-\326\330-\336\340-\366\370-\376", 0);
+#endif
+ already_initialized = 1;
+ }
+
+ i = 1; while (i < 10)
+ {
+ reg->beg_matches[i] = -1;
+ reg->end_matches[i] = 0;
+ i++;
+ }
+
+ if (*pat == '\\')
+ {
+ if (pat[1] == 'c')
+ {
+ cs = 1;
+ pat += 2;
+ no_osearch = 1;
+ }
+ else if (pat[1] == 'C')
+ {
+ cs = 0;
+ pat += 2;
+ no_osearch = 1;
+ }
+ }
+
+ if (*pat == '^')
+ {
+ pat++;
+ *buf++ = BOL;
+ reg->must_match_bol = 1;
+ }
+ else reg->must_match_bol = 0;
+
+ if (cs != reg->case_sensitive)
+ {
+ if (cs) *buf++ = YES_CASE;
+ else *buf++ = NO_CASE;
+ }
+
+ *buf = 0;
+
+ last_count = count = 0;
+ while ((c = *pat++) != 0)
+ {
+ if (buf >= ebuf - 3)
+ {
+ SLang_doerror ("Pattern too large to be compiled.");
+ ERROR;
+ }
+
+ count++;
+ switch (c)
+ {
+ case '$':
+ if (*pat != 0) goto literal_char;
+ *buf++ = EOL;
+ break;
+
+ case '\\':
+ c = *pat++;
+ no_osearch = 1;
+ switch(c)
+ {
+ case 'e': c = 033; goto literal_char;
+ case 'n': c = '\n'; goto literal_char;
+ case 't': c = '\t'; goto literal_char;
+ case 'C': cs = 0; *buf++ = NO_CASE; break;
+ case 'c': cs = 1; *buf++ = YES_CASE; break;
+ case '1': case '2': case '3': case '4': case '5':
+ case '6': case '7': case '8': case '9':
+ c = c - '0';
+ if ((int) c > nparen) ERROR;
+ last = buf;
+ *buf++ = NTH_MATCH; *buf++ = c;
+ break;
+#ifdef NOT_LITERAL
+ case '~': /* slang extension */
+ if ((c = *pat) == 0) ERROR;
+ pat++;
+ last = buf;
+ *buf++ = NOT_LITERAL;
+ *buf++ = c;
+ min_length++;
+ break;
+#endif
+ case 'd': /* slang extension */
+ last = buf;
+ *buf++ = ANY_DIGIT;
+ min_length++;
+ break;
+
+ case '<':
+ last = NULL;
+ *buf++ = BOW;
+ break;
+
+ case '>':
+ last = NULL;
+ *buf++ = EOW;
+ break;
+
+ case '{':
+ if (last == NULL) goto literal_char;
+ *last |= MANY;
+ tmppat = convert_digit(pat, &n);
+ if (tmppat == NULL) ERROR;
+ pat = tmppat;
+ *buf++ = n;
+
+ min_length += (n - 1);
+
+ if (*pat == '\\')
+ {
+ *buf++ = n;
+ }
+ else if (*pat == ',')
+ {
+ pat++;
+ if (*pat == '\\')
+ {
+ n = 255;
+ }
+ else
+ {
+ tmppat = convert_digit(pat, &n);
+ if (tmppat == NULL) ERROR;
+ pat = tmppat;
+ if (*pat != '\\') ERROR;
+ }
+ *buf++ = n;
+ }
+ else ERROR;
+ last = NULL;
+ pat++;
+ if (*pat != '}') ERROR;
+ pat++;
+ break; /* case '{' */
+
+ case '(':
+ oparen++;
+ if (oparen > 9) ERROR;
+ *buf++ = OPAREN;
+ break;
+ case ')':
+ if (oparen == 0) ERROR;
+ oparen--;
+ nparen++;
+ *buf++ = CPAREN;
+ break;
+
+ case 0: ERROR;
+ default:
+ goto literal_char;
+ }
+ break;
+
+ case '[':
+
+ *buf = RANGE;
+ last = buf++;
+
+ if (buf + 32 >= ebuf) ERROR;
+
+ for (i = 0; i < 32; i++) buf[i] = 0;
+ c = *pat++;
+ if (c == '^')
+ {
+ reverse = 1;
+ SET_BIT(buf, '\n');
+ c = *pat++;
+ }
+
+ if (c == ']')
+ {
+ SET_BIT(buf, c);
+ c = *pat++;
+ }
+ while (c && (c != ']'))
+ {
+ if (c == '\\')
+ {
+ c = *pat++;
+ switch(c)
+ {
+ case 'n': c = '\n'; break;
+ case 't': c = '\t'; break;
+ case 0: ERROR;
+ }
+ }
+
+ if (*pat == '-')
+ {
+ pat++;
+ while (c < *pat)
+ {
+ if (cs == 0)
+ {
+ SET_BIT(buf, UPPERCASE(c));
+ SET_BIT(buf, LOWERCASE(c));
+ }
+ else SET_BIT(buf, c);
+ c++;
+ }
+ }
+ if (cs == 0)
+ {
+ SET_BIT(buf, UPPERCASE(c));
+ SET_BIT(buf, LOWERCASE(c));
+ }
+ else SET_BIT(buf, c);
+ c = *pat++;
+ }
+ if (c != ']') ERROR;
+ if (reverse) for (i = 0; i < 32; i++) buf[i] = buf[i] ^ 0xFF;
+ reverse = 0;
+ buf += 32;
+ min_length++;
+ break;
+
+ case '.':
+ last = buf;
+ *buf++ = ANY;
+ min_length++;
+ break;
+
+ case '*':
+ if (last == NULL) goto literal_char;
+ *last |= STAR;
+ min_length--;
+ last = NULL;
+ break;
+
+ case '+':
+ if (last == NULL) goto literal_char;
+ *last |= LEAST_ONCE;
+ last = NULL;
+ break;
+
+ case '?':
+ if (last == NULL) goto literal_char;
+ *last |= MAYBE_ONCE;
+ last = NULL;
+ min_length--;
+ break;
+
+ literal_char:
+ default:
+ /* This is to keep track of longest substring */
+ min_length++;
+ this_max_mm++;
+ if (last_count + 1 == count)
+ {
+ if (this_max_mm == 1)
+ {
+ this_mm_p = buf;
+ }
+ else if (max_mm < this_max_mm)
+ {
+ mm_p = this_mm_p;
+ max_mm = this_max_mm;
+ }
+ }
+ else
+ {
+ this_mm_p = buf;
+ this_max_mm = 1;
+ }
+
+ last_count = count;
+
+ last = buf;
+ *buf++ = LITERAL;
+ *buf++ = UPPERCASE(c);
+ }
+ }
+ *buf = 0;
+ /* Check for ordinary search */
+ ebuf = buf;
+ buf = reg->buf;
+
+ if (no_osearch) ordinary_search = 0;
+ else
+ {
+ ordinary_search = 1;
+ while (buf < ebuf)
+ {
+ if (*buf != LITERAL)
+ {
+ ordinary_search = 0;
+ break;
+ }
+ buf += 2;
+ }
+ }
+
+ reg->osearch = ordinary_search;
+ reg->must_match_str[15] = 0;
+ reg->min_length = (min_length > 0) ? (unsigned int) min_length : 0;
+ if (ordinary_search)
+ {
+ strncpy((char *) reg->must_match_str, (char *) reg->pat, 15);
+ reg->must_match = 1;
+ return(0);
+ }
+ /* check for longest substring of pattern */
+ reg->must_match = 0;
+ if ((mm_p == NULL) && (this_mm_p != NULL)) mm_p = this_mm_p;
+ if (mm_p == NULL)
+ {
+ return (0);
+ }
+ n = 15;
+ pat = reg->must_match_str;
+ buf = mm_p;
+ while (n--)
+ {
+ if (*buf++ != LITERAL) break;
+ *pat++ = *buf++;
+ }
+ *pat = 0;
+ if (pat != reg->must_match_str) reg->must_match = 1;
+ return(0);
+}
+
+char *SLregexp_quote_string (char *re, char *buf, unsigned int buflen)
+{
+ char ch;
+ char *b, *bmax;
+
+ if (re == NULL) return NULL;
+
+ b = buf;
+ bmax = buf + buflen;
+
+ while (b < bmax)
+ {
+ switch (ch = *re++)
+ {
+ case 0:
+ *b = 0;
+ return buf;
+
+ case '$':
+ case '\\':
+ case '[':
+ case ']':
+ case '.':
+ case '^':
+ case '*':
+ case '+':
+ case '?':
+ *b++ = '\\';
+ if (b == bmax) break;
+ /* drop */
+
+ default:
+ *b++ = ch;
+ }
+ }
+ return NULL;
+}
+
+#if 0
+#define MAX_EXP 4096
+int main(int argc, char **argv)
+{
+ FILE *fp;
+ char *regexp, *file;
+ char expbuf[MAX_EXP], buf[512];
+ SLRegexp_Type reg;
+
+ file = argv[2];
+ regexp = argv[1];
+
+ if (NULL == (fp = fopen(file, "r")))
+ {
+ fprintf(stderr, "File not open\n");
+ return(1);
+ }
+
+ reg.buf = expbuf;
+ reg.buf_len = MAX_EXP;
+ reg.pat = regexp;
+ reg.case_sensitive = 1;
+
+ if (!regexp_compile(&reg)) while (NULL != fgets(buf, 511, fp))
+ {
+ if (reg.osearch)
+ {
+ if (NULL == strstr(buf, reg.pat)) continue;
+ }
+ else
+ {
+ if (reg.must_match && (NULL == strstr(buf, reg.must_match_str))) continue;
+ if (0 == regexp_match(buf, buf + strlen(buf), &reg)) continue;
+ }
+
+ fputs(buf, stdout);
+ }
+ return (0);
+}
+#endif
diff --git a/mdk-stage1/slang/slrline.c b/mdk-stage1/slang/slrline.c
new file mode 100644
index 000000000..1874be0bb
--- /dev/null
+++ b/mdk-stage1/slang/slrline.c
@@ -0,0 +1,836 @@
+/* SLang_read_line interface --- uses SLang tty stuff */
+/* Copyright (c) 1992, 1999, 2001 John E. Davis
+ * This file is part of the S-Lang library.
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Perl Artistic License.
+ */
+
+#include "slinclud.h"
+
+#include "slang.h"
+#include "_slang.h"
+
+#ifdef REAL_UNIX_SYSTEM
+int SLang_RL_EOF_Char = 4;
+#else
+int SLang_RL_EOF_Char = 26;
+#endif
+
+int SLang_Rline_Quit;
+static SLang_RLine_Info_Type *This_RLI;
+
+static unsigned char Char_Widths[256];
+static void position_cursor (int);
+
+static void rl_beep (void)
+{
+ putc(7, stdout);
+ fflush (stdout);
+}
+
+/* editing functions */
+static int rl_bol (void)
+{
+ if (This_RLI->point == 0) return 0;
+ This_RLI->point = 0;
+ return 1;
+}
+
+static int rl_eol (void)
+{
+ if (This_RLI->point == This_RLI->len) return 0;
+ This_RLI->point = This_RLI->len;
+ return 1;
+}
+
+static int rl_right (void)
+{
+ if (This_RLI->point == This_RLI->len) return 0;
+ This_RLI->point++;
+ return 1;
+}
+
+static int rl_left (void)
+{
+ if (This_RLI->point == 0) return 0;
+ This_RLI->point--;
+ return 1;
+}
+
+static int rl_self_insert (void)
+{
+ unsigned char *pmin, *p;
+
+ if (This_RLI->len == This_RLI->buf_len)
+ {
+ rl_beep ();
+ return 0;
+ }
+
+ pmin = This_RLI->buf + This_RLI->point;
+ p = This_RLI->buf + This_RLI->len;
+ while (p > pmin)
+ {
+ *p = *(p - 1);
+ p--;
+ }
+ *pmin = SLang_Last_Key_Char;
+
+ This_RLI->len++;
+ This_RLI->point++;
+ if ((This_RLI->curs_pos + 2 >= This_RLI->edit_width)
+ || (This_RLI->tt_insert == NULL)
+ || (Char_Widths[SLang_Last_Key_Char] != 1)) return 1;
+
+ (*This_RLI->tt_insert)((char) SLang_Last_Key_Char);
+ /* update screen buf */
+ p = This_RLI->old_upd + (This_RLI->len - 1);
+ pmin = This_RLI->old_upd + (This_RLI->point - 1);
+ while (p > pmin)
+ {
+ *p = *(p - 1);
+ p--;
+ }
+ *pmin = SLang_Last_Key_Char;
+ return 0;
+}
+
+int SLang_rline_insert (char *s)
+{
+ unsigned char *pmin, *p;
+ int n;
+
+ n = strlen (s);
+ if (n > This_RLI->buf_len - This_RLI->len)
+ n = This_RLI->buf_len - This_RLI->len;
+
+ if (n == 0) return 0;
+
+ pmin = This_RLI->buf + This_RLI->point;
+ p = This_RLI->buf + (This_RLI->len - 1);
+
+ while (p >= pmin)
+ {
+ *(p + n) = *p;
+ p--;
+ }
+ SLMEMCPY ((char *) pmin, s, n);
+
+ This_RLI->len += n;
+ This_RLI->point += n;
+ return n;
+}
+
+static int rl_deln (int n)
+{
+ unsigned char *pmax, *p;
+
+ p = This_RLI->buf + This_RLI->point;
+ pmax = This_RLI->buf + This_RLI->len;
+
+ if (p + n > pmax) n = (int) (pmax - p);
+ while (p < pmax)
+ {
+ *p = *(p + n);
+ p++;
+ }
+ This_RLI->len -= n;
+ return n;
+}
+
+static int rl_del (void)
+{
+ return rl_deln(1);
+}
+
+static int rl_quote_insert (void)
+{
+ int err = SLang_Error;
+ SLang_Error = 0;
+ SLang_Last_Key_Char = (*This_RLI->getkey)();
+ rl_self_insert ();
+ if (SLang_Error == SL_USER_BREAK) SLang_Error = 0;
+ else SLang_Error = err;
+ return 1;
+}
+
+static int rl_trim (void)
+{
+ unsigned char *p, *pmax, *p1;
+ p = This_RLI->buf + This_RLI->point;
+ pmax = This_RLI->buf + This_RLI->len;
+
+ if (p == pmax)
+ {
+ if (p == This_RLI->buf) return 0;
+ p--;
+ }
+
+ if ((*p != ' ') && (*p != '\t')) return 0;
+ p1 = p;
+ while ((p1 < pmax) && ((*p1 == ' ') || (*p1 == '\t'))) p1++;
+ pmax = p1;
+ p1 = This_RLI->buf;
+
+ while ((p >= p1) && ((*p == ' ') || (*p == '\t'))) p--;
+ if (p == pmax) return 0;
+ p++;
+
+ This_RLI->point = (int) (p - p1);
+ return rl_deln ((int) (pmax - p));
+}
+
+static int rl_bdel (void)
+{
+ if (rl_left()) return rl_del();
+ return 0;
+}
+
+static int rl_deleol (void)
+{
+ if (This_RLI->point == This_RLI->len) return 0;
+ *(This_RLI->buf + This_RLI->point) = 0;
+ This_RLI->len = This_RLI->point;
+ return 1;
+}
+
+static int rl_delete_line (void)
+{
+ This_RLI->point = 0;
+ *(This_RLI->buf + This_RLI->point) = 0;
+ This_RLI->len = 0;
+ return 1;
+}
+
+static int rl_enter (void)
+{
+ *(This_RLI->buf + This_RLI->len) = 0;
+ SLang_Rline_Quit = 1;
+ return 1;
+}
+
+static SLKeyMap_List_Type *RL_Keymap;
+
+/* This update is designed for dumb terminals. It assumes only that the
+ * terminal can backspace via ^H, and move cursor to start of line via ^M.
+ * There is a hook so the user can provide a more sophisticated update if
+ * necessary.
+ */
+
+static void position_cursor (int col)
+{
+ unsigned char *p, *pmax;
+ int dc;
+
+ if (col == This_RLI->curs_pos)
+ {
+ fflush (stdout);
+ return;
+ }
+
+ if (This_RLI->tt_goto_column != NULL)
+ {
+ (*This_RLI->tt_goto_column)(col);
+ This_RLI->curs_pos = col;
+ fflush (stdout);
+ return;
+ }
+
+ dc = This_RLI->curs_pos - col;
+ if (dc < 0)
+ {
+ p = This_RLI->new_upd + This_RLI->curs_pos;
+ pmax = This_RLI->new_upd + col;
+ while (p < pmax) putc((char) *p++, stdout);
+ }
+ else
+ {
+ if (dc < col)
+ {
+ while (dc--) putc(8, stdout);
+ }
+ else
+ {
+ putc('\r', stdout);
+ p = This_RLI->new_upd;
+ pmax = This_RLI->new_upd + col;
+ while (p < pmax) putc((char) *p++, stdout);
+ }
+ }
+ This_RLI->curs_pos = col;
+ fflush (stdout);
+}
+
+static void erase_eol (SLang_RLine_Info_Type *rli)
+{
+ unsigned char *p, *pmax;
+
+ p = rli->old_upd + rli->curs_pos;
+ pmax = rli->old_upd + rli->old_upd_len;
+
+ while (p++ < pmax) putc(' ', stdout);
+
+ rli->curs_pos = rli->old_upd_len;
+}
+
+static unsigned char *spit_out(SLang_RLine_Info_Type *rli, unsigned char *p)
+{
+ unsigned char *pmax;
+ position_cursor ((int) (p - rli->new_upd));
+ pmax = rli->new_upd + rli->new_upd_len;
+ while (p < pmax) putc((char) *p++, stdout);
+ rli->curs_pos = rli->new_upd_len;
+ return pmax;
+}
+
+static void really_update (SLang_RLine_Info_Type *rli, int new_curs_position)
+{
+ unsigned char *b = rli->old_upd, *p = rli->new_upd, chb, chp;
+ unsigned char *pmax;
+
+ if (rli->update_hook != NULL)
+ {
+ (*rli->update_hook)(p, rli->edit_width, new_curs_position);
+ }
+ else
+ {
+ pmax = p + rli->edit_width;
+ while (p < pmax)
+ {
+ chb = *b++; chp = *p++;
+ if (chb == chp) continue;
+
+ if (rli->old_upd_len <= rli->new_upd_len)
+ {
+ /* easy one */
+ (void) spit_out (rli, p - 1);
+ break;
+ }
+ spit_out(rli, p - 1);
+ erase_eol (rli);
+ break;
+ }
+ position_cursor (new_curs_position);
+ }
+
+ /* update finished, so swap */
+
+ rli->old_upd_len = rli->new_upd_len;
+ p = rli->old_upd;
+ rli->old_upd = rli->new_upd;
+ rli->new_upd = p;
+}
+
+static void RLupdate (SLang_RLine_Info_Type *rli)
+{
+ int len, dlen, start_len = 0, prompt_len = 0, tw = 0, count;
+ int want_cursor_pos;
+ unsigned char *b, chb, *b_point, *p;
+ int no_echo;
+
+ no_echo = rli->flags & SL_RLINE_NO_ECHO;
+
+ b_point = (unsigned char *) (rli->buf + rli->point);
+ *(rli->buf + rli->len) = 0;
+
+ /* expand characters for output buffer --- handle prompt first.
+ * Do two passes --- first to find out where to begin upon horiz
+ * scroll and the second to actually fill the buffer. */
+ len = 0;
+ count = 2; /* once for prompt and once for buf */
+
+ b = (unsigned char *) rli->prompt;
+ while (count--)
+ {
+ if ((count == 0) && no_echo)
+ break;
+
+ /* The prompt could be NULL */
+ if (b != NULL) while ((chb = *b) != 0)
+ {
+ /* This will ensure that the screen is scrolled a third of the edit
+ * width each time */
+ if (b_point == b) break;
+ dlen = Char_Widths[chb];
+ if ((chb == '\t') && tw)
+ {
+ dlen = tw * ((len - prompt_len) / tw + 1) - (len - prompt_len);
+ }
+ len += dlen;
+ b++;
+ }
+ tw = rli->tab;
+ b = (unsigned char *) rli->buf;
+ if (count == 1) want_cursor_pos = prompt_len = len;
+ }
+
+ if (len < rli->edit_width - rli->dhscroll) start_len = 0;
+ else if ((rli->start_column > len)
+ || (rli->start_column + rli->edit_width <= len))
+ {
+ start_len = len - (rli->edit_width - rli->dhscroll);
+ if (start_len < 0) start_len = 0;
+ }
+ else start_len = rli->start_column;
+ rli->start_column = start_len;
+
+ want_cursor_pos = len - start_len;
+
+ /* second pass */
+ p = rli->new_upd;
+
+ len = 0;
+ count = 2;
+ b = (unsigned char *) rli->prompt;
+ if (b == NULL) b = (unsigned char *) "";
+
+ while ((len < start_len) && (*b))
+ {
+ len += Char_Widths[*b++];
+ }
+
+ tw = 0;
+ if (*b == 0)
+ {
+ b = (unsigned char *) rli->buf;
+ while (len < start_len)
+ {
+ len += Char_Widths[*b++];
+ }
+ tw = rli->tab;
+ count--;
+ }
+
+ len = 0;
+ while (count--)
+ {
+ if ((count == 0) && (no_echo))
+ break;
+
+ while ((len < rli->edit_width) && ((chb = *b++) != 0))
+ {
+ dlen = Char_Widths[chb];
+ if (dlen == 1) *p++ = chb;
+ else
+ {
+ if ((chb == '\t') && tw)
+ {
+ dlen = tw * ((len + start_len - prompt_len) / tw + 1) - (len + start_len - prompt_len);
+ len += dlen; /* ok since dlen comes out 0 */
+ if (len > rli->edit_width) dlen = len - rli->edit_width;
+ while (dlen--) *p++ = ' ';
+ dlen = 0;
+ }
+ else
+ {
+ if (dlen == 3)
+ {
+ chb &= 0x7F;
+ *p++ = '~';
+ }
+
+ *p++ = '^';
+ if (chb == 127) *p++ = '?';
+ else *p++ = chb + '@';
+ }
+ }
+ len += dlen;
+ }
+ /* if (start_len > prompt_len) break; */
+ tw = rli->tab;
+ b = (unsigned char *) rli->buf;
+ }
+
+ rli->new_upd_len = (int) (p - rli->new_upd);
+ while (p < rli->new_upd + rli->edit_width) *p++ = ' ';
+ really_update (rli, want_cursor_pos);
+}
+
+void SLrline_redraw (SLang_RLine_Info_Type *rli)
+{
+ unsigned char *p = rli->new_upd;
+ unsigned char *pmax = p + rli->edit_width;
+ while (p < pmax) *p++ = ' ';
+ rli->new_upd_len = rli->edit_width;
+ really_update (rli, 0);
+ RLupdate (rli);
+}
+
+static int rl_eof_insert (void)
+{
+ if (This_RLI->len == 0)
+ {
+ SLang_Last_Key_Char = SLang_RL_EOF_Char;
+ /* rl_self_insert (); */
+ return rl_enter ();
+ }
+ return 0;
+}
+
+/* This is very naive. It knows very little about nesting and nothing
+ * about quoting.
+ */
+static void blink_match (SLang_RLine_Info_Type *rli)
+{
+ unsigned char bra, ket;
+ unsigned int delta_column;
+ unsigned char *p, *pmin;
+ int dq_level, sq_level;
+ int level;
+
+ pmin = rli->buf;
+ p = pmin + rli->point;
+ if (pmin == p)
+ return;
+
+ ket = SLang_Last_Key_Char;
+ switch (ket)
+ {
+ case ')':
+ bra = '(';
+ break;
+ case ']':
+ bra = '[';
+ break;
+ case '}':
+ bra = '{';
+ break;
+ default:
+ return;
+ }
+
+ level = 0;
+ sq_level = dq_level = 0;
+
+ delta_column = 0;
+ while (p > pmin)
+ {
+ char ch;
+
+ p--;
+ delta_column++;
+ ch = *p;
+
+ if (ch == ket)
+ {
+ if ((dq_level == 0) && (sq_level == 0))
+ level++;
+ }
+ else if (ch == bra)
+ {
+ if ((dq_level != 0) || (sq_level != 0))
+ continue;
+
+ level--;
+ if (level == 0)
+ {
+ rli->point -= delta_column;
+ RLupdate (rli);
+ (*rli->input_pending)(10);
+ rli->point += delta_column;
+ RLupdate (rli);
+ break;
+ }
+ if (level < 0)
+ break;
+ }
+ else if (ch == '"') dq_level = !dq_level;
+ else if (ch == '\'') sq_level = !sq_level;
+ }
+}
+
+int SLang_read_line (SLang_RLine_Info_Type *rli)
+{
+ unsigned char *p, *pmax;
+ SLang_Key_Type *key;
+
+ SLang_Rline_Quit = 0;
+ This_RLI = rli;
+ p = rli->old_upd; pmax = p + rli->edit_width;
+ while (p < pmax) *p++ = ' ';
+
+ /* Sanity checking */
+ rli->len = strlen ((char *) rli->buf);
+ if (rli->len >= rli->buf_len)
+ {
+ rli->len = 0;
+ *rli->buf = 0;
+ }
+ if (rli->point > rli->len) rli->point = rli->len;
+ if (rli->point < 0) rli->point = 0;
+
+ rli->curs_pos = rli->start_column = 0;
+ rli->new_upd_len = rli->old_upd_len = 0;
+
+ This_RLI->last_fun = NULL;
+ if (rli->update_hook == NULL)
+ putc ('\r', stdout);
+
+ RLupdate (rli);
+
+ while (1)
+ {
+ key = SLang_do_key (RL_Keymap, (int (*)(void)) rli->getkey);
+
+ if ((key == NULL) || (key->f.f == NULL))
+ rl_beep ();
+ else
+ {
+ if ((SLang_Last_Key_Char == SLang_RL_EOF_Char)
+ && (*key->str == 2)
+ && (This_RLI->len == 0))
+ rl_eof_insert ();
+ else if (key->type == SLKEY_F_INTRINSIC)
+ {
+ if ((key->f.f)())
+ RLupdate (rli);
+
+ if ((rli->flags & SL_RLINE_BLINK_MATCH)
+ && (rli->input_pending != NULL))
+ blink_match (rli);
+ }
+
+ if (SLang_Rline_Quit)
+ {
+ This_RLI->buf[This_RLI->len] = 0;
+ if (SLang_Error == SL_USER_BREAK)
+ {
+ SLang_Error = 0;
+ return -1;
+ }
+ return This_RLI->len;
+ }
+ }
+ if (key != NULL)
+ This_RLI->last_fun = key->f.f;
+ }
+}
+
+static int rl_abort (void)
+{
+ rl_delete_line ();
+ return rl_enter ();
+}
+
+/* TTY interface --- ANSI */
+
+static void ansi_goto_column (int n)
+{
+ putc('\r', stdout);
+ if (n) fprintf(stdout, "\033[%dC", n);
+}
+
+static void rl_select_line (SLang_Read_Line_Type *p)
+{
+ This_RLI->last = p;
+ strcpy ((char *) This_RLI->buf, (char *) p->buf);
+ This_RLI->point = This_RLI->len = strlen((char *) p->buf);
+}
+static int rl_next_line (void);
+static int rl_prev_line (void)
+{
+ SLang_Read_Line_Type *prev;
+
+ if (((This_RLI->last_fun != (FVOID_STAR) rl_prev_line)
+ && (This_RLI->last_fun != (FVOID_STAR) rl_next_line))
+ || (This_RLI->last == NULL))
+ {
+ prev = This_RLI->tail;
+ }
+ else prev = This_RLI->last->prev;
+
+ if (prev == NULL)
+ {
+ rl_beep ();
+ return 0;
+ }
+
+ rl_select_line (prev);
+ return 1;
+}
+static int rl_redraw (void)
+{
+ SLrline_redraw (This_RLI);
+ return 1;
+}
+
+static int rl_next_line (void)
+{
+ SLang_Read_Line_Type *next;
+
+ if (((This_RLI->last_fun != (FVOID_STAR) rl_prev_line)
+ && (This_RLI->last_fun != (FVOID_STAR) rl_next_line))
+ || (This_RLI->last == NULL))
+ {
+ rl_beep ();
+ return 0;
+ }
+
+ next = This_RLI->last->next;
+
+ if (next == NULL)
+ {
+ This_RLI->len = This_RLI->point = 0;
+ *This_RLI->buf = 0;
+ This_RLI->last = NULL;
+ }
+ else rl_select_line (next);
+ return 1;
+}
+
+static SLKeymap_Function_Type SLReadLine_Functions[] =
+{
+ {"up", rl_prev_line},
+ {"down", rl_next_line},
+ {"bol", rl_bol},
+ {"eol", rl_eol},
+ {"right", rl_right},
+ {"left", rl_left},
+ {"self_insert", rl_self_insert},
+ {"bdel", rl_bdel},
+ {"del", rl_del},
+ {"deleol", rl_deleol},
+ {"enter", rl_enter},
+ {"trim", rl_trim},
+ {"quoted_insert", rl_quote_insert},
+ {(char *) NULL, NULL}
+};
+
+int SLang_init_readline (SLang_RLine_Info_Type *rli)
+{
+ int ch;
+ char simple[2];
+
+ if (RL_Keymap == NULL)
+ {
+ simple[1] = 0;
+ if (NULL == (RL_Keymap = SLang_create_keymap ("ReadLine", NULL)))
+ return -1;
+
+ RL_Keymap->functions = SLReadLine_Functions;
+
+ /* This breaks under some DEC ALPHA compilers (scary!) */
+#ifndef __DECC
+ for (ch = ' '; ch < 256; ch++)
+ {
+ simple[0] = (char) ch;
+ SLkm_define_key (simple, (FVOID_STAR) rl_self_insert, RL_Keymap);
+ }
+#else
+ ch = ' ';
+ while (1)
+ {
+ simple[0] = (char) ch;
+ SLkm_define_key (simple, (FVOID_STAR) rl_self_insert, RL_Keymap);
+ ch = ch + 1;
+ if (ch == 256) break;
+ }
+#endif /* NOT __DECC */
+
+ simple[0] = SLang_Abort_Char;
+ SLkm_define_key (simple, (FVOID_STAR) rl_abort, RL_Keymap);
+ simple[0] = SLang_RL_EOF_Char;
+ SLkm_define_key (simple, (FVOID_STAR) rl_eof_insert, RL_Keymap);
+
+#ifndef IBMPC_SYSTEM
+ SLkm_define_key ("^[[A", (FVOID_STAR) rl_prev_line, RL_Keymap);
+ SLkm_define_key ("^[[B", (FVOID_STAR) rl_next_line, RL_Keymap);
+ SLkm_define_key ("^[[C", (FVOID_STAR) rl_right, RL_Keymap);
+ SLkm_define_key ("^[[D", (FVOID_STAR) rl_left, RL_Keymap);
+ SLkm_define_key ("^[OA", (FVOID_STAR) rl_prev_line, RL_Keymap);
+ SLkm_define_key ("^[OB", (FVOID_STAR) rl_next_line, RL_Keymap);
+ SLkm_define_key ("^[OC", (FVOID_STAR) rl_right, RL_Keymap);
+ SLkm_define_key ("^[OD", (FVOID_STAR) rl_left, RL_Keymap);
+#else
+ SLkm_define_key ("^@H", (FVOID_STAR) rl_prev_line, RL_Keymap);
+ SLkm_define_key ("^@P", (FVOID_STAR) rl_next_line, RL_Keymap);
+ SLkm_define_key ("^@M", (FVOID_STAR) rl_right, RL_Keymap);
+ SLkm_define_key ("^@K", (FVOID_STAR) rl_left, RL_Keymap);
+ SLkm_define_key ("^@S", (FVOID_STAR) rl_del, RL_Keymap);
+ SLkm_define_key ("^@O", (FVOID_STAR) rl_eol, RL_Keymap);
+ SLkm_define_key ("^@G", (FVOID_STAR) rl_bol, RL_Keymap);
+
+ SLkm_define_key ("\xE0H", (FVOID_STAR) rl_prev_line, RL_Keymap);
+ SLkm_define_key ("\xE0P", (FVOID_STAR) rl_next_line, RL_Keymap);
+ SLkm_define_key ("\xE0M", (FVOID_STAR) rl_right, RL_Keymap);
+ SLkm_define_key ("\xE0K", (FVOID_STAR) rl_left, RL_Keymap);
+ SLkm_define_key ("\xE0S", (FVOID_STAR) rl_del, RL_Keymap);
+ SLkm_define_key ("\xE0O", (FVOID_STAR) rl_eol, RL_Keymap);
+ SLkm_define_key ("\xE0G", (FVOID_STAR) rl_bol, RL_Keymap);
+#endif
+ SLkm_define_key ("^C", (FVOID_STAR) rl_abort, RL_Keymap);
+ SLkm_define_key ("^E", (FVOID_STAR) rl_eol, RL_Keymap);
+ SLkm_define_key ("^G", (FVOID_STAR) rl_abort, RL_Keymap);
+ SLkm_define_key ("^I", (FVOID_STAR) rl_self_insert, RL_Keymap);
+ SLkm_define_key ("^A", (FVOID_STAR) rl_bol, RL_Keymap);
+ SLkm_define_key ("\r", (FVOID_STAR) rl_enter, RL_Keymap);
+ SLkm_define_key ("\n", (FVOID_STAR) rl_enter, RL_Keymap);
+ SLkm_define_key ("^K", (FVOID_STAR) rl_deleol, RL_Keymap);
+ SLkm_define_key ("^L", (FVOID_STAR) rl_deleol, RL_Keymap);
+ SLkm_define_key ("^V", (FVOID_STAR) rl_del, RL_Keymap);
+ SLkm_define_key ("^D", (FVOID_STAR) rl_del, RL_Keymap);
+ SLkm_define_key ("^F", (FVOID_STAR) rl_right, RL_Keymap);
+ SLkm_define_key ("^B", (FVOID_STAR) rl_left, RL_Keymap);
+ SLkm_define_key ("^?", (FVOID_STAR) rl_bdel, RL_Keymap);
+ SLkm_define_key ("^H", (FVOID_STAR) rl_bdel, RL_Keymap);
+ SLkm_define_key ("^P", (FVOID_STAR) rl_prev_line, RL_Keymap);
+ SLkm_define_key ("^N", (FVOID_STAR) rl_next_line, RL_Keymap);
+ SLkm_define_key ("^R", (FVOID_STAR) rl_redraw, RL_Keymap);
+ SLkm_define_key ("`", (FVOID_STAR) rl_quote_insert, RL_Keymap);
+ SLkm_define_key ("\033\\", (FVOID_STAR) rl_trim, RL_Keymap);
+ if (SLang_Error) return -1;
+ }
+
+ if (rli->prompt == NULL) rli->prompt = "";
+ if (rli->keymap == NULL) rli->keymap = RL_Keymap;
+ rli->old_upd = rli->upd_buf1;
+ rli->new_upd = rli->upd_buf2;
+ *rli->buf = 0;
+ rli->point = 0;
+
+ if (rli->flags & SL_RLINE_USE_ANSI)
+ {
+ if (rli->tt_goto_column == NULL) rli->tt_goto_column = ansi_goto_column;
+ }
+
+ if (Char_Widths[0] == 2) return 0;
+
+ for (ch = 0; ch < 32; ch++) Char_Widths[ch] = 2;
+ for (ch = 32; ch < 256; ch++) Char_Widths[ch] = 1;
+ Char_Widths[127] = 2;
+#ifndef IBMPC_SYSTEM
+ for (ch = 128; ch < 160; ch++) Char_Widths[ch] = 3;
+#endif
+
+ return 0;
+}
+
+SLang_Read_Line_Type *SLang_rline_save_line (SLang_RLine_Info_Type *rli)
+{
+ SLang_Read_Line_Type *rl = NULL;
+ unsigned char *buf;
+
+ if ((rli == NULL) || (rli->buf == NULL))
+ return NULL;
+
+ if (NULL == (rl = (SLang_Read_Line_Type *) SLmalloc (sizeof (SLang_Read_Line_Type)))
+ || (NULL == (buf = (unsigned char *) SLmake_string ((char *)rli->buf))))
+ {
+ SLfree ((char *)rl);
+ return NULL;
+ }
+ rl->buf = buf;
+ rl->buf_len = strlen ((char *)buf);
+ rl->num = rl->misc = 0;
+ rl->next = rl->prev = NULL;
+
+ if (rli->tail != NULL)
+ {
+ rli->tail->next = rl;
+ rl->prev = rli->tail;
+ }
+ rli->tail = rl;
+
+ return rl;
+}
diff --git a/mdk-stage1/slang/slscanf.c b/mdk-stage1/slang/slscanf.c
new file mode 100644
index 000000000..5bd93ff41
--- /dev/null
+++ b/mdk-stage1/slang/slscanf.c
@@ -0,0 +1,718 @@
+/* sscanf function for S-Lang */
+/* Copyright (c) 1999, 2001 John E. Davis
+ * This file is part of the S-Lang library.
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Perl Artistic License.
+ */
+
+#include "slinclud.h"
+#include <ctype.h>
+#include <math.h>
+#include <errno.h>
+
+#include "slang.h"
+#include "_slang.h"
+
+static char *skip_whitespace (char *s)
+{
+ while (isspace (*s))
+ s++;
+
+ return s;
+}
+
+static void init_map (unsigned char map[256], int base)
+{
+ memset ((char *) map, 0xFF, 256);
+
+ map['0'] = 0; map['1'] = 1; map['2'] = 2; map['3'] = 3;
+ map['4'] = 4; map['5'] = 5; map['6'] = 6; map['7'] = 7;
+ if (base == 8)
+ return;
+
+ map['8'] = 8; map['9'] = 9;
+ if (base == 10)
+ return;
+
+ map['A'] = 10; map['B'] = 11; map['C'] = 12; map['D'] = 13;
+ map['E'] = 14; map['F'] = 15; map['a'] = 10; map['b'] = 11;
+ map['c'] = 12; map['d'] = 13; map['e'] = 14; map['f'] = 15;
+}
+
+static char *get_sign (char *s, char *smax, int *sign)
+{
+ *sign = 1;
+ if (s + 1 < smax)
+ {
+ if (*s == '+') s++;
+ else if (*s == '-')
+ {
+ s++;
+ *sign = -1;
+ }
+ }
+ return s;
+}
+
+
+static int parse_long (char **sp, char *smax, long *np,
+ long base, unsigned char map[256])
+{
+ char *s, *s0;
+ long n;
+ int sign;
+
+ s = s0 = get_sign (*sp, smax, &sign);
+
+ n = 0;
+ while (s < smax)
+ {
+ unsigned char value;
+
+ value = map [(unsigned char) *s];
+ if (value == 0xFF)
+ break;
+
+ n = base * n + value;
+ s++;
+ }
+
+ *sp = s;
+ if (s == s0)
+ return 0;
+
+ *np = n * sign;
+
+ return 1;
+}
+
+
+static int parse_int (char **sp, char *smax, int *np,
+ long base, unsigned char map[256])
+{
+ long n;
+ int status;
+
+ if (1 == (status = parse_long (sp, smax, &n, base, map)))
+ *np = (int) n;
+ return status;
+}
+
+static int parse_short (char **sp, char *smax, short *np,
+ long base, unsigned char map[256])
+{
+ long n;
+ int status;
+
+ if (1 == (status = parse_long (sp, smax, &n, base, map)))
+ *np = (short) n;
+ return status;
+}
+
+static int parse_ulong (char **sp, char *smax, unsigned long *np,
+ long base, unsigned char map[256])
+{
+ return parse_long (sp, smax, (long *) np, base, map);
+}
+
+static int parse_uint (char **sp, char *smax, unsigned int *np,
+ long base, unsigned char map[256])
+{
+ return parse_int (sp, smax, (int *) np, base, map);
+}
+
+static int parse_ushort (char **sp, char *smax, unsigned short *np,
+ long base, unsigned char map[256])
+{
+ return parse_short (sp, smax, (short *) np, base, map);
+}
+
+#if SLANG_HAS_FLOAT
+/*
+ * In an ideal world, strtod would be the correct function to use. However,
+ * there may be problems relying on this function because some systems do
+ * not support and some that do get it wrong. So, I will handle the parsing
+ * of the string and let atof or strtod handle the arithmetic.
+ */
+static int parse_double (char **sp, char *smax, double *d)
+{
+ char *s, *s0;
+ int sign;
+ int expon;
+ unsigned char map[256];
+ char buf[128];
+ int has_leading_zeros;
+ char *start_pos, *sign_pos;
+ char *b, *bmax;
+
+ start_pos = *sp;
+ s = get_sign (start_pos, smax, &sign);
+ if (s >= smax)
+ {
+ errno = _SLerrno_errno = EINVAL;
+ return 0;
+ }
+
+ /* Prepare the buffer that will be passed to strtod */
+ /* Allow the exponent to be 5 significant digits: E+xxxxx\0 */
+ bmax = buf + (sizeof (buf) - 8);
+ buf[0] = '0'; buf[1] = '.';
+ b = buf + 2;
+
+ init_map (map, 10);
+
+ /* Skip leading 0s */
+ s0 = s;
+ while ((s < smax) && (*s == '0'))
+ s++;
+ has_leading_zeros = (s != s0);
+
+ expon = 0;
+ while (s < smax)
+ {
+ unsigned char value = map [(unsigned char) *s];
+
+ if (value == 0xFF)
+ break;
+
+ if (b < bmax)
+ *b++ = *s;
+
+ expon++;
+ s++;
+ }
+
+ if ((s < smax) && (*s == '.'))
+ {
+ s++;
+ if (b == buf + 2) /* nothing added yet */
+ {
+ while ((s < smax) && (*s == '0'))
+ {
+ expon--;
+ s++;
+ }
+ }
+
+ while (s < smax)
+ {
+ unsigned char value = map [(unsigned char) *s];
+
+ if (value == 0xFF)
+ break;
+
+ if (b < bmax)
+ *b++ = *s;
+ s++;
+ }
+ }
+
+ if ((b == buf + 2)
+ && (has_leading_zeros == 0))
+ {
+ *sp = start_pos;
+ errno = EINVAL;
+ return 0;
+ }
+
+ if ((s + 1 < smax) && ((*s == 'E') || (*s == 'e')))
+ {
+ int e;
+ int esign;
+
+ s0 = s;
+ s = get_sign (s + 1, smax, &esign);
+ sign_pos = s;
+ e = 0;
+ while (s < smax)
+ {
+ unsigned char value = map [(unsigned char) *s];
+ if (value == 0xFF)
+ break;
+ if (e < 25000) /* avoid overflow if 16 bit */
+ e = 10 * e + value;
+ s++;
+ }
+#ifdef ERANGE
+ if (e >= 25000)
+ errno = ERANGE;
+#endif
+ if (s == sign_pos)
+ s = s0; /* ...E-X */
+ else
+ {
+ e = esign * e;
+ expon += e;
+ }
+ }
+
+ if (expon != 0)
+ sprintf (b, "e%d", expon);
+ else
+ *b = 0;
+
+ *sp = s;
+#if HAVE_STRTOD
+ *d = sign * strtod (buf, NULL);
+#else
+ *d = sign * atof (buf);
+#endif
+ return 1;
+}
+
+static int parse_float (char **sp, char *smax, float *d)
+{
+ double x;
+ if (1 == parse_double (sp, smax, &x))
+ {
+ *d = (float) x;
+ return 1;
+ }
+ return 0;
+}
+#endif /* SLANG_HAS_FLOAT */
+
+static int parse_string (char **sp, char *smax, char **str)
+{
+ char *s, *s0;
+
+ s0 = s = *sp;
+ while (s < smax)
+ {
+ if (isspace (*s))
+ break;
+ s++;
+ }
+ if (NULL == (*str = SLang_create_nslstring (s0, (unsigned int) (s - s0))))
+ return -1;
+
+ *sp = s;
+ return 1;
+}
+
+static int parse_bstring (char **sp, char *smax, char **str)
+{
+ char *s;
+
+ s = *sp;
+ if (NULL == (*str = SLang_create_nslstring (s, (unsigned int) (smax - s))))
+ return -1;
+
+ *sp = smax;
+ return 1;
+}
+
+static int parse_range (char **sp, char *smax, char **fp, char **str)
+{
+ char *s, *s0;
+ char *range;
+ char *f;
+ unsigned char map[256];
+ unsigned char reverse;
+
+ /* How can one represent a range with just '^'? The naive answer is
+ * is [^]. However, this may be interpreted as meaning any character
+ * but ']' and others. Let's assume that the user will not use a range
+ * to match '^'.
+ */
+ f = *fp;
+ /* f is a pointer to (one char after) [...]. */
+ if (*f == '^')
+ {
+ f++;
+ reverse = 1;
+ }
+ else reverse = 0;
+
+ s0 = f;
+ if (*f == ']')
+ f++;
+
+ while (1)
+ {
+ char ch = *f;
+
+ if (ch == 0)
+ {
+ SLang_verror (SL_INVALID_PARM, "Unexpected end of range in format");
+ return -1;
+ }
+ if (ch == ']')
+ break;
+ f++;
+ }
+ if (NULL == (range = SLmake_nstring (s0, (unsigned int) (f - s0))))
+ return -1;
+ *fp = f + 1; /* skip ] */
+
+ SLmake_lut (map, (unsigned char *) range, reverse);
+ SLfree (range);
+
+ s0 = s = *sp;
+ while ((s < smax) && map [(unsigned char) *s])
+ s++;
+
+ if (NULL == (*str = SLang_create_nslstring (s0, (unsigned int) (s - s0))))
+ return -1;
+
+ *sp = s;
+ return 1;
+}
+
+
+int _SLang_sscanf (void)
+{
+ int num;
+ unsigned int num_refs;
+ char *format;
+ char *input_string, *input_string_max;
+ char *f, *s;
+ unsigned char map8[256], map10[256], map16[256];
+
+ if (SLang_Num_Function_Args < 2)
+ {
+ SLang_verror (SL_INVALID_PARM, "Int_Type sscanf (str, format, ...)");
+ return -1;
+ }
+
+ num_refs = (unsigned int) SLang_Num_Function_Args;
+ if (-1 == SLreverse_stack (num_refs))
+ return -1;
+ num_refs -= 2;
+
+ if (-1 == SLang_pop_slstring (&input_string))
+ return -1;
+
+ if (-1 == SLang_pop_slstring (&format))
+ {
+ SLang_free_slstring (input_string);
+ return -1;
+ }
+
+ f = format;
+ s = input_string;
+ input_string_max = input_string + strlen (input_string);
+
+ init_map (map8, 8);
+ init_map (map10, 10);
+ init_map (map16, 16);
+
+ num = 0;
+
+ while (num_refs != 0)
+ {
+ SLang_Object_Type obj;
+ SLang_Ref_Type *ref;
+ char *smax;
+ unsigned char *map;
+ int base;
+ int no_assign;
+ int is_short;
+ int is_long;
+ int status;
+ char chf;
+ unsigned int width;
+ int has_width;
+
+ chf = *f++;
+
+ if (chf == 0)
+ {
+ /* Hmmm.... what is the most useful thing to do?? */
+#if 1
+ break;
+#else
+ SLang_verror (SL_INVALID_PARM, "sscanf: format not big enough for output list");
+ goto return_error;
+#endif
+ }
+
+ if (isspace (chf))
+ {
+ s = skip_whitespace (s);
+ continue;
+ }
+
+ if ((chf != '%')
+ || ((chf = *f++) == '%'))
+ {
+ if (*s != chf)
+ break;
+ s++;
+ continue;
+ }
+
+ no_assign = 0;
+ is_short = 0;
+ is_long = 0;
+ width = 0;
+ smax = input_string_max;
+
+ /* Look for the flag character */
+ if (chf == '*')
+ {
+ no_assign = 1;
+ chf = *f++;
+ }
+
+ /* Width */
+ has_width = isdigit (chf);
+ if (has_width)
+ {
+ f--;
+ (void) parse_uint (&f, f + strlen(f), &width, 10, map10);
+ chf = *f++;
+ }
+
+ /* Now the type modifier */
+ switch (chf)
+ {
+ case 'h':
+ is_short = 1;
+ chf = *f++;
+ break;
+
+ case 'L': /* not implemented */
+ case 'l':
+ is_long = 1;
+ chf = *f++;
+ break;
+ }
+
+ status = -1;
+
+ if ((chf != 'c') && (chf != '['))
+ s = skip_whitespace (s);
+
+ if (has_width)
+ {
+ if (width > (unsigned int) (input_string_max - s))
+ width = (unsigned int) (input_string_max - s);
+ smax = s + width;
+ }
+
+ /* Now the format descriptor */
+
+ map = map10;
+ base = 10;
+
+ try_again: /* used by i, x, and o, conversions */
+ switch (chf)
+ {
+ case 0:
+ SLang_verror (SL_INVALID_PARM, "sscanf: Unexpected end of format");
+ goto return_error;
+ case 'D':
+ is_long = 1;
+ case 'd':
+ if (is_short)
+ {
+ obj.data_type = SLANG_SHORT_TYPE;
+ status = parse_short (&s, smax, &obj.v.short_val, base, map);
+ }
+ else if (is_long)
+ {
+ obj.data_type = SLANG_LONG_TYPE;
+ status = parse_long (&s, smax, &obj.v.long_val, base, map);
+ }
+ else
+ {
+ obj.data_type = SLANG_INT_TYPE;
+ status = parse_int (&s, smax, &obj.v.int_val, base, map);
+ }
+ break;
+
+
+ case 'U':
+ is_long = 1;
+ case 'u':
+ if (is_short)
+ {
+ obj.data_type = SLANG_USHORT_TYPE;
+ status = parse_ushort (&s, smax, &obj.v.ushort_val, base, map);
+ }
+ else if (is_long)
+ {
+ obj.data_type = SLANG_ULONG_TYPE;
+ status = parse_ulong (&s, smax, &obj.v.ulong_val, base, map);
+ }
+ else
+ {
+ obj.data_type = SLANG_INT_TYPE;
+ status = parse_uint (&s, smax, &obj.v.uint_val, base, map);
+ }
+ break;
+
+ case 'I':
+ is_long = 1;
+ case 'i':
+ if ((s + 1 >= smax)
+ || (*s != 0))
+ chf = 'd';
+ else if (((s[1] == 'x') || (s[1] == 'X'))
+ && (s + 2 < smax))
+ {
+ s += 2;
+ chf = 'x';
+ }
+ else chf = 'o';
+ goto try_again;
+
+ case 'O':
+ is_long = 1;
+ case 'o':
+ map = map8;
+ base = 8;
+ chf = 'd';
+ goto try_again;
+
+ case 'X':
+ is_long = 1;
+ case 'x':
+ base = 16;
+ map = map16;
+ chf = 'd';
+ goto try_again;
+
+ case 'E':
+ case 'F':
+ is_long = 1;
+ case 'e':
+ case 'f':
+ case 'g':
+#if SLANG_HAS_FLOAT
+ if (is_long)
+ {
+ obj.data_type = SLANG_DOUBLE_TYPE;
+ status = parse_double (&s, smax, &obj.v.double_val);
+ }
+ else
+ {
+ obj.data_type = SLANG_FLOAT_TYPE;
+ status = parse_float (&s, smax, &obj.v.float_val);
+ }
+#else
+ SLang_verror (SL_NOT_IMPLEMENTED,
+ "This version of the S-Lang does not support floating point");
+ status = -1;
+#endif
+ break;
+
+ case 's':
+ obj.data_type = SLANG_STRING_TYPE;
+ status = parse_string (&s, smax, &obj.v.s_val);
+ break;
+
+ case 'c':
+ if (has_width == 0)
+ {
+ obj.data_type = SLANG_UCHAR_TYPE;
+ obj.v.uchar_val = *s++;
+ status = 1;
+ break;
+ }
+ obj.data_type = SLANG_STRING_TYPE;
+ status = parse_bstring (&s, smax, &obj.v.s_val);
+ break;
+
+ case '[':
+ obj.data_type = SLANG_STRING_TYPE;
+ status = parse_range (&s, smax, &f, &obj.v.s_val);
+ break;
+
+ case 'n':
+ obj.data_type = SLANG_UINT_TYPE;
+ obj.v.uint_val = (unsigned int) (s - input_string);
+ status = 1;
+ break;
+
+ default:
+ status = -1;
+ SLang_verror (SL_NOT_IMPLEMENTED, "format specifier '%c' is not supported", chf);
+ break;
+ }
+
+ if (status == 0)
+ break;
+
+ if (status == -1)
+ goto return_error;
+
+ if (no_assign)
+ {
+ SLang_free_object (&obj);
+ continue;
+ }
+
+ if (-1 == SLang_pop_ref (&ref))
+ {
+ SLang_free_object (&obj);
+ goto return_error;
+ }
+
+ if (-1 == SLang_push (&obj))
+ {
+ SLang_free_object (&obj);
+ SLang_free_ref (ref);
+ goto return_error;
+ }
+
+ if (-1 == _SLang_deref_assign (ref))
+ {
+ SLang_free_ref (ref);
+ goto return_error;
+ }
+ SLang_free_ref (ref);
+
+ num++;
+ num_refs--;
+ }
+
+ if (-1 == SLdo_pop_n (num_refs))
+ goto return_error;
+
+ SLang_free_slstring (format);
+ SLang_free_slstring (input_string);
+ return num;
+
+ return_error:
+ /* NULLS ok */
+ SLang_free_slstring (format);
+ SLang_free_slstring (input_string);
+ return -1;
+}
+
+
+# if SLANG_HAS_FLOAT
+
+#ifndef HAVE_STDLIB_H
+/* Oh dear. Where is the prototype for atof? If not in stdlib, then
+ * I do not know where. Not in math.h on some systems either.
+ */
+extern double atof ();
+#endif
+
+double _SLang_atof (char *s)
+{
+ double x;
+
+ s = skip_whitespace (s);
+ errno = 0;
+
+ if (1 != parse_double (&s, s + strlen (s), &x))
+ {
+ if ((0 == strcmp ("NaN", s))
+ || (0 == strcmp ("-Inf", s))
+ || (0 == strcmp ("Inf", s)))
+ return atof (s); /* let this deal with it */
+#ifdef EINVAL
+ errno = _SLerrno_errno = EINVAL;
+#endif
+ return 0.0;
+ }
+ if (errno)
+ _SLerrno_errno = errno;
+ return x;
+}
+#endif
diff --git a/mdk-stage1/slang/slscroll.c b/mdk-stage1/slang/slscroll.c
new file mode 100644
index 000000000..358296116
--- /dev/null
+++ b/mdk-stage1/slang/slscroll.c
@@ -0,0 +1,450 @@
+/* SLang Scrolling Window Routines */
+/* Copyright (c) 1996, 1999, 2001 John E. Davis
+ * This file is part of the S-Lang library.
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Perl Artistic License.
+ */
+
+#include "slinclud.h"
+
+#include "slang.h"
+#include "_slang.h"
+
+static void find_window_bottom (SLscroll_Window_Type *win)
+{
+ unsigned int nrows;
+ unsigned int hidden_mask;
+ SLscroll_Type *bot, *cline, *last_bot;
+ unsigned int row;
+
+ nrows = win->nrows;
+ hidden_mask = win->hidden_mask;
+ cline = win->current_line;
+
+ win->window_row = row = 0;
+ last_bot = bot = win->top_window_line;
+
+ while (row < nrows)
+ {
+ if (bot == cline)
+ win->window_row = row;
+
+ last_bot = bot;
+
+ if (bot == NULL)
+ break;
+
+ bot = bot->next;
+
+ if (hidden_mask)
+ {
+ while ((bot != NULL) && (bot->flags & hidden_mask))
+ bot = bot->next;
+ }
+
+ row++;
+ }
+
+ win->bot_window_line = last_bot;
+}
+
+static int find_top_to_recenter (SLscroll_Window_Type *win)
+{
+ unsigned int nrows;
+ unsigned int hidden_mask;
+ SLscroll_Type *prev, *last_prev, *cline;
+
+ nrows = win->nrows;
+ cline = win->current_line;
+ hidden_mask = win->hidden_mask;
+
+ nrows = nrows / 2;
+
+ last_prev = prev = cline;
+
+ while (nrows && (prev != NULL))
+ {
+ nrows--;
+ last_prev = prev;
+ do
+ {
+ prev = prev->prev;
+ }
+ while (hidden_mask
+ && (prev != NULL)
+ && (prev->flags & hidden_mask));
+ }
+
+ if (prev == NULL) prev = last_prev;
+
+ win->top_window_line = prev;
+ find_window_bottom (win);
+
+ return 0;
+}
+
+#define HAS_BORDER_CODE 1
+int SLscroll_find_top (SLscroll_Window_Type *win)
+{
+ unsigned int i;
+ SLscroll_Type *cline, *prev, *next;
+ SLscroll_Type *top_window_line;
+ unsigned int nrows;
+ unsigned int hidden_mask;
+ int scroll_mode;
+ unsigned int border;
+
+ cline = win->current_line;
+ nrows = win->nrows;
+ scroll_mode = win->cannot_scroll;
+ border = win->border;
+ if (scroll_mode == 2)
+ border = 0;
+
+ if ((cline == NULL) || (nrows <= 1))
+ {
+ win->top_window_line = cline;
+ find_window_bottom (win);
+ return 0;
+ }
+
+ hidden_mask = win->hidden_mask;
+
+ /* Note: top_window_line might be a bogus pointer. This means that I cannot
+ * access it unless it really corresponds to a pointer in the buffer.
+ */
+ top_window_line = win->top_window_line;
+
+ if (top_window_line == NULL)
+ return find_top_to_recenter (win);
+
+ /* Chances are that the current line is visible in the window. This means
+ * that the top window line should be above it.
+ */
+ prev = cline;
+
+ i = 0;
+
+ while ((i < nrows) && (prev != NULL))
+ {
+ if (prev == top_window_line)
+ {
+ SLscroll_Type *twl = top_window_line;
+ int dir = 0;
+
+ if (i < border) dir = -1; else if (i + border >= nrows) dir = 1;
+
+ if (dir) while (border)
+ {
+ if (dir < 0) twl = twl->prev;
+ else twl = twl->next;
+
+ if (twl == NULL)
+ {
+ twl = top_window_line;
+ break;
+ }
+ if ((hidden_mask == 0)
+ || (0 == (twl->flags & hidden_mask)))
+ border--;
+ }
+
+ win->top_window_line = twl;
+ find_window_bottom (win);
+ return 0;
+ }
+
+ do
+ {
+ prev = prev->prev;
+ }
+ while (hidden_mask
+ && (prev != NULL)
+ && (prev->flags & hidden_mask));
+ i++;
+ }
+
+ /* Now check the borders of the window. Perhaps the current line lies
+ * outsider the border by a line. Only do this if terminal can scroll.
+ */
+
+ if (scroll_mode == 1)
+ return find_top_to_recenter (win);
+ else if (scroll_mode == -1)
+ scroll_mode = 0;
+
+ next = cline->next;
+ while (hidden_mask
+ && (next != NULL)
+ && (next->flags & hidden_mask))
+ next = next->next;
+
+ if ((next != NULL)
+ && (next == top_window_line))
+ {
+ /* The current line is one line above the window. This means user
+ * has moved up past the top of the window. If scroll_mode is set
+ * to scroll by pages, we need to do a page up.
+ */
+
+ win->top_window_line = cline;
+ find_window_bottom (win);
+
+ if (scroll_mode) return SLscroll_pageup (win);
+
+ return 0;
+ }
+
+ prev = cline->prev;
+
+ while (hidden_mask
+ && (prev != NULL)
+ && (prev->flags & hidden_mask))
+ prev = prev->prev;
+
+ if ((prev == NULL)
+ || (prev != win->bot_window_line))
+ return find_top_to_recenter (win);
+
+ /* It looks like cline is below window by one line. See what line should
+ * be at top to scroll it into view. Only do this unless we are scrolling
+ * by pages.
+ */
+ if (scroll_mode)
+ {
+ win->top_window_line = cline;
+ find_window_bottom (win);
+ return 0;
+ }
+
+ i = 2;
+ while ((i < nrows) && (prev != NULL))
+ {
+ do
+ {
+ prev = prev->prev;
+ }
+ while (hidden_mask
+ && (prev != NULL)
+ && (prev->flags & hidden_mask));
+ i++;
+ }
+
+ if (prev != NULL)
+ {
+ win->top_window_line = prev;
+ find_window_bottom (win);
+ return 0;
+ }
+
+ return find_top_to_recenter (win);
+}
+
+int SLscroll_find_line_num (SLscroll_Window_Type *win)
+{
+ SLscroll_Type *cline, *l;
+ unsigned int n;
+ unsigned int hidden_mask;
+
+ if (win == NULL) return -1;
+
+ hidden_mask = win->hidden_mask;
+ cline = win->current_line;
+
+ n = 1;
+
+ l = win->lines;
+ while (l != cline)
+ {
+ if ((hidden_mask == 0)
+ || (0 == (l->flags & hidden_mask)))
+ n++;
+
+ l = l->next;
+ }
+
+ win->line_num = n;
+ n--;
+
+ while (l != NULL)
+ {
+ if ((hidden_mask == 0)
+ || (0 == (l->flags & hidden_mask)))
+ n++;
+ l = l->next;
+ }
+ win->num_lines = n;
+
+ return 0;
+}
+
+unsigned int SLscroll_next_n (SLscroll_Window_Type *win, unsigned int n)
+{
+ unsigned int i;
+ unsigned int hidden_mask;
+ SLscroll_Type *l, *cline;
+
+ if ((win == NULL)
+ || (NULL == (cline = win->current_line)))
+ return 0;
+
+ hidden_mask = win->hidden_mask;
+ l = cline;
+ i = 0;
+ while (i < n)
+ {
+ l = l->next;
+ while (hidden_mask
+ && (l != NULL) && (l->flags & hidden_mask))
+ l = l->next;
+
+ if (l == NULL)
+ break;
+
+ i++;
+ cline = l;
+ }
+
+ win->current_line = cline;
+ win->line_num += i;
+ return i;
+}
+
+unsigned int SLscroll_prev_n (SLscroll_Window_Type *win, unsigned int n)
+{
+ unsigned int i;
+ unsigned int hidden_mask;
+ SLscroll_Type *l, *cline;
+
+ if ((win == NULL)
+ || (NULL == (cline = win->current_line)))
+ return 0;
+
+ hidden_mask = win->hidden_mask;
+ l = cline;
+ i = 0;
+ while (i < n)
+ {
+ l = l->prev;
+ while (hidden_mask
+ && (l != NULL) && (l->flags & hidden_mask))
+ l = l->prev;
+
+ if (l == NULL)
+ break;
+
+ i++;
+ cline = l;
+ }
+
+ win->current_line = cline;
+ win->line_num -= i;
+ return i;
+}
+
+int SLscroll_pageup (SLscroll_Window_Type *win)
+{
+ SLscroll_Type *l, *top;
+ unsigned int nrows, hidden_mask;
+ unsigned int n;
+
+ if (win == NULL)
+ return -1;
+
+ (void) SLscroll_find_top (win);
+
+ nrows = win->nrows;
+
+ if ((NULL != (top = win->top_window_line))
+ && (nrows > 2))
+ {
+ n = 0;
+ hidden_mask = win->hidden_mask;
+ l = win->current_line;
+ while ((l != NULL) && (l != top))
+ {
+ l = l->prev;
+ if ((hidden_mask == 0)
+ || ((l != NULL) && (0 == (l->flags & hidden_mask))))
+ n++;
+ }
+
+ if (l != NULL)
+ {
+ unsigned int save_line_num;
+ int ret = 0;
+
+ win->current_line = l;
+ win->line_num -= n;
+
+ /* Compute a new top/bottom header */
+ save_line_num = win->line_num;
+
+ if ((0 == SLscroll_prev_n (win, nrows - 1))
+ && (n == 0))
+ ret = -1;
+
+ win->top_window_line = win->current_line;
+ win->current_line = l;
+ win->line_num = save_line_num;
+
+ find_window_bottom (win);
+ return ret;
+ }
+ }
+
+ if (nrows < 2) nrows++;
+ if (0 == SLscroll_prev_n (win, nrows - 1))
+ return -1;
+ return 0;
+}
+
+int SLscroll_pagedown (SLscroll_Window_Type *win)
+{
+ SLscroll_Type *l, *bot;
+ unsigned int nrows, hidden_mask;
+ unsigned int n;
+
+ if (win == NULL)
+ return -1;
+
+ (void) SLscroll_find_top (win);
+
+ nrows = win->nrows;
+
+ if ((NULL != (bot = win->bot_window_line))
+ && (nrows > 2))
+ {
+ n = 0;
+ hidden_mask = win->hidden_mask;
+ l = win->current_line;
+ while ((l != NULL) && (l != bot))
+ {
+ l = l->next;
+ if ((hidden_mask == 0)
+ || ((l != NULL) && (0 == (l->flags & hidden_mask))))
+ n++;
+ }
+
+ if (l != NULL)
+ {
+ win->current_line = l;
+ win->top_window_line = l;
+ win->line_num += n;
+
+ find_window_bottom (win);
+
+ if (n || (bot != win->bot_window_line))
+ return 0;
+
+ return -1;
+ }
+ }
+
+ if (nrows < 2) nrows++;
+ if (0 == SLscroll_next_n (win, nrows - 1))
+ return -1;
+ return 0;
+}
+
diff --git a/mdk-stage1/slang/slsearch.c b/mdk-stage1/slang/slsearch.c
new file mode 100644
index 000000000..a9a427a7d
--- /dev/null
+++ b/mdk-stage1/slang/slsearch.c
@@ -0,0 +1,239 @@
+/* Copyright (c) 1992, 1999, 2001 John E. Davis
+ * This file is part of the S-Lang library.
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Perl Artistic License.
+ */
+#include "slinclud.h"
+
+#include "slang.h"
+#include "_slang.h"
+
+#ifdef upcase
+# undef upcase
+#endif
+
+#define upcase(ch) (cs ? ch : UPPER_CASE(ch))
+
+static unsigned char *search_forward (register unsigned char *beg,
+ unsigned char *end,
+ unsigned char *key,
+ register int key_len, int cs, int *ind)
+{
+ register unsigned char char1;
+ unsigned char *pos;
+ int j, str_len;
+ register unsigned char ch;
+ register int db;
+
+ str_len = (int) (end - beg);
+ if (str_len < key_len) return (NULL);
+
+ if (key_len == 0)
+ return NULL;
+
+ char1 = key[key_len - 1];
+ beg += (key_len - 1);
+
+ while(1)
+ {
+ if (cs) while (beg < end)
+ {
+ ch = *beg;
+ db = ind[(unsigned char) ch];
+ if ((db < key_len) && (ch == char1)) break;
+ beg += db; /* ind[(unsigned char) ch]; */
+ }
+ else while (beg < end)
+ {
+ ch = *beg;
+ db = ind[(unsigned char) ch];
+ if ((db < key_len) &&
+ (UPPER_CASE(ch) == char1)) break;
+ beg += db; /* ind[(unsigned char) ch]; */
+ }
+
+ if (beg >= end) return(NULL);
+
+ pos = beg - (key_len - 1);
+ for (j = 0; j < key_len; j++)
+ {
+ ch = upcase(pos[j]);
+ if (ch != (unsigned char) key[j]) break;
+ }
+
+ if (j == key_len) return(pos);
+ beg += 1;
+ }
+}
+
+static unsigned char *search_backward (unsigned char *beg,unsigned char *end,
+ unsigned char *key, int key_len,
+ int cs, int *ind)
+{
+ unsigned char ch, char1;
+ int j, str_len, ofs;
+
+ str_len = (int) (end - beg);
+ if (str_len < key_len) return (NULL);
+
+ if (key_len == 0)
+ return NULL;
+
+ /* end -= (key_len - 1); */
+ end -= key_len;
+
+ char1 = key[0];
+
+ while(1)
+ {
+ while ((beg <= end) && (ch = *end, ch = upcase(ch), ch != char1))
+ {
+ ofs = ind[(unsigned char) ch];
+#ifdef __MSDOS__
+ /* This is needed for msdos segment wrapping problems */
+ if (beg + ofs > end) return(NULL);
+#endif
+ end -= ofs;
+ }
+ if (beg > end) return(NULL);
+ for (j = 1; j < key_len; j++)
+ {
+ ch = upcase(end[j]);
+ if (ch != key[j]) break;
+ }
+ if (j == key_len) return(end);
+ end--;
+ }
+}
+
+unsigned char *SLsearch (unsigned char *pmin, unsigned char *pmax,
+ SLsearch_Type *st)
+{
+ if (st->dir > 0) return search_forward (pmin, pmax, st->key,
+ st->key_len, st->cs, st->ind);
+ else return search_backward (pmin, pmax, st->key,
+ st->key_len, st->cs, st->ind);
+}
+
+static int Case_Tables_Ok;
+
+int SLsearch_init (char *str, int dir, int cs, SLsearch_Type *st)
+{
+ int i, maxi;
+ register int max = strlen(str);
+ unsigned char *w, *work = st->key;
+ register int *indp, *indpm;
+ int *ind = st->ind;
+
+ if (max >= (int) sizeof (st->key))
+ {
+ SLang_doerror ("Search string too long.");
+ return -1;
+ }
+
+ st->dir = dir; st->cs = cs;
+
+ if (!Case_Tables_Ok) SLang_init_case_tables ();
+
+ if (dir > 0)
+ {
+ w = work;
+ }
+ else
+ {
+ maxi = max - 1;
+ str = str + maxi;
+ w = work + maxi;
+ }
+
+ /* for (i = 0; i < 256; i++) ind[i] = max; */
+ indp = ind; indpm = ind + 256;
+ while (indp < indpm)
+ {
+ *indp++ = max;
+ *indp++ = max;
+ *indp++ = max;
+ *indp++ = max;
+ }
+
+ i = 0;
+ if (cs) while (i < max)
+ {
+ i++;
+ maxi = max - i;
+ *w = *str;
+ ind[(unsigned char) *str] = maxi;
+ str += dir; w += dir;
+ }
+ else while (i < max)
+ {
+ i++;
+ maxi = max - i;
+ *w = UPPER_CASE(*str);
+ ind[(unsigned char) *w] = maxi;
+ ind[(unsigned char) LOWER_CASE(*str)] = maxi;
+ str += dir; w += dir;
+ }
+
+ work[max] = 0;
+ st->key_len = max;
+ return max;
+}
+
+/* 8bit clean upper and lowercase macros */
+unsigned char _SLChg_LCase_Lut[256];
+unsigned char _SLChg_UCase_Lut[256];
+
+void SLang_define_case (int *u, int *l)
+{
+ unsigned char up = (unsigned char) *u, dn = (unsigned char) *l;
+
+ _SLChg_LCase_Lut[up] = dn;
+ _SLChg_LCase_Lut[dn] = dn;
+ _SLChg_UCase_Lut[dn] = up;
+ _SLChg_UCase_Lut[up] = up;
+}
+
+void SLang_init_case_tables (void)
+{
+ int i, j;
+ if (Case_Tables_Ok) return;
+
+ for (i = 0; i < 256; i++)
+ {
+ _SLChg_UCase_Lut[i] = i;
+ _SLChg_LCase_Lut[i] = i;
+ }
+
+ for (i = 'A'; i <= 'Z'; i++)
+ {
+ j = i + 32;
+ _SLChg_UCase_Lut[j] = i;
+ _SLChg_LCase_Lut[i] = j;
+ }
+#ifdef PC_SYSTEM
+ /* Initialize for DOS code page 437. */
+ _SLChg_UCase_Lut[135] = 128; _SLChg_LCase_Lut[128] = 135;
+ _SLChg_UCase_Lut[132] = 142; _SLChg_LCase_Lut[142] = 132;
+ _SLChg_UCase_Lut[134] = 143; _SLChg_LCase_Lut[143] = 134;
+ _SLChg_UCase_Lut[130] = 144; _SLChg_LCase_Lut[144] = 130;
+ _SLChg_UCase_Lut[145] = 146; _SLChg_LCase_Lut[146] = 145;
+ _SLChg_UCase_Lut[148] = 153; _SLChg_LCase_Lut[153] = 148;
+ _SLChg_UCase_Lut[129] = 154; _SLChg_LCase_Lut[154] = 129;
+ _SLChg_UCase_Lut[164] = 165; _SLChg_LCase_Lut[165] = 164;
+#else
+ /* ISO Latin */
+ for (i = 192; i <= 221; i++)
+ {
+ j = i + 32;
+ _SLChg_UCase_Lut[j] = i;
+ _SLChg_LCase_Lut[i] = j;
+ }
+ _SLChg_UCase_Lut[215] = 215; _SLChg_LCase_Lut[215] = 215;
+ _SLChg_UCase_Lut[223] = 223; _SLChg_LCase_Lut[223] = 223;
+ _SLChg_UCase_Lut[247] = 247; _SLChg_LCase_Lut[247] = 247;
+ _SLChg_UCase_Lut[255] = 255; _SLChg_LCase_Lut[255] = 255;
+#endif
+ Case_Tables_Ok = 1;
+}
diff --git a/mdk-stage1/slang/slsignal.c b/mdk-stage1/slang/slsignal.c
new file mode 100644
index 000000000..30707dea5
--- /dev/null
+++ b/mdk-stage1/slang/slsignal.c
@@ -0,0 +1,336 @@
+/* Copyright (c) 1998, 1999, 2001 John E. Davis
+ * This file is part of the S-Lang library.
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Perl Artistic License.
+ */
+#include "slinclud.h"
+
+#include <signal.h>
+
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_WAIT_H
+# include <sys/wait.h>
+#endif
+
+#include <errno.h>
+
+#include "slang.h"
+#include "_slang.h"
+
+/* Do not trust these environments */
+#if defined(__CYGWIN32__) || defined(__MINGW32__) || defined(AMIGA)
+# ifdef SLANG_POSIX_SIGNALS
+# undef SLANG_POSIX_SIGNALS
+# endif
+#endif
+
+/* This function will cause system calls to be restarted after signal if possible */
+SLSig_Fun_Type *SLsignal (int sig, SLSig_Fun_Type *f)
+{
+#if defined(SLANG_POSIX_SIGNALS)
+ struct sigaction old_sa, new_sa;
+
+# ifdef SIGALRM
+ /* We want system calls to be interrupted by SIGALRM. */
+ if (sig == SIGALRM) return SLsignal_intr (sig, f);
+# endif
+
+ sigemptyset (&new_sa.sa_mask);
+ new_sa.sa_handler = f;
+
+ new_sa.sa_flags = 0;
+# ifdef SA_RESTART
+ new_sa.sa_flags |= SA_RESTART;
+# endif
+
+ if (-1 == sigaction (sig, &new_sa, &old_sa))
+ return (SLSig_Fun_Type *) SIG_ERR;
+
+ return old_sa.sa_handler;
+#else
+ /* Not POSIX. */
+ return signal (sig, f);
+#endif
+}
+
+/* This function will NOT cause system calls to be restarted after
+ * signal if possible
+ */
+SLSig_Fun_Type *SLsignal_intr (int sig, SLSig_Fun_Type *f)
+{
+#ifdef SLANG_POSIX_SIGNALS
+ struct sigaction old_sa, new_sa;
+
+ sigemptyset (&new_sa.sa_mask);
+ new_sa.sa_handler = f;
+
+ new_sa.sa_flags = 0;
+# ifdef SA_INTERRUPT
+ new_sa.sa_flags |= SA_INTERRUPT;
+# endif
+
+ if (-1 == sigaction (sig, &new_sa, &old_sa))
+ return (SLSig_Fun_Type *) SIG_ERR;
+
+ return old_sa.sa_handler;
+#else
+ /* Not POSIX. */
+ return signal (sig, f);
+#endif
+}
+
+/* We are primarily interested in blocking signals that would cause the
+ * application to reset the tty. These include suspend signals and
+ * possibly interrupt signals.
+ */
+#ifdef SLANG_POSIX_SIGNALS
+static sigset_t Old_Signal_Mask;
+#endif
+
+static volatile unsigned int Blocked_Depth;
+
+int SLsig_block_signals (void)
+{
+#ifdef SLANG_POSIX_SIGNALS
+ sigset_t new_mask;
+#endif
+
+ Blocked_Depth++;
+ if (Blocked_Depth != 1)
+ {
+ return 0;
+ }
+
+#ifdef SLANG_POSIX_SIGNALS
+ sigemptyset (&new_mask);
+# ifdef SIGQUIT
+ sigaddset (&new_mask, SIGQUIT);
+# endif
+# ifdef SIGTSTP
+ sigaddset (&new_mask, SIGTSTP);
+# endif
+# ifdef SIGINT
+ sigaddset (&new_mask, SIGINT);
+# endif
+# ifdef SIGTTIN
+ sigaddset (&new_mask, SIGTTIN);
+# endif
+# ifdef SIGTTOU
+ sigaddset (&new_mask, SIGTTOU);
+# endif
+# ifdef SIGWINCH
+ sigaddset (&new_mask, SIGWINCH);
+# endif
+
+ (void) sigprocmask (SIG_BLOCK, &new_mask, &Old_Signal_Mask);
+ return 0;
+#else
+ /* Not implemented. */
+ return -1;
+#endif
+}
+
+int SLsig_unblock_signals (void)
+{
+ if (Blocked_Depth == 0)
+ return -1;
+
+ Blocked_Depth--;
+
+ if (Blocked_Depth != 0)
+ return 0;
+
+#ifdef SLANG_POSIX_SIGNALS
+ (void) sigprocmask (SIG_SETMASK, &Old_Signal_Mask, NULL);
+ return 0;
+#else
+ return -1;
+#endif
+}
+
+#ifdef MSWINDOWS
+int SLsystem (char *cmd)
+{
+ SLang_verror (SL_NOT_IMPLEMENTED, "system not implemented");
+ return -1;
+}
+
+#else
+int SLsystem (char *cmd)
+{
+#ifdef SLANG_POSIX_SIGNALS
+ pid_t pid;
+ int status;
+ struct sigaction ignore;
+# ifdef SIGINT
+ struct sigaction save_intr;
+# endif
+# ifdef SIGQUIT
+ struct sigaction save_quit;
+# endif
+# ifdef SIGCHLD
+ sigset_t child_mask, save_mask;
+# endif
+
+ if (cmd == NULL) return 1;
+
+ ignore.sa_handler = SIG_IGN;
+ sigemptyset (&ignore.sa_mask);
+ ignore.sa_flags = 0;
+
+# ifdef SIGINT
+ if (-1 == sigaction (SIGINT, &ignore, &save_intr))
+ return -1;
+# endif
+
+# ifdef SIGQUIT
+ if (-1 == sigaction (SIGQUIT, &ignore, &save_quit))
+ {
+ (void) sigaction (SIGINT, &save_intr, NULL);
+ return -1;
+ }
+# endif
+
+# ifdef SIGCHLD
+ sigemptyset (&child_mask);
+ sigaddset (&child_mask, SIGCHLD);
+ if (-1 == sigprocmask (SIG_BLOCK, &child_mask, &save_mask))
+ {
+# ifdef SIGINT
+ (void) sigaction (SIGINT, &save_intr, NULL);
+# endif
+# ifdef SIGQUIT
+ (void) sigaction (SIGQUIT, &save_quit, NULL);
+# endif
+ return -1;
+ }
+# endif
+
+ pid = fork();
+
+ if (pid == -1)
+ status = -1;
+ else if (pid == 0)
+ {
+ /* Child */
+# ifdef SIGINT
+ (void) sigaction (SIGINT, &save_intr, NULL);
+# endif
+# ifdef SIGQUIT
+ (void) sigaction (SIGQUIT, &save_quit, NULL);
+# endif
+# ifdef SIGCHLD
+ (void) sigprocmask (SIG_SETMASK, &save_mask, NULL);
+# endif
+
+ execl ("/bin/sh", "sh", "-c", cmd, NULL);
+ _exit (127);
+ }
+ else
+ {
+ /* parent */
+ while (-1 == waitpid (pid, &status, 0))
+ {
+# ifdef EINTR
+ if (errno == EINTR)
+ continue;
+# endif
+# ifdef ERESTARTSYS
+ if (errno == ERESTARTSYS)
+ continue;
+# endif
+ status = -1;
+ break;
+ }
+ }
+# ifdef SIGINT
+ if (-1 == sigaction (SIGINT, &save_intr, NULL))
+ status = -1;
+# endif
+# ifdef SIGQUIT
+ if (-1 == sigaction (SIGQUIT, &save_quit, NULL))
+ status = -1;
+# endif
+# ifdef SIGCHLD
+ if (-1 == sigprocmask (SIG_SETMASK, &save_mask, NULL))
+ status = -1;
+# endif
+
+ return status;
+
+#else /* No POSIX Signals */
+# ifdef SIGINT
+ void (*sint)(int);
+# endif
+# ifdef SIGQUIT
+ void (*squit)(int);
+# endif
+ int status;
+
+# ifdef SIGQUIT
+ squit = SLsignal (SIGQUIT, SIG_IGN);
+# endif
+# ifdef SIGINT
+ sint = SLsignal (SIGINT, SIG_IGN);
+# endif
+ status = system (cmd);
+# ifdef SIGINT
+ SLsignal (SIGINT, sint);
+# endif
+# ifdef SIGQUIT
+ SLsignal (SIGQUIT, squit);
+# endif
+ return status;
+#endif /* POSIX_SIGNALS */
+}
+#endif
+
+#if 0
+#include <windows.h>
+static int msw_system (char *cmd)
+{
+ STARTUPINFO startup_info;
+ PROCESS_INFORMATION process_info;
+ int status;
+
+ if (cmd == NULL) return -1;
+
+ memset ((char *) &startup_info, 0, sizeof (STARTUPINFO));
+ startup_info.cb = sizeof(STARTUPINFO);
+ startup_info.dwFlags = STARTF_USESHOWWINDOW;
+ startup_info.wShowWindow = SW_SHOWDEFAULT;
+
+ if (FALSE == CreateProcess (NULL,
+ cmd,
+ NULL,
+ NULL,
+ FALSE,
+ NORMAL_PRIORITY_CLASS|CREATE_NEW_CONSOLE,
+ NULL,
+ NULL,
+ &startup_info,
+ &process_info))
+ {
+ SLang_verror (0, "%s: CreateProcess failed.", cmd);
+ return -1;
+ }
+
+ status = -1;
+
+ if (0xFFFFFFFFUL != WaitForSingleObject (process_info.hProcess, INFINITE))
+ {
+ DWORD exit_code;
+
+ if (TRUE == GetExitCodeProcess (process_info.hProcess, &exit_code))
+ status = (int) exit_code;
+ }
+
+ CloseHandle (process_info.hThread);
+ CloseHandle (process_info.hProcess);
+
+ return status;
+}
+#endif
diff --git a/mdk-stage1/slang/slsmg.c b/mdk-stage1/slang/slsmg.c
new file mode 100644
index 000000000..088557f27
--- /dev/null
+++ b/mdk-stage1/slang/slsmg.c
@@ -0,0 +1,1584 @@
+/* SLang Screen management routines */
+/* Copyright (c) 1992, 1999, 2001 John E. Davis
+ * This file is part of the S-Lang library.
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Perl Artistic License.
+ */
+
+#include "slinclud.h"
+
+#include "slang.h"
+#include "_slang.h"
+
+typedef struct Screen_Type
+ {
+ int n; /* number of chars written last time */
+ int flags; /* line untouched, etc... */
+ SLsmg_Char_Type *old, *neew;
+#ifndef IBMPC_SYSTEM
+ unsigned long old_hash, new_hash;
+#endif
+ }
+Screen_Type;
+
+#define TOUCHED 0x1
+#define TRASHED 0x2
+static int Screen_Trashed;
+
+#if !defined(__MSDOS_16BIT__)
+# define MAX_SCREEN_SIZE 256
+#else
+# define MAX_SCREEN_SIZE 75
+#endif
+
+Screen_Type SL_Screen[MAX_SCREEN_SIZE];
+static int Start_Col, Start_Row;
+static int Screen_Cols, Screen_Rows;
+static int This_Row, This_Col;
+static int This_Color; /* only the first 8 bits of this
+ * are used. The highest bit is used
+ * to indicate an alternate character
+ * set. This leaves 127 userdefineable
+ * color combination.
+ */
+
+#ifndef IBMPC_SYSTEM
+#define ALT_CHAR_FLAG 0x80
+#else
+#define ALT_CHAR_FLAG 0x00
+#endif
+
+#if SLTT_HAS_NON_BCE_SUPPORT && !defined(IBMPC_SYSTEM)
+#define REQUIRES_NON_BCE_SUPPORT 1
+static int Bce_Color_Offset;
+#endif
+
+int SLsmg_Newline_Behavior = 0;
+int SLsmg_Backspace_Moves = 0;
+/* Backward compatibility. Not used. */
+/* int SLsmg_Newline_Moves; */
+
+static void (*tt_normal_video)(void) = SLtt_normal_video;
+static void (*tt_goto_rc)(int, int) = SLtt_goto_rc;
+static void (*tt_cls) (void) = SLtt_cls;
+static void (*tt_del_eol) (void) = SLtt_del_eol;
+static void (*tt_smart_puts) (SLsmg_Char_Type *, SLsmg_Char_Type *, int, int) = SLtt_smart_puts;
+static int (*tt_flush_output) (void) = SLtt_flush_output;
+static int (*tt_reset_video) (void) = SLtt_reset_video;
+static int (*tt_init_video) (void) = SLtt_init_video;
+static int *tt_Screen_Rows = &SLtt_Screen_Rows;
+static int *tt_Screen_Cols = &SLtt_Screen_Cols;
+
+#ifndef IBMPC_SYSTEM
+static void (*tt_set_scroll_region)(int, int) = SLtt_set_scroll_region;
+static void (*tt_reverse_index)(int) = SLtt_reverse_index;
+static void (*tt_reset_scroll_region)(void) = SLtt_reset_scroll_region;
+static void (*tt_delete_nlines)(int) = SLtt_delete_nlines;
+#endif
+
+#ifndef IBMPC_SYSTEM
+static int *tt_Term_Cannot_Scroll = &SLtt_Term_Cannot_Scroll;
+static int *tt_Has_Alt_Charset = &SLtt_Has_Alt_Charset;
+static char **tt_Graphics_Char_Pairs = &SLtt_Graphics_Char_Pairs;
+static int *tt_Use_Blink_For_ACS = &SLtt_Use_Blink_For_ACS;
+#endif
+
+static int Smg_Inited;
+
+static void blank_line (SLsmg_Char_Type *p, int n, unsigned char ch)
+{
+ register SLsmg_Char_Type *pmax = p + n;
+ register SLsmg_Char_Type color_ch;
+
+ color_ch = SLSMG_BUILD_CHAR(ch,This_Color);
+
+ while (p < pmax)
+ {
+ *p++ = color_ch;
+ }
+}
+
+static void clear_region (int row, int n)
+{
+ int i;
+ int imax = row + n;
+
+ if (imax > Screen_Rows) imax = Screen_Rows;
+ for (i = row; i < imax; i++)
+ {
+ if (i >= 0)
+ {
+ blank_line (SL_Screen[i].neew, Screen_Cols, ' ');
+ SL_Screen[i].flags |= TOUCHED;
+ }
+ }
+}
+
+void SLsmg_erase_eol (void)
+{
+ int r, c;
+
+ if (Smg_Inited == 0) return;
+
+ c = This_Col - Start_Col;
+ r = This_Row - Start_Row;
+
+ if ((r < 0) || (r >= Screen_Rows)) return;
+ if (c < 0) c = 0; else if (c >= Screen_Cols) return;
+ blank_line (SL_Screen[This_Row].neew + c , Screen_Cols - c, ' ');
+ SL_Screen[This_Row].flags |= TOUCHED;
+}
+
+static void scroll_up (void)
+{
+ unsigned int i, imax;
+ SLsmg_Char_Type *neew;
+
+ neew = SL_Screen[0].neew;
+ imax = Screen_Rows - 1;
+ for (i = 0; i < imax; i++)
+ {
+ SL_Screen[i].neew = SL_Screen[i + 1].neew;
+ SL_Screen[i].flags |= TOUCHED;
+ }
+ SL_Screen[i].neew = neew;
+ SL_Screen[i].flags |= TOUCHED;
+ blank_line (neew, Screen_Cols, ' ');
+ This_Row--;
+}
+
+void SLsmg_gotorc (int r, int c)
+{
+ This_Row = r;
+ This_Col = c;
+}
+
+int SLsmg_get_row (void)
+{
+ return This_Row;
+}
+
+int SLsmg_get_column (void)
+{
+ return This_Col;
+}
+
+void SLsmg_erase_eos (void)
+{
+ if (Smg_Inited == 0) return;
+
+ SLsmg_erase_eol ();
+ clear_region (This_Row + 1, Screen_Rows);
+}
+
+static int This_Alt_Char;
+
+void SLsmg_set_char_set (int i)
+{
+#ifdef IBMPC_SYSTEM
+ (void) i;
+#else
+ if ((tt_Use_Blink_For_ACS != NULL)
+ && (*tt_Use_Blink_For_ACS != 0))
+ return;/* alt chars not used and the alt bit
+ * is used to indicate a blink.
+ */
+
+ if (i) This_Alt_Char = ALT_CHAR_FLAG;
+ else This_Alt_Char = 0;
+
+ This_Color &= 0x7F;
+ This_Color |= This_Alt_Char;
+#endif
+}
+
+void SLsmg_set_color (int color)
+{
+ if (color < 0) return;
+#ifdef REQUIRES_NON_BCE_SUPPORT
+ color += Bce_Color_Offset;
+#endif
+ This_Color = color | This_Alt_Char;
+}
+
+void SLsmg_reverse_video (void)
+{
+ SLsmg_set_color (1);
+}
+
+void SLsmg_normal_video (void)
+{
+ SLsmg_set_color (0);
+}
+
+static int point_visible (int col_too)
+{
+ return ((This_Row >= Start_Row) && (This_Row < Start_Row + Screen_Rows)
+ && ((col_too == 0)
+ || ((This_Col >= Start_Col)
+ && (This_Col < Start_Col + Screen_Cols))));
+}
+
+void SLsmg_write_string (char *str)
+{
+ SLsmg_write_nchars (str, strlen (str));
+}
+
+void SLsmg_write_nstring (char *str, unsigned int n)
+{
+ unsigned int width;
+ char blank = ' ';
+
+ /* Avoid a problem if a user accidently passes a negative value */
+ if ((int) n < 0)
+ return;
+
+ if (str == NULL) width = 0;
+ else
+ {
+ width = strlen (str);
+ if (width > n) width = n;
+ SLsmg_write_nchars (str, width);
+ }
+ while (width++ < n) SLsmg_write_nchars (&blank, 1);
+}
+
+void SLsmg_write_wrapped_string (char *s, int r, int c,
+ unsigned int dr, unsigned int dc,
+ int fill)
+{
+ register char ch, *p;
+ int maxc = (int) dc;
+
+ if ((dr == 0) || (dc == 0)) return;
+ p = s;
+ dc = 0;
+ while (1)
+ {
+ ch = *p++;
+ if ((ch == 0) || (ch == '\n'))
+ {
+ int diff;
+
+ diff = maxc - (int) dc;
+
+ SLsmg_gotorc (r, c);
+ SLsmg_write_nchars (s, dc);
+ if (fill && (diff > 0))
+ {
+ while (diff--) SLsmg_write_char (' ');
+ }
+ if ((ch == 0) || (dr == 1)) break;
+
+ r++;
+ dc = 0;
+ dr--;
+ s = p;
+ }
+ else if ((int) dc == maxc)
+ {
+ SLsmg_gotorc (r, c);
+ SLsmg_write_nchars (s, dc + 1);
+ if (dr == 1) break;
+
+ r++;
+ dc = 0;
+ dr--;
+ s = p;
+ }
+ else dc++;
+ }
+}
+
+int SLsmg_Tab_Width = 8;
+
+/* Minimum value for which eight bit char is displayed as is. */
+
+#ifndef IBMPC_SYSTEM
+int SLsmg_Display_Eight_Bit = 160;
+static unsigned char Alt_Char_Set[129];/* 129th is used as a flag */
+#else
+int SLsmg_Display_Eight_Bit = 128;
+#endif
+
+void SLsmg_write_nchars (char *str, unsigned int n)
+{
+ register SLsmg_Char_Type *p, old, neew, color;
+ unsigned char ch;
+ unsigned int flags;
+ int len, start_len, max_len;
+ char *str_max;
+ int newline_flag;
+#ifndef IBMPC_SYSTEM
+ int alt_char_set_flag;
+
+ alt_char_set_flag = ((This_Color & ALT_CHAR_FLAG)
+ && ((tt_Use_Blink_For_ACS == NULL)
+ || (*tt_Use_Blink_For_ACS == 0)));
+#endif
+
+ if (Smg_Inited == 0) return;
+
+ str_max = str + n;
+ color = This_Color;
+
+ top: /* get here only on newline */
+
+ newline_flag = 0;
+ start_len = Start_Col;
+
+ if (point_visible (0) == 0) return;
+
+ len = This_Col;
+ max_len = start_len + Screen_Cols;
+
+ p = SL_Screen[This_Row - Start_Row].neew;
+ if (len > start_len) p += (len - start_len);
+
+ flags = SL_Screen[This_Row - Start_Row].flags;
+ while ((len < max_len) && (str < str_max))
+ {
+ ch = (unsigned char) *str++;
+
+#ifndef IBMPC_SYSTEM
+ if (alt_char_set_flag)
+ ch = Alt_Char_Set [ch & 0x7F];
+#endif
+ if (((ch >= ' ') && (ch < 127))
+ || (ch >= (unsigned char) SLsmg_Display_Eight_Bit)
+#ifndef IBMPC_SYSTEM
+ || alt_char_set_flag
+#endif
+ )
+ {
+ len += 1;
+ if (len > start_len)
+ {
+ old = *p;
+ neew = SLSMG_BUILD_CHAR(ch,color);
+ if (old != neew)
+ {
+ flags |= TOUCHED;
+ *p = neew;
+ }
+ p++;
+ }
+ }
+
+ else if ((ch == '\t') && (SLsmg_Tab_Width > 0))
+ {
+ n = len;
+ n += SLsmg_Tab_Width;
+ n = SLsmg_Tab_Width - (n % SLsmg_Tab_Width);
+ if ((unsigned int) len + n > (unsigned int) max_len)
+ n = (unsigned int) (max_len - len);
+ neew = SLSMG_BUILD_CHAR(' ',color);
+ while (n--)
+ {
+ len += 1;
+ if (len > start_len)
+ {
+ if (*p != neew)
+ {
+ flags |= TOUCHED;
+ *p = neew;
+ }
+ p++;
+ }
+ }
+ }
+ else if ((ch == '\n')
+ && (SLsmg_Newline_Behavior != SLSMG_NEWLINE_PRINTABLE))
+ {
+ newline_flag = 1;
+ break;
+ }
+ else if ((ch == 0x8) && SLsmg_Backspace_Moves)
+ {
+ if (len != 0) len--;
+ }
+ else
+ {
+ if (ch & 0x80)
+ {
+ neew = SLSMG_BUILD_CHAR('~',color);
+ len += 1;
+ if (len > start_len)
+ {
+ if (*p != neew)
+ {
+ *p = neew;
+ flags |= TOUCHED;
+ }
+ p++;
+ if (len == max_len) break;
+ ch &= 0x7F;
+ }
+ }
+
+ len += 1;
+ if (len > start_len)
+ {
+ neew = SLSMG_BUILD_CHAR('^',color);
+ if (*p != neew)
+ {
+ *p = neew;
+ flags |= TOUCHED;
+ }
+ p++;
+ if (len == max_len) break;
+ }
+
+ if (ch == 127) ch = '?'; else ch = ch + '@';
+ len++;
+ if (len > start_len)
+ {
+ neew = SLSMG_BUILD_CHAR(ch,color);
+ if (*p != neew)
+ {
+ *p = neew;
+ flags |= TOUCHED;
+ }
+ p++;
+ }
+ }
+ }
+
+ SL_Screen[This_Row - Start_Row].flags = flags;
+ This_Col = len;
+
+ if (SLsmg_Newline_Behavior == 0)
+ return;
+
+ if (newline_flag == 0)
+ {
+ while (str < str_max)
+ {
+ if (*str == '\n') break;
+ str++;
+ }
+ if (str == str_max) return;
+ str++;
+ }
+
+ This_Row++;
+ This_Col = 0;
+ if (This_Row == Start_Row + Screen_Rows)
+ {
+ if (SLsmg_Newline_Behavior == SLSMG_NEWLINE_SCROLLS) scroll_up ();
+ }
+ goto top;
+}
+
+void SLsmg_write_char (char ch)
+{
+ SLsmg_write_nchars (&ch, 1);
+}
+
+static int Cls_Flag;
+
+void SLsmg_cls (void)
+{
+ int tac;
+ if (Smg_Inited == 0) return;
+
+ tac = This_Alt_Char; This_Alt_Char = 0;
+ SLsmg_set_color (0);
+ clear_region (0, Screen_Rows);
+ This_Alt_Char = tac;
+ SLsmg_set_color (0);
+ Cls_Flag = 1;
+}
+#if 0
+static void do_copy (SLsmg_Char_Type *a, SLsmg_Char_Type *b)
+{
+ SLsmg_Char_Type *amax = a + Screen_Cols;
+
+ while (a < amax) *a++ = *b++;
+}
+#endif
+
+#ifndef IBMPC_SYSTEM
+int SLsmg_Scroll_Hash_Border = 0;
+static unsigned long compute_hash (SLsmg_Char_Type *s, int n)
+{
+ register unsigned long h = 0, g;
+ register unsigned long sum = 0;
+ register SLsmg_Char_Type *smax, ch;
+ int is_blank = 2;
+
+ s += SLsmg_Scroll_Hash_Border;
+ smax = s + (n - SLsmg_Scroll_Hash_Border);
+ while (s < smax)
+ {
+ ch = *s++;
+ if (is_blank && (SLSMG_EXTRACT_CHAR(ch) != 32)) is_blank--;
+
+ sum += ch;
+
+ h = sum + (h << 3);
+ if ((g = h & 0xE0000000UL) != 0)
+ {
+ h = h ^ (g >> 24);
+ h = h ^ g;
+ }
+ }
+ if (is_blank) return 0;
+ return h;
+}
+
+static unsigned long Blank_Hash;
+
+static int try_scroll_down (int rmin, int rmax)
+{
+ int i, r1, r2, di, j;
+ unsigned long hash;
+ int did_scroll;
+ int color;
+ SLsmg_Char_Type *tmp;
+ int ignore;
+
+ did_scroll = 0;
+ for (i = rmax; i > rmin; i--)
+ {
+ hash = SL_Screen[i].new_hash;
+ if (hash == Blank_Hash) continue;
+
+ if ((hash == SL_Screen[i].old_hash)
+#if 0
+ || ((i + 1 < Screen_Rows) && (hash == SL_Screen[i + 1].old_hash))
+ || ((i - 1 > rmin) && (SL_Screen[i].old_hash == SL_Screen[i - 1].new_hash))
+#endif
+ )
+ continue;
+
+ for (j = i - 1; j >= rmin; j--)
+ {
+ if (hash == SL_Screen[j].old_hash) break;
+ }
+ if (j < rmin) continue;
+
+ r2 = i; /* end scroll region */
+
+ di = i - j;
+ j--;
+ ignore = 0;
+ while ((j >= rmin) && (SL_Screen[j].old_hash == SL_Screen[j + di].new_hash))
+ {
+ if (SL_Screen[j].old_hash == Blank_Hash) ignore++;
+ j--;
+ }
+ r1 = j + 1;
+
+ /* If this scroll only scrolls this line into place, don't do it.
+ */
+ if ((di > 1) && (r1 + di + ignore == r2)) continue;
+
+ /* If there is anything in the scrolling region that is ok, abort the
+ * scroll.
+ */
+
+ for (j = r1; j <= r2; j++)
+ {
+ if ((SL_Screen[j].old_hash != Blank_Hash)
+ && (SL_Screen[j].old_hash == SL_Screen[j].new_hash))
+ {
+ /* See if the scroll is happens to scroll this one into place. */
+ if ((j + di > r2) || (SL_Screen[j].old_hash != SL_Screen[j + di].new_hash))
+ break;
+ }
+ }
+ if (j <= r2) continue;
+
+ color = This_Color; This_Color = 0;
+ did_scroll = 1;
+ (*tt_normal_video) ();
+ (*tt_set_scroll_region) (r1, r2);
+ (*tt_goto_rc) (0, 0);
+ (*tt_reverse_index) (di);
+ (*tt_reset_scroll_region) ();
+ /* Now we have a hole in the screen.
+ * Make the virtual screen look like it.
+ *
+ * Note that if the terminal does not support BCE, then we have
+ * no idea what color the hole is. So, for this case, we do not
+ * want to add Bce_Color_Offset to This_Color since if Bce_Color_Offset
+ * is non-zero, then This_Color = 0 does not match any valid color
+ * obtained by adding Bce_Color_Offset.
+ */
+ for (j = r1; j <= r2; j++) SL_Screen[j].flags = TOUCHED;
+
+ while (di--)
+ {
+ tmp = SL_Screen[r2].old;
+ for (j = r2; j > r1; j--)
+ {
+ SL_Screen[j].old = SL_Screen[j - 1].old;
+ SL_Screen[j].old_hash = SL_Screen[j - 1].old_hash;
+ }
+ SL_Screen[r1].old = tmp;
+ blank_line (SL_Screen[r1].old, Screen_Cols, ' ');
+ SL_Screen[r1].old_hash = Blank_Hash;
+ r1++;
+ }
+ This_Color = color;
+ }
+
+ return did_scroll;
+}
+
+static int try_scroll_up (int rmin, int rmax)
+{
+ int i, r1, r2, di, j;
+ unsigned long hash;
+ int did_scroll;
+ int color;
+ SLsmg_Char_Type *tmp;
+ int ignore;
+
+ did_scroll = 0;
+ for (i = rmin; i < rmax; i++)
+ {
+ hash = SL_Screen[i].new_hash;
+ if (hash == Blank_Hash) continue;
+ if (hash == SL_Screen[i].old_hash)
+ continue;
+ /* find a match further down screen */
+ for (j = i + 1; j <= rmax; j++)
+ {
+ if (hash == SL_Screen[j].old_hash) break;
+ }
+ if (j > rmax) continue;
+
+ r1 = i; /* beg scroll region */
+ di = j - i; /* number of lines to scroll */
+ j++; /* since we know this is a match */
+
+ /* find end of scroll region */
+ ignore = 0;
+ while ((j <= rmax) && (SL_Screen[j].old_hash == SL_Screen[j - di].new_hash))
+ {
+ if (SL_Screen[j].old_hash == Blank_Hash) ignore++;
+ j++;
+ }
+ r2 = j - 1; /* end of scroll region */
+
+ /* If this scroll only scrolls this line into place, don't do it.
+ */
+ if ((di > 1) && (r1 + di + ignore == r2)) continue;
+
+ /* If there is anything in the scrolling region that is ok, abort the
+ * scroll.
+ */
+
+ for (j = r1; j <= r2; j++)
+ {
+ if ((SL_Screen[j].old_hash != Blank_Hash)
+ && (SL_Screen[j].old_hash == SL_Screen[j].new_hash))
+ {
+ if ((j - di < r1) || (SL_Screen[j].old_hash != SL_Screen[j - di].new_hash))
+ break;
+ }
+
+ }
+ if (j <= r2) continue;
+
+ did_scroll = 1;
+
+ /* See the above comments about BCE */
+ color = This_Color; This_Color = 0;
+ (*tt_normal_video) ();
+ (*tt_set_scroll_region) (r1, r2);
+ (*tt_goto_rc) (0, 0); /* relative to scroll region */
+ (*tt_delete_nlines) (di);
+ (*tt_reset_scroll_region) ();
+ /* Now we have a hole in the screen. Make the virtual screen look
+ * like it.
+ */
+ for (j = r1; j <= r2; j++) SL_Screen[j].flags = TOUCHED;
+
+ while (di--)
+ {
+ tmp = SL_Screen[r1].old;
+ for (j = r1; j < r2; j++)
+ {
+ SL_Screen[j].old = SL_Screen[j + 1].old;
+ SL_Screen[j].old_hash = SL_Screen[j + 1].old_hash;
+ }
+ SL_Screen[r2].old = tmp;
+ blank_line (SL_Screen[r2].old, Screen_Cols, ' ');
+ SL_Screen[r2].old_hash = Blank_Hash;
+ r2--;
+ }
+ This_Color = color;
+ }
+ return did_scroll;
+}
+
+static void try_scroll (void)
+{
+ int r1, rmin, rmax;
+ int num_up, num_down;
+ /* find region limits. */
+
+ for (rmax = Screen_Rows - 1; rmax > 0; rmax--)
+ {
+ if (SL_Screen[rmax].new_hash != SL_Screen[rmax].old_hash)
+ {
+ r1 = rmax - 1;
+ if ((r1 == 0)
+ || (SL_Screen[r1].new_hash != SL_Screen[r1].old_hash))
+ break;
+
+ rmax = r1;
+ }
+ }
+
+ for (rmin = 0; rmin < rmax; rmin++)
+ {
+ if (SL_Screen[rmin].new_hash != SL_Screen[rmin].old_hash)
+ {
+ r1 = rmin + 1;
+ if ((r1 == rmax)
+ || (SL_Screen[r1].new_hash != SL_Screen[r1].old_hash))
+ break;
+
+ rmin = r1;
+ }
+ }
+
+ /* Below, we have two scrolling algorithms. The first has the effect of
+ * scrolling lines down. This is usually appropriate when one moves
+ * up the display, e.g., with the UP arrow. The second algorithm is
+ * appropriate for going the other way. It is important to choose the
+ * correct one.
+ */
+
+ num_up = 0;
+ for (r1 = rmin; r1 < rmax; r1++)
+ {
+ if (SL_Screen[r1].new_hash == SL_Screen[r1 + 1].old_hash)
+ num_up++;
+ }
+
+ num_down = 0;
+ for (r1 = rmax; r1 > rmin; r1--)
+ {
+ if (SL_Screen[r1 - 1].old_hash == SL_Screen[r1].new_hash)
+ num_down++;
+ }
+
+ if (num_up > num_down)
+ {
+ if (try_scroll_up (rmin, rmax))
+ return;
+
+ (void) try_scroll_down (rmin, rmax);
+ }
+ else
+ {
+ if (try_scroll_down (rmin, rmax))
+ return;
+
+ (void) try_scroll_up (rmin, rmax);
+ }
+}
+#endif /* NOT IBMPC_SYSTEM */
+
+
+#ifdef REQUIRES_NON_BCE_SUPPORT
+static void adjust_colors (void)
+{
+ int bce;
+ int i;
+
+ bce = Bce_Color_Offset;
+ Bce_Color_Offset = _SLtt_get_bce_color_offset ();
+ if (bce == Bce_Color_Offset)
+ return;
+
+ if ((tt_Use_Blink_For_ACS != NULL)
+ && (*tt_Use_Blink_For_ACS != 0))
+ return; /* this mode does not support non-BCE
+ * terminals.
+ */
+
+ for (i = 0; i < Screen_Rows; i++)
+ {
+ SLsmg_Char_Type *s, *smax;
+
+ SL_Screen[i].flags |= TRASHED;
+ s = SL_Screen[i].neew;
+ smax = s + Screen_Cols;
+
+ while (s < smax)
+ {
+ int color = (int) SLSMG_EXTRACT_COLOR(*s);
+ int acs;
+
+ if (color < 0)
+ {
+ s++;
+ continue;
+ }
+
+ acs = color & 0x80;
+ color = (color & 0x7F) - bce;
+ color += Bce_Color_Offset;
+ if (color >= 0)
+ {
+ unsigned char ch = SLSMG_EXTRACT_CHAR(*s);
+ *s = SLSMG_BUILD_CHAR(ch, ((color&0x7F)|acs));
+ }
+ s++;
+ }
+ }
+}
+#endif
+
+void SLsmg_refresh (void)
+{
+ int i;
+#ifndef IBMPC_SYSTEM
+ int trashed = 0;
+#endif
+
+ if (Smg_Inited == 0) return;
+
+ if (Screen_Trashed)
+ {
+ Cls_Flag = 1;
+ for (i = 0; i < Screen_Rows; i++)
+ SL_Screen[i].flags |= TRASHED;
+#ifdef REQUIRES_NON_BCE_SUPPORT
+ adjust_colors ();
+#endif
+ }
+
+#ifndef IBMPC_SYSTEM
+ for (i = 0; i < Screen_Rows; i++)
+ {
+ if (SL_Screen[i].flags == 0) continue;
+ SL_Screen[i].new_hash = compute_hash (SL_Screen[i].neew, Screen_Cols);
+ trashed = 1;
+ }
+#endif
+
+ if (Cls_Flag)
+ {
+ (*tt_normal_video) (); (*tt_cls) ();
+ }
+#ifndef IBMPC_SYSTEM
+ else if (trashed && (*tt_Term_Cannot_Scroll == 0)) try_scroll ();
+#endif
+
+ for (i = 0; i < Screen_Rows; i++)
+ {
+ if (SL_Screen[i].flags == 0) continue;
+
+ if (Cls_Flag || SL_Screen[i].flags & TRASHED)
+ {
+ int color = This_Color;
+
+ if (Cls_Flag == 0)
+ {
+ (*tt_goto_rc) (i, 0);
+ (*tt_del_eol) ();
+ }
+ This_Color = 0;
+ blank_line (SL_Screen[i].old, Screen_Cols, ' ');
+ This_Color = color;
+ }
+
+ SL_Screen[i].old[Screen_Cols] = 0;
+ SL_Screen[i].neew[Screen_Cols] = 0;
+
+ (*tt_smart_puts) (SL_Screen[i].neew, SL_Screen[i].old, Screen_Cols, i);
+
+ SLMEMCPY ((char *) SL_Screen[i].old, (char *) SL_Screen[i].neew,
+ Screen_Cols * sizeof (SLsmg_Char_Type));
+
+ SL_Screen[i].flags = 0;
+#ifndef IBMPC_SYSTEM
+ SL_Screen[i].old_hash = SL_Screen[i].new_hash;
+#endif
+ }
+
+ if (point_visible (1)) (*tt_goto_rc) (This_Row - Start_Row, This_Col - Start_Col);
+ (*tt_flush_output) ();
+ Cls_Flag = 0;
+ Screen_Trashed = 0;
+}
+
+static int compute_clip (int row, int n, int box_start, int box_end,
+ int *rmin, int *rmax)
+{
+ int row_max;
+
+ if (n < 0) return 0;
+ if (row >= box_end) return 0;
+ row_max = row + n;
+ if (row_max <= box_start) return 0;
+
+ if (row < box_start) row = box_start;
+ if (row_max >= box_end) row_max = box_end;
+ *rmin = row;
+ *rmax = row_max;
+ return 1;
+}
+
+void SLsmg_touch_lines (int row, unsigned int n)
+{
+ int i;
+ int r1, r2;
+
+ /* Allow this function to be called even when we are not initialied.
+ * Calling this function is useful after calling SLtt_set_color
+ * to force the display to be redrawn
+ */
+
+ if (Smg_Inited == 0)
+ return;
+
+ if (0 == compute_clip (row, (int) n, Start_Row, Start_Row + Screen_Rows, &r1, &r2))
+ return;
+
+ r1 -= Start_Row;
+ r2 -= Start_Row;
+ for (i = r1; i < r2; i++)
+ {
+ SL_Screen[i].flags |= TRASHED;
+ }
+}
+
+void SLsmg_touch_screen (void)
+{
+ Screen_Trashed = 1;
+}
+
+
+#ifndef IBMPC_SYSTEM
+static char Fake_Alt_Char_Pairs [] = "a:j+k+l+m+q-t+u+v+w+x|n+`+f\\g#~o,<+>.v-^h#0#";
+
+static void init_alt_char_set (void)
+{
+ int i;
+ unsigned char *p, *pmax, ch;
+
+ if (Alt_Char_Set[128] == 128) return;
+
+ i = 32;
+ memset ((char *)Alt_Char_Set, ' ', i);
+ while (i <= 128)
+ {
+ Alt_Char_Set [i] = i;
+ i++;
+ }
+
+ /* Map to VT100 */
+ if (*tt_Has_Alt_Charset)
+ {
+ if (tt_Graphics_Char_Pairs == NULL) p = NULL;
+ else p = (unsigned char *) *tt_Graphics_Char_Pairs;
+ if (p == NULL) return;
+ }
+ else p = (unsigned char *) Fake_Alt_Char_Pairs;
+ pmax = p + strlen ((char *) p);
+
+ /* Some systems have messed up entries for this */
+ while (p < pmax)
+ {
+ ch = *p++;
+ ch &= 0x7F; /* should be unnecessary */
+ Alt_Char_Set [ch] = *p;
+ p++;
+ }
+}
+#endif
+
+#ifndef IBMPC_SYSTEM
+# define BLOCK_SIGNALS SLsig_block_signals ()
+# define UNBLOCK_SIGNALS SLsig_unblock_signals ()
+#else
+# define BLOCK_SIGNALS (void)0
+# define UNBLOCK_SIGNALS (void)0
+#endif
+
+static int Smg_Suspended;
+int SLsmg_suspend_smg (void)
+{
+ BLOCK_SIGNALS;
+
+ if (Smg_Suspended == 0)
+ {
+ (*tt_reset_video) ();
+ Smg_Suspended = 1;
+ }
+
+ UNBLOCK_SIGNALS;
+ return 0;
+}
+
+int SLsmg_resume_smg (void)
+{
+ BLOCK_SIGNALS;
+
+ if (Smg_Suspended == 0)
+ {
+ UNBLOCK_SIGNALS;
+ return 0;
+ }
+
+ Smg_Suspended = 0;
+
+ if (-1 == (*tt_init_video) ())
+ {
+ UNBLOCK_SIGNALS;
+ return -1;
+ }
+
+ Cls_Flag = 1;
+ SLsmg_touch_screen ();
+ SLsmg_refresh ();
+
+ UNBLOCK_SIGNALS;
+ return 0;
+}
+
+
+static void reset_smg (void)
+{
+ int i;
+ if (Smg_Inited == 0)
+ return;
+
+ for (i = 0; i < Screen_Rows; i++)
+ {
+ SLfree ((char *)SL_Screen[i].old);
+ SLfree ((char *)SL_Screen[i].neew);
+ SL_Screen[i].old = SL_Screen[i].neew = NULL;
+ }
+ This_Alt_Char = This_Color = 0;
+ Smg_Inited = 0;
+}
+
+
+static int init_smg (void)
+{
+ int i, len;
+ SLsmg_Char_Type *old, *neew;
+
+ Smg_Inited = 0;
+
+#ifdef REQUIRES_NON_BCE_SUPPORT
+ Bce_Color_Offset = _SLtt_get_bce_color_offset ();
+#endif
+
+ Screen_Rows = *tt_Screen_Rows;
+ if (Screen_Rows > MAX_SCREEN_SIZE)
+ Screen_Rows = MAX_SCREEN_SIZE;
+
+ Screen_Cols = *tt_Screen_Cols;
+
+ This_Col = This_Row = Start_Col = Start_Row = 0;
+
+ This_Alt_Char = 0;
+ SLsmg_set_color (0);
+ Cls_Flag = 1;
+#ifndef IBMPC_SYSTEM
+ init_alt_char_set ();
+#endif
+ len = Screen_Cols + 3;
+ for (i = 0; i < Screen_Rows; i++)
+ {
+ if ((NULL == (old = (SLsmg_Char_Type *) SLmalloc (sizeof(SLsmg_Char_Type) * len)))
+ || ((NULL == (neew = (SLsmg_Char_Type *) SLmalloc (sizeof(SLsmg_Char_Type) * len)))))
+ {
+ SLfree ((char *) old);
+ return -1;
+ }
+ blank_line (old, len, ' ');
+ blank_line (neew, len, ' ');
+ SL_Screen[i].old = old;
+ SL_Screen[i].neew = neew;
+ SL_Screen[i].flags = 0;
+#ifndef IBMPC_SYSTEM
+ Blank_Hash = compute_hash (old, Screen_Cols);
+ SL_Screen[i].new_hash = SL_Screen[i].old_hash = Blank_Hash;
+#endif
+ }
+
+ _SLtt_color_changed_hook = SLsmg_touch_screen;
+ Screen_Trashed = 1;
+ Smg_Inited = 1;
+ return 0;
+}
+
+
+int SLsmg_init_smg (void)
+{
+ int ret;
+
+ BLOCK_SIGNALS;
+
+ if (Smg_Inited)
+ SLsmg_reset_smg ();
+
+ if (-1 == (*tt_init_video) ())
+ {
+ UNBLOCK_SIGNALS;
+ return -1;
+ }
+
+ if (-1 == (ret = init_smg ()))
+ (void) (*tt_reset_video)();
+
+ UNBLOCK_SIGNALS;
+ return ret;
+}
+
+int SLsmg_reinit_smg (void)
+{
+ int ret;
+
+ if (Smg_Inited == 0)
+ return SLsmg_init_smg ();
+
+ BLOCK_SIGNALS;
+ reset_smg ();
+ ret = init_smg ();
+ UNBLOCK_SIGNALS;
+ return ret;
+}
+
+void SLsmg_reset_smg (void)
+{
+ if (Smg_Inited == 0)
+ return;
+
+ BLOCK_SIGNALS;
+
+ reset_smg ();
+ (*tt_reset_video)();
+
+ UNBLOCK_SIGNALS;
+}
+
+SLsmg_Char_Type SLsmg_char_at (void)
+{
+ if (Smg_Inited == 0) return 0;
+
+ if (point_visible (1))
+ {
+ return SL_Screen[This_Row - Start_Row].neew[This_Col - Start_Col];
+ }
+ return 0;
+}
+
+void SLsmg_vprintf (char *fmt, va_list ap)
+{
+ char buf[1024];
+
+ if (Smg_Inited == 0) return;
+
+ (void) _SLvsnprintf (buf, sizeof (buf), fmt, ap);
+ SLsmg_write_string (buf);
+}
+
+void SLsmg_printf (char *fmt, ...)
+{
+ va_list ap;
+ unsigned int len;
+ char *f;
+
+ if (Smg_Inited == 0) return;
+
+ va_start(ap, fmt);
+
+ f = fmt;
+ while (*f && (*f != '%'))
+ f++;
+ len = (unsigned int) (f - fmt);
+ if (len) SLsmg_write_nchars (fmt, len);
+
+ if (*f != 0)
+ SLsmg_vprintf (f, ap);
+
+ va_end (ap);
+}
+
+void SLsmg_set_screen_start (int *r, int *c)
+{
+ int orow = Start_Row, oc = Start_Col;
+
+ if (Smg_Inited == 0) return;
+
+ if (c == NULL) Start_Col = 0;
+ else
+ {
+ Start_Col = *c;
+ *c = oc;
+ }
+ if (r == NULL) Start_Row = 0;
+ else
+ {
+ Start_Row = *r;
+ *r = orow;
+ }
+}
+
+void SLsmg_draw_object (int r, int c, unsigned char object)
+{
+ This_Row = r; This_Col = c;
+
+ if (Smg_Inited == 0) return;
+
+ if (point_visible (1))
+ {
+ int color = This_Color;
+ This_Color |= ALT_CHAR_FLAG;
+ SLsmg_write_char (object);
+ This_Color = color;
+ }
+
+ This_Col = c + 1;
+}
+
+void SLsmg_draw_hline (unsigned int n)
+{
+ static unsigned char hbuf[16];
+ int count;
+ int cmin, cmax;
+ int final_col = This_Col + (int) n;
+ int save_color;
+
+ if (Smg_Inited == 0) return;
+
+ if ((This_Row < Start_Row) || (This_Row >= Start_Row + Screen_Rows)
+ || (0 == compute_clip (This_Col, n, Start_Col, Start_Col + Screen_Cols,
+ &cmin, &cmax)))
+ {
+ This_Col = final_col;
+ return;
+ }
+
+ if (hbuf[0] == 0)
+ {
+ SLMEMSET ((char *) hbuf, SLSMG_HLINE_CHAR, 16);
+ }
+
+ n = (unsigned int)(cmax - cmin);
+ count = n / 16;
+
+ save_color = This_Color;
+ This_Color |= ALT_CHAR_FLAG;
+ This_Col = cmin;
+
+ SLsmg_write_nchars ((char *) hbuf, n % 16);
+ while (count-- > 0)
+ {
+ SLsmg_write_nchars ((char *) hbuf, 16);
+ }
+
+ This_Color = save_color;
+ This_Col = final_col;
+}
+
+void SLsmg_draw_vline (int n)
+{
+ unsigned char ch = SLSMG_VLINE_CHAR;
+ int c = This_Col, rmin, rmax;
+ int final_row = This_Row + n;
+ int save_color;
+
+ if (Smg_Inited == 0) return;
+
+ if (((c < Start_Col) || (c >= Start_Col + Screen_Cols)) ||
+ (0 == compute_clip (This_Row, n, Start_Row, Start_Row + Screen_Rows,
+ &rmin, &rmax)))
+ {
+ This_Row = final_row;
+ return;
+ }
+
+ save_color = This_Color;
+ This_Color |= ALT_CHAR_FLAG;
+
+ for (This_Row = rmin; This_Row < rmax; This_Row++)
+ {
+ This_Col = c;
+ SLsmg_write_nchars ((char *) &ch, 1);
+ }
+
+ This_Col = c; This_Row = final_row;
+ This_Color = save_color;
+}
+
+void SLsmg_draw_box (int r, int c, unsigned int dr, unsigned int dc)
+{
+ if (Smg_Inited == 0) return;
+
+ if (!dr || !dc) return;
+ This_Row = r; This_Col = c;
+ dr--; dc--;
+ SLsmg_draw_hline (dc);
+ SLsmg_draw_vline (dr);
+ This_Row = r; This_Col = c;
+ SLsmg_draw_vline (dr);
+ SLsmg_draw_hline (dc);
+ SLsmg_draw_object (r, c, SLSMG_ULCORN_CHAR);
+ SLsmg_draw_object (r, c + (int) dc, SLSMG_URCORN_CHAR);
+ SLsmg_draw_object (r + (int) dr, c, SLSMG_LLCORN_CHAR);
+ SLsmg_draw_object (r + (int) dr, c + (int) dc, SLSMG_LRCORN_CHAR);
+ This_Row = r; This_Col = c;
+}
+
+void SLsmg_fill_region (int r, int c, unsigned int dr, unsigned int dc, unsigned char ch)
+{
+ static unsigned char hbuf[16];
+ int count;
+ int dcmax, rmax;
+
+ if (Smg_Inited == 0) return;
+
+ SLsmg_gotorc (r, c);
+ r = This_Row; c = This_Col;
+
+ dcmax = Screen_Cols - This_Col;
+ if (dcmax < 0)
+ return;
+
+ if (dc > (unsigned int) dcmax) dc = (unsigned int) dcmax;
+
+ rmax = This_Row + dr;
+ if (rmax > Screen_Rows) rmax = Screen_Rows;
+
+#if 0
+ ch = Alt_Char_Set[ch];
+#endif
+ if (ch != hbuf[0]) SLMEMSET ((char *) hbuf, (char) ch, 16);
+
+ for (This_Row = r; This_Row < rmax; This_Row++)
+ {
+ This_Col = c;
+ count = dc / 16;
+ SLsmg_write_nchars ((char *) hbuf, dc % 16);
+ while (count-- > 0)
+ {
+ SLsmg_write_nchars ((char *) hbuf, 16);
+ }
+ }
+
+ This_Row = r;
+}
+
+void SLsmg_forward (int n)
+{
+ This_Col += n;
+}
+
+void SLsmg_write_color_chars (SLsmg_Char_Type *s, unsigned int len)
+{
+ SLsmg_Char_Type *smax, sh;
+ char buf[32], *b, *bmax;
+ int color, save_color;
+
+ if (Smg_Inited == 0) return;
+
+ smax = s + len;
+ b = buf;
+ bmax = b + sizeof (buf);
+
+ save_color = This_Color;
+
+ while (s < smax)
+ {
+ sh = *s++;
+
+ color = SLSMG_EXTRACT_COLOR(sh);
+
+#if REQUIRES_NON_BCE_SUPPORT
+ if (Bce_Color_Offset)
+ {
+ if (color & 0x80)
+ color = ((color & 0x7F) + Bce_Color_Offset) | 0x80;
+ else
+ color = ((color & 0x7F) + Bce_Color_Offset) & 0x7F;
+ }
+#endif
+
+ if ((color != This_Color) || (b == bmax))
+ {
+ if (b != buf)
+ {
+ SLsmg_write_nchars (buf, (int) (b - buf));
+ b = buf;
+ }
+ This_Color = color;
+ }
+ *b++ = (char) SLSMG_EXTRACT_CHAR(sh);
+ }
+
+ if (b != buf)
+ SLsmg_write_nchars (buf, (unsigned int) (b - buf));
+
+ This_Color = save_color;
+}
+
+unsigned int SLsmg_read_raw (SLsmg_Char_Type *buf, unsigned int len)
+{
+ unsigned int r, c;
+
+ if (Smg_Inited == 0) return 0;
+
+ if (0 == point_visible (1)) return 0;
+
+ r = (unsigned int) (This_Row - Start_Row);
+ c = (unsigned int) (This_Col - Start_Col);
+
+ if (c + len > (unsigned int) Screen_Cols)
+ len = (unsigned int) Screen_Cols - c;
+
+ memcpy ((char *) buf, (char *) (SL_Screen[r].neew + c), len * sizeof (SLsmg_Char_Type));
+ return len;
+}
+
+unsigned int SLsmg_write_raw (SLsmg_Char_Type *buf, unsigned int len)
+{
+ unsigned int r, c;
+ SLsmg_Char_Type *dest;
+
+ if (Smg_Inited == 0) return 0;
+
+ if (0 == point_visible (1)) return 0;
+
+ r = (unsigned int) (This_Row - Start_Row);
+ c = (unsigned int) (This_Col - Start_Col);
+
+ if (c + len > (unsigned int) Screen_Cols)
+ len = (unsigned int) Screen_Cols - c;
+
+ dest = SL_Screen[r].neew + c;
+
+ if (0 != memcmp ((char *) dest, (char *) buf, len * sizeof (SLsmg_Char_Type)))
+ {
+ memcpy ((char *) dest, (char *) buf, len * sizeof (SLsmg_Char_Type));
+ SL_Screen[r].flags |= TOUCHED;
+ }
+ return len;
+}
+
+void
+SLsmg_set_color_in_region (int color, int r, int c, unsigned int dr, unsigned int dc)
+{
+ int cmax, rmax;
+ SLsmg_Char_Type char_mask;
+
+ if (Smg_Inited == 0) return;
+
+ c -= Start_Col;
+ r -= Start_Row;
+
+ cmax = c + (int) dc;
+ rmax = r + (int) dr;
+
+ if (cmax > Screen_Cols) cmax = Screen_Cols;
+ if (rmax > Screen_Rows) rmax = Screen_Rows;
+
+ if (c < 0) c = 0;
+ if (r < 0) r = 0;
+
+#if REQUIRES_NON_BCE_SUPPORT
+ if (Bce_Color_Offset)
+ {
+ if (color & 0x80)
+ color = ((color & 0x7F) + Bce_Color_Offset) | 0x80;
+ else
+ color = ((color & 0x7F) + Bce_Color_Offset) & 0x7F;
+ }
+#endif
+ color = color << 8;
+
+ char_mask = 0xFF;
+
+#ifndef IBMPC_SYSTEM
+ if ((tt_Use_Blink_For_ACS == NULL)
+ || (0 == *tt_Use_Blink_For_ACS))
+ char_mask = 0x80FF;
+#endif
+
+ while (r < rmax)
+ {
+ SLsmg_Char_Type *s, *smax;
+
+ SL_Screen[r].flags |= TOUCHED;
+ s = SL_Screen[r].neew;
+ smax = s + cmax;
+ s += c;
+
+ while (s < smax)
+ {
+ *s = (*s & char_mask) | color;
+ s++;
+ }
+ r++;
+ }
+}
+
+void SLsmg_set_terminal_info (SLsmg_Term_Type *tt)
+{
+ if (tt == NULL) /* use default */
+ return;
+
+ if ((tt->tt_normal_video == NULL)
+ || (tt->tt_goto_rc == NULL)
+ || (tt->tt_cls == NULL)
+ || (tt->tt_del_eol == NULL)
+ || (tt->tt_smart_puts == NULL)
+ || (tt->tt_flush_output == NULL)
+ || (tt->tt_reset_video == NULL)
+ || (tt->tt_init_video == NULL)
+#ifndef IBMPC_SYSTEM
+ || (tt->tt_set_scroll_region == NULL)
+ || (tt->tt_reverse_index == NULL)
+ || (tt->tt_reset_scroll_region == NULL)
+ || (tt->tt_delete_nlines == NULL)
+ /* Variables */
+ || (tt->tt_term_cannot_scroll == NULL)
+ || (tt->tt_has_alt_charset == NULL)
+#if 0 /* These can be NULL */
+ || (tt->tt_use_blink_for_acs == NULL)
+ || (tt->tt_graphic_char_pairs == NULL)
+#endif
+ || (tt->tt_screen_cols == NULL)
+ || (tt->tt_screen_rows == NULL)
+#endif
+ )
+ SLang_exit_error ("Terminal not powerful enough for SLsmg");
+
+ tt_normal_video = tt->tt_normal_video;
+ tt_goto_rc = tt->tt_goto_rc;
+ tt_cls = tt->tt_cls;
+ tt_del_eol = tt->tt_del_eol;
+ tt_smart_puts = tt->tt_smart_puts;
+ tt_flush_output = tt->tt_flush_output;
+ tt_reset_video = tt->tt_reset_video;
+ tt_init_video = tt->tt_init_video;
+
+#ifndef IBMPC_SYSTEM
+ tt_set_scroll_region = tt->tt_set_scroll_region;
+ tt_reverse_index = tt->tt_reverse_index;
+ tt_reset_scroll_region = tt->tt_reset_scroll_region;
+ tt_delete_nlines = tt->tt_delete_nlines;
+
+ tt_Term_Cannot_Scroll = tt->tt_term_cannot_scroll;
+ tt_Has_Alt_Charset = tt->tt_has_alt_charset;
+ tt_Use_Blink_For_ACS = tt->tt_use_blink_for_acs;
+ tt_Graphics_Char_Pairs = tt->tt_graphic_char_pairs;
+#endif
+
+ tt_Screen_Cols = tt->tt_screen_cols;
+ tt_Screen_Rows = tt->tt_screen_rows;
+}
+
diff --git a/mdk-stage1/slang/slstd.c b/mdk-stage1/slang/slstd.c
new file mode 100644
index 000000000..b05dfcddb
--- /dev/null
+++ b/mdk-stage1/slang/slstd.c
@@ -0,0 +1,724 @@
+/* -*- mode: C; mode: fold; -*- */
+/* Standard intrinsic functions for S-Lang. Included here are string
+ and array operations */
+/* Copyright (c) 1992, 1999, 2001 John E. Davis
+ * This file is part of the S-Lang library.
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Perl Artistic License.
+ */
+
+#include "slinclud.h"
+/*{{{ Include Files */
+
+#include <time.h>
+
+#ifndef __QNX__
+# if defined(__GO32__) || defined(__WATCOMC__)
+# include <dos.h>
+# include <bios.h>
+# endif
+#endif
+
+#if SLANG_HAS_FLOAT
+# include <math.h>
+#endif
+
+#include "slang.h"
+#include "_slang.h"
+
+/*}}}*/
+
+/* builtin stack manipulation functions */
+int SLdo_pop(void) /*{{{*/
+{
+ return SLdo_pop_n (1);
+}
+
+/*}}}*/
+
+int SLdo_pop_n (unsigned int n)
+{
+ SLang_Object_Type x;
+
+ while (n--)
+ {
+ if (SLang_pop(&x)) return -1;
+ SLang_free_object (&x);
+ }
+
+ return 0;
+}
+
+static void do_dup(void) /*{{{*/
+{
+ (void) SLdup_n (1);
+}
+
+/*}}}*/
+
+static int length_cmd (void)
+{
+ SLang_Class_Type *cl;
+ SLang_Object_Type obj;
+ VOID_STAR p;
+ unsigned int length;
+ int len;
+
+ if (-1 == SLang_pop (&obj))
+ return -1;
+
+ cl = _SLclass_get_class (obj.data_type);
+ p = _SLclass_get_ptr_to_value (cl, &obj);
+
+ len = 1;
+ if (cl->cl_length != NULL)
+ {
+ if (0 == (*cl->cl_length)(obj.data_type, p, &length))
+ len = (int) length;
+ else
+ len = -1;
+ }
+
+ SLang_free_object (&obj);
+ return len;
+}
+
+/* convert integer to a string of length 1 */
+static void char_cmd (int *x) /*{{{*/
+{
+ char ch, buf[2];
+
+ ch = (char) *x;
+ buf[0] = ch;
+ buf[1] = 0;
+ SLang_push_string (buf);
+}
+
+/*}}}*/
+
+/* format object into a string and returns slstring */
+char *_SLstringize_object (SLang_Object_Type *obj) /*{{{*/
+{
+ SLang_Class_Type *cl;
+ unsigned char stype;
+ VOID_STAR p;
+ char *s, *s1;
+
+ stype = obj->data_type;
+ p = (VOID_STAR) &obj->v.ptr_val;
+
+ cl = _SLclass_get_class (stype);
+
+ s = (*cl->cl_string) (stype, p);
+ if (s != NULL)
+ {
+ s1 = SLang_create_slstring (s);
+ SLfree (s);
+ s = s1;
+ }
+ return s;
+}
+/*}}}*/
+
+int SLang_run_hooks(char *hook, unsigned int num_args, ...)
+{
+ unsigned int i;
+ va_list ap;
+
+ if (SLang_Error) return -1;
+
+ if (0 == SLang_is_defined (hook))
+ return 0;
+
+ (void) SLang_start_arg_list ();
+ va_start (ap, num_args);
+ for (i = 0; i < num_args; i++)
+ {
+ char *arg;
+
+ arg = va_arg (ap, char *);
+ if (-1 == SLang_push_string (arg))
+ break;
+ }
+ va_end (ap);
+ (void) SLang_end_arg_list ();
+
+ if (SLang_Error) return -1;
+ return SLang_execute_function (hook);
+}
+
+static void intrin_getenv_cmd (char *s)
+{
+ SLang_push_string (getenv (s));
+}
+
+#ifdef HAVE_PUTENV
+static void intrin_putenv (void) /*{{{*/
+{
+ char *s;
+
+ /* Some putenv implementations required malloced strings. */
+ if (SLpop_string(&s)) return;
+
+ if (putenv (s))
+ {
+ SLang_Error = SL_INTRINSIC_ERROR;
+ SLfree (s);
+ }
+
+ /* Note that s is NOT freed */
+}
+
+/*}}}*/
+
+#endif
+
+static void lang_print_stack (void) /*{{{*/
+{
+ char buf[32];
+ unsigned int n;
+
+ n = (unsigned int) (_SLStack_Pointer - _SLRun_Stack);
+ while (n)
+ {
+ n--;
+ sprintf (buf, "(%u)", n);
+ _SLdump_objects (buf, _SLRun_Stack + n, 1, 1);
+ }
+}
+
+/*}}}*/
+
+static void byte_compile_file (char *f, int *m)
+{
+ SLang_byte_compile_file (f, *m);
+}
+
+static void intrin_type_info1 (void)
+{
+ SLang_Object_Type obj;
+ unsigned int type;
+
+ if (-1 == SLang_pop (&obj))
+ return;
+
+ type = obj.data_type;
+ if (type == SLANG_ARRAY_TYPE)
+ type = obj.v.array_val->data_type;
+
+ SLang_free_object (&obj);
+
+ _SLang_push_datatype (type);
+}
+
+static void intrin_type_info (void)
+{
+ SLang_Object_Type obj;
+
+ if (-1 == SLang_pop (&obj))
+ return;
+
+ _SLang_push_datatype (obj.data_type);
+ SLang_free_object (&obj);
+}
+
+void _SLstring_intrinsic (void) /*{{{*/
+{
+ SLang_Object_Type x;
+ char *s;
+
+ if (SLang_pop (&x)) return;
+ if (NULL != (s = _SLstringize_object (&x)))
+ _SLang_push_slstring (s);
+
+ SLang_free_object (&x);
+}
+
+/*}}}*/
+
+static void intrin_typecast (void)
+{
+ unsigned char to_type;
+ if (0 == _SLang_pop_datatype (&to_type))
+ (void) SLclass_typecast (to_type, 0, 1);
+}
+
+#if SLANG_HAS_FLOAT
+static void intrin_double (void)
+{
+ (void) SLclass_typecast (SLANG_DOUBLE_TYPE, 0, 1);
+}
+
+#endif
+
+static void intrin_int (void) /*{{{*/
+{
+ (void) SLclass_typecast (SLANG_INT_TYPE, 0, 1);
+}
+
+/*}}}*/
+
+static char *
+intrin_function_name (void)
+{
+ if (NULL == _SLang_Current_Function_Name)
+ return "";
+ return _SLang_Current_Function_Name;
+}
+
+static void intrin_message (char *s)
+{
+ SLang_vmessage ("%s", s);
+}
+
+static void intrin_error (char *s)
+{
+ SLang_verror (SL_USER_ERROR, "%s", s);
+}
+
+static void intrin_pop_n (int *n)
+{
+ SLdo_pop_n ((unsigned int) *n);
+}
+
+static void intrin_reverse_stack (int *n)
+{
+ SLreverse_stack (*n);
+}
+
+static void intrin_roll_stack (int *n)
+{
+ SLroll_stack (*n);
+}
+
+static void usage (void)
+{
+ char *msg;
+
+ _SLstrops_do_sprintf_n (SLang_Num_Function_Args - 1); /* do not include format */
+
+ if (-1 == SLang_pop_slstring (&msg))
+ return;
+
+ SLang_verror (SL_USAGE_ERROR, "Usage: %s", msg);
+ SLang_free_slstring (msg);
+}
+
+/* Convert string to integer */
+static int intrin_integer (char *s)
+{
+ int i;
+
+ i = SLatoi ((unsigned char *) s);
+
+ if (SLang_Error)
+ SLang_verror (SL_TYPE_MISMATCH, "Unable to convert string to integer");
+ return i;
+}
+/*}}}*/
+
+static void guess_type (char *s)
+{
+ _SLang_push_datatype (SLang_guess_type(s));
+}
+
+static int load_file (char *s)
+{
+ if (-1 == SLang_load_file (s))
+ return 0;
+ return 1;
+}
+
+static void get_doc_string (char *file, char *topic)
+{
+ FILE *fp;
+ char line[1024];
+ unsigned int topic_len, str_len;
+ char *str;
+ char ch;
+
+ if (NULL == (fp = fopen (file, "r")))
+ {
+ SLang_push_null ();
+ return;
+ }
+
+ topic_len = strlen (topic);
+ ch = *topic;
+
+ while (1)
+ {
+ if (NULL == fgets (line, sizeof(line), fp))
+ {
+ fclose (fp);
+ (void) SLang_push_null ();
+ return;
+ }
+
+ if ((ch == *line)
+ && (0 == strncmp (line, topic, topic_len))
+ && ((line[topic_len] == '\n') || (line [topic_len] == 0)
+ || (line[topic_len] == ' ') || (line[topic_len] == '\t')))
+ break;
+ }
+
+ if (NULL == (str = SLmake_string (line)))
+ {
+ fclose (fp);
+ (void) SLang_push_null ();
+ return;
+ }
+ str_len = strlen (str);
+
+ while (NULL != fgets (line, sizeof (line), fp))
+ {
+ unsigned int len;
+ char *new_str;
+
+ ch = *line;
+ if (ch == '#') continue;
+ if (ch == '-') break;
+
+ len = strlen (line);
+ if (NULL == (new_str = SLrealloc (str, str_len + len + 1)))
+ {
+ SLfree (str);
+ str = NULL;
+ break;
+ }
+ str = new_str;
+ strcpy (str + str_len, line);
+ str_len += len;
+ }
+
+ fclose (fp);
+
+ (void) SLang_push_malloced_string (str);
+}
+
+static int push_string_array_elements (SLang_Array_Type *at)
+{
+ char **strs;
+ unsigned int num;
+ unsigned int i;
+
+ if (at == NULL)
+ return -1;
+
+ strs = (char **)at->data;
+ num = at->num_elements;
+ for (i = 0; i < num; i++)
+ {
+ if (-1 == SLang_push_string (strs[i]))
+ {
+ SLdo_pop_n (i);
+ return -1;
+ }
+ }
+ SLang_push_integer ((int) num);
+ return 0;
+}
+
+
+static void intrin_apropos (void)
+{
+ int num_args;
+ char *pat;
+ char *namespace_name;
+ unsigned int flags;
+ SLang_Array_Type *at;
+
+ num_args = SLang_Num_Function_Args;
+
+ if (-1 == SLang_pop_uinteger (&flags))
+ return;
+ if (-1 == SLang_pop_slstring (&pat))
+ return;
+
+ namespace_name = NULL;
+ at = NULL;
+ if (num_args == 3)
+ {
+ if (-1 == SLang_pop_slstring (&namespace_name))
+ goto free_and_return;
+ }
+
+ at = _SLang_apropos (namespace_name, pat, flags);
+ if (num_args == 3)
+ {
+ (void) SLang_push_array (at, 0);
+ goto free_and_return;
+ }
+
+ /* Maintain compatibility with old version of the function. That version
+ * did not take three arguments and returned everything to the stack.
+ * Yuk.
+ */
+ (void) push_string_array_elements (at);
+
+ free_and_return:
+ /* NULLs ok */
+ SLang_free_slstring (namespace_name);
+ SLang_free_slstring (pat);
+ SLang_free_array (at);
+}
+
+static int intrin_get_defines (void)
+{
+ int n = 0;
+ char **s = _SLdefines;
+
+ while (*s != NULL)
+ {
+ if (-1 == SLang_push_string (*s))
+ {
+ SLdo_pop_n ((unsigned int) n);
+ return -1;
+ }
+ s++;
+ n++;
+ }
+ return n;
+}
+
+static void intrin_get_reference (char *name)
+{
+ _SLang_push_ref (1, (VOID_STAR) _SLlocate_name (name));
+}
+
+#ifdef HAVE_SYS_UTSNAME_H
+# include <sys/utsname.h>
+#endif
+
+static void uname_cmd (void)
+{
+#ifdef HAVE_UNAME
+ struct utsname u;
+ char *field_names [6];
+ unsigned char field_types[6];
+ VOID_STAR field_values [6];
+ char *ptrs[6];
+ int i;
+
+ if (-1 == uname (&u))
+ (void) SLang_push_null ();
+
+ field_names[0] = "sysname"; ptrs[0] = u.sysname;
+ field_names[1] = "nodename"; ptrs[1] = u.nodename;
+ field_names[2] = "release"; ptrs[2] = u.release;
+ field_names[3] = "version"; ptrs[3] = u.version;
+ field_names[4] = "machine"; ptrs[4] = u.machine;
+
+ for (i = 0; i < 5; i++)
+ {
+ field_types[i] = SLANG_STRING_TYPE;
+ field_values[i] = (VOID_STAR) &ptrs[i];
+ }
+
+ if (0 == SLstruct_create_struct (5, field_names, field_types, field_values))
+ return;
+#endif
+
+ SLang_push_null ();
+}
+
+static void uninitialize_ref_intrin (SLang_Ref_Type *ref)
+{
+ (void) _SLang_uninitialize_ref (ref);
+}
+
+static SLang_Intrin_Fun_Type SLang_Basic_Table [] = /*{{{*/
+{
+ MAKE_INTRINSIC_1("__is_initialized", _SLang_is_ref_initialized, SLANG_INT_TYPE, SLANG_REF_TYPE),
+ MAKE_INTRINSIC_S("__get_reference", intrin_get_reference, SLANG_VOID_TYPE),
+ MAKE_INTRINSIC_1("__uninitialize", uninitialize_ref_intrin, SLANG_VOID_TYPE, SLANG_REF_TYPE),
+ MAKE_INTRINSIC_SS("get_doc_string_from_file", get_doc_string, SLANG_VOID_TYPE),
+ MAKE_INTRINSIC_SS("autoload", SLang_autoload, SLANG_VOID_TYPE),
+ MAKE_INTRINSIC_S("is_defined", SLang_is_defined, SLANG_INT_TYPE),
+ MAKE_INTRINSIC_0("string", _SLstring_intrinsic, SLANG_VOID_TYPE),
+ MAKE_INTRINSIC_0("uname", uname_cmd, SLANG_VOID_TYPE),
+ MAKE_INTRINSIC_S("getenv", intrin_getenv_cmd, SLANG_VOID_TYPE),
+#ifdef HAVE_PUTENV
+ MAKE_INTRINSIC_0("putenv", intrin_putenv, SLANG_VOID_TYPE),
+#endif
+ MAKE_INTRINSIC_S("evalfile", load_file, SLANG_INT_TYPE),
+ MAKE_INTRINSIC_I("char", char_cmd, SLANG_VOID_TYPE),
+ MAKE_INTRINSIC_S("eval", SLang_load_string, SLANG_VOID_TYPE),
+ MAKE_INTRINSIC_0("dup", do_dup, SLANG_VOID_TYPE),
+ MAKE_INTRINSIC_S("integer", intrin_integer, SLANG_INT_TYPE),
+ MAKE_INTRINSIC_S("system", SLsystem, SLANG_INT_TYPE),
+ MAKE_INTRINSIC_0("_apropos", intrin_apropos, SLANG_VOID_TYPE),
+ MAKE_INTRINSIC_S("_trace_function", _SLang_trace_fun, SLANG_VOID_TYPE),
+#if SLANG_HAS_FLOAT
+ MAKE_INTRINSIC_S("atof", _SLang_atof, SLANG_DOUBLE_TYPE),
+ MAKE_INTRINSIC_0("double", intrin_double, SLANG_VOID_TYPE),
+#endif
+ MAKE_INTRINSIC_0("int", intrin_int, SLANG_VOID_TYPE),
+ MAKE_INTRINSIC_0("typecast", intrin_typecast, SLANG_VOID_TYPE),
+ MAKE_INTRINSIC_0("_stkdepth", _SLstack_depth, SLANG_INT_TYPE),
+ MAKE_INTRINSIC_I("_stk_reverse", intrin_reverse_stack, SLANG_VOID_TYPE),
+ MAKE_INTRINSIC_0("typeof", intrin_type_info, VOID_TYPE),
+ MAKE_INTRINSIC_0("_typeof", intrin_type_info1, VOID_TYPE),
+ MAKE_INTRINSIC_I("_pop_n", intrin_pop_n, SLANG_VOID_TYPE),
+ MAKE_INTRINSIC_0("_print_stack", lang_print_stack, SLANG_VOID_TYPE),
+ MAKE_INTRINSIC_I("_stk_roll", intrin_roll_stack, SLANG_VOID_TYPE),
+ MAKE_INTRINSIC_SI("byte_compile_file", byte_compile_file, SLANG_VOID_TYPE),
+ MAKE_INTRINSIC_0("_clear_error", _SLang_clear_error, SLANG_VOID_TYPE),
+ MAKE_INTRINSIC_0("_function_name", intrin_function_name, SLANG_STRING_TYPE),
+#if SLANG_HAS_FLOAT
+ MAKE_INTRINSIC_S("set_float_format", _SLset_double_format, SLANG_VOID_TYPE),
+#endif
+ MAKE_INTRINSIC_S("_slang_guess_type", guess_type, SLANG_VOID_TYPE),
+ MAKE_INTRINSIC_S("error", intrin_error, SLANG_VOID_TYPE),
+ MAKE_INTRINSIC_S("message", intrin_message, SLANG_VOID_TYPE),
+ MAKE_INTRINSIC_0("__get_defined_symbols", intrin_get_defines, SLANG_INT_TYPE),
+ MAKE_INTRINSIC_I("__pop_args", _SLstruct_pop_args, SLANG_VOID_TYPE),
+ MAKE_INTRINSIC_1("__push_args", _SLstruct_push_args, SLANG_VOID_TYPE, SLANG_ARRAY_TYPE),
+ MAKE_INTRINSIC_0("usage", usage, SLANG_VOID_TYPE),
+ MAKE_INTRINSIC_S("implements", _SLang_implements_intrinsic, SLANG_VOID_TYPE),
+ MAKE_INTRINSIC_S("use_namespace", _SLang_use_namespace_intrinsic, SLANG_VOID_TYPE),
+ MAKE_INTRINSIC_0("current_namespace", _SLang_cur_namespace_intrinsic, SLANG_STRING_TYPE),
+ MAKE_INTRINSIC_0("length", length_cmd, SLANG_INT_TYPE),
+ SLANG_END_INTRIN_FUN_TABLE
+};
+
+/*}}}*/
+
+#ifdef SLANG_DOC_DIR
+char *SLang_Doc_Dir = SLANG_DOC_DIR;
+#else
+char *SLang_Doc_Dir = "";
+#endif
+
+static SLang_Intrin_Var_Type Intrin_Vars[] =
+{
+ MAKE_VARIABLE("_debug_info", &_SLang_Compile_Line_Num_Info, SLANG_INT_TYPE, 0),
+ MAKE_VARIABLE("_auto_declare", &_SLang_Auto_Declare_Globals, SLANG_INT_TYPE, 0),
+ MAKE_VARIABLE("_traceback", &SLang_Traceback, SLANG_INT_TYPE, 0),
+ MAKE_VARIABLE("_slangtrace", &_SLang_Trace, SLANG_INT_TYPE, 0),
+ MAKE_VARIABLE("_slang_version", &SLang_Version, SLANG_INT_TYPE, 1),
+ MAKE_VARIABLE("_slang_version_string", &SLang_Version_String, SLANG_STRING_TYPE, 1),
+ MAKE_VARIABLE("_NARGS", &SLang_Num_Function_Args, SLANG_INT_TYPE, 1),
+ MAKE_VARIABLE("_slang_doc_dir", &SLang_Doc_Dir, SLANG_STRING_TYPE, 1),
+ MAKE_VARIABLE("NULL", NULL, SLANG_NULL_TYPE, 1),
+ SLANG_END_INTRIN_VAR_TABLE
+};
+
+int SLang_init_slang (void) /*{{{*/
+{
+ char name[3];
+ unsigned int i;
+ char **s;
+ static char *sys_defines [] =
+ {
+#if defined(__os2__)
+ "OS2",
+#endif
+#if defined(__MSDOS__)
+ "MSDOS",
+#endif
+#if defined(__WIN16__)
+ "WIN16",
+#endif
+#if defined (__WIN32__)
+ "WIN32",
+#endif
+#if defined(__NT__)
+ "NT",
+#endif
+#if defined (VMS)
+ "VMS",
+#endif
+#ifdef REAL_UNIX_SYSTEM
+ "UNIX",
+#endif
+#if SLANG_HAS_FLOAT
+ "SLANG_DOUBLE_TYPE",
+#endif
+ NULL
+ };
+
+ if (-1 == _SLregister_types ()) return -1;
+
+ if ((-1 == SLadd_intrin_fun_table(SLang_Basic_Table, NULL))
+ || (-1 == SLadd_intrin_var_table (Intrin_Vars, NULL))
+ || (-1 == _SLang_init_slstrops ())
+ || (-1 == _SLang_init_sltime ())
+ || (-1 == _SLstruct_init ())
+#if SLANG_HAS_COMPLEX
+ || (-1 == _SLinit_slcomplex ())
+#endif
+#if SLANG_HAS_ASSOC_ARRAYS
+ || (-1 == SLang_init_slassoc ())
+#endif
+ )
+ return -1;
+
+ SLadd_global_variable (SLANG_SYSTEM_NAME);
+
+ s = sys_defines;
+ while (*s != NULL)
+ {
+ if (-1 == SLdefine_for_ifdef (*s)) return -1;
+ s++;
+ }
+
+ /* give temp global variables $0 --> $9 */
+ name[2] = 0; name[0] = '$';
+ for (i = 0; i < 10; i++)
+ {
+ name[1] = (char) (i + '0');
+ SLadd_global_variable (name);
+ }
+
+ SLang_init_case_tables ();
+
+ /* Now add a couple of macros */
+ SLang_load_string (".(_NARGS 1 - Sprintf error)verror");
+ SLang_load_string (".(_NARGS 1 - Sprintf message)vmessage");
+
+ if (SLang_Error)
+ return -1;
+
+ return 0;
+}
+
+/*}}}*/
+
+int SLang_set_argc_argv (int argc, char **argv)
+{
+ static int this_argc;
+ static char **this_argv;
+ int i;
+
+ if (argc < 0) argc = 0;
+ this_argc = argc;
+
+ if (NULL == (this_argv = (char **) SLmalloc ((argc + 1) * sizeof (char *))))
+ return -1;
+ memset ((char *) this_argv, 0, sizeof (char *) * (argc + 1));
+
+ for (i = 0; i < argc; i++)
+ {
+ if (NULL == (this_argv[i] = SLang_create_slstring (argv[i])))
+ goto return_error;
+ }
+
+ if (-1 == SLadd_intrinsic_variable ("__argc", (VOID_STAR)&this_argc,
+ SLANG_INT_TYPE, 1))
+ goto return_error;
+
+ if (-1 == SLang_add_intrinsic_array ("__argv", SLANG_STRING_TYPE, 1,
+ (VOID_STAR) this_argv, 1, argc))
+ goto return_error;
+
+ return 0;
+
+ return_error:
+ for (i = 0; i < argc; i++)
+ SLang_free_slstring (this_argv[i]); /* NULL ok */
+ SLfree ((char *) this_argv);
+
+ return -1;
+}
diff --git a/mdk-stage1/slang/slstdio.c b/mdk-stage1/slang/slstdio.c
new file mode 100644
index 000000000..05db1af77
--- /dev/null
+++ b/mdk-stage1/slang/slstdio.c
@@ -0,0 +1,1050 @@
+/* file stdio intrinsics for S-Lang */
+/* Copyright (c) 1992, 1999, 2001 John E. Davis
+ * This file is part of the S-Lang library.
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Perl Artistic License.
+ */
+
+#include "slinclud.h"
+
+#if defined(__unix__) || (defined (__os2__) && defined (__EMX__))
+# include <sys/types.h>
+#endif
+
+#ifdef HAVE_FCNTL_H
+# include <fcntl.h>
+#endif
+#ifdef HAVE_SYS_FCNTL_H
+# include <sys/fcntl.h>
+#endif
+
+#ifdef __unix__
+# include <sys/file.h>
+#endif
+
+#if defined(__BORLANDC__)
+# include <io.h>
+# include <dir.h>
+#endif
+
+#if defined(__DECC) && defined(VMS)
+# include <unixio.h>
+# include <unixlib.h>
+#endif
+
+#ifdef VMS
+# include <stat.h>
+#else
+# include <sys/stat.h>
+#endif
+
+#include <errno.h>
+
+#define SL_APP_WANTS_FOREACH
+#include "slang.h"
+#include "_slang.h"
+
+typedef struct
+{
+ FILE *fp; /* kind of obvious */
+ char *file; /* file name associated with pointer */
+
+ unsigned int flags; /* modes, etc... */
+#define SL_READ 0x0001
+#define SL_WRITE 0x0002
+#define SL_BINARY 0x0004
+#define SL_FDOPEN 0x2000
+#define SL_PIPE 0x4000
+#define SL_INUSE 0x8000
+}
+SL_File_Table_Type;
+
+static SL_File_Table_Type *SL_File_Table;
+
+static SL_File_Table_Type *get_free_file_table_entry (void)
+{
+ SL_File_Table_Type *t = SL_File_Table, *tmax;
+
+ tmax = t + SL_MAX_FILES;
+ while (t < tmax)
+ {
+ if (t->flags == 0)
+ {
+ memset ((char *) t, 0, sizeof (SL_File_Table_Type));
+ return t;
+ }
+ t++;
+ }
+
+ return NULL;
+}
+
+static unsigned int file_process_flags (char *mode)
+{
+ char ch;
+ unsigned int flags = 0;
+
+ while (1)
+ {
+ ch = *mode++;
+ switch (ch)
+ {
+ case 'r': flags |= SL_READ;
+ break;
+ case 'w':
+ case 'a':
+ case 'A':
+ flags |= SL_WRITE;
+ break;
+ case '+': flags |= SL_WRITE | SL_READ;
+ break;
+ case 'b': flags |= SL_BINARY;
+ break;
+ case 0:
+ return flags;
+
+ default:
+ SLang_verror (SL_INVALID_PARM, "File flag %c is not supported", ch);
+ return 0;
+ }
+ }
+}
+
+static int open_file_type (char *file, int fd, char *mode,
+ FILE *(*open_fun)(char *, char *),
+ int (*close_fun)(FILE *),
+ unsigned int xflags)
+{
+ FILE *fp;
+ SL_File_Table_Type *t;
+ unsigned int flags;
+ SLang_MMT_Type *mmt;
+
+ fp = NULL;
+ t = NULL;
+ mmt = NULL;
+
+ if ((NULL == (t = get_free_file_table_entry ()))
+ || (0 == (flags = file_process_flags(mode))))
+ goto return_error;
+
+ if (fd != -1)
+ fp = fdopen (fd, mode);
+ else
+ fp = open_fun (file, mode);
+
+ if (fp == NULL)
+ {
+ _SLerrno_errno = errno;
+ goto return_error;
+ }
+
+ if (NULL == (mmt = SLang_create_mmt (SLANG_FILE_PTR_TYPE, (VOID_STAR) t)))
+ goto return_error;
+
+ t->fp = fp;
+ t->flags = flags | xflags;
+ fp = NULL; /* allow free_mmt to close fp */
+
+ if ((NULL != (t->file = SLang_create_slstring (file)))
+ && (0 == SLang_push_mmt (mmt)))
+ return 0;
+
+ /* drop */
+
+ return_error:
+ if (fp != NULL) (*close_fun) (fp);
+ if (mmt != NULL) SLang_free_mmt (mmt);
+ (void) SLang_push_null ();
+ return -1;
+}
+
+/* Since some compilers do not have popen/pclose prototyped and in scope,
+ * and pc compilers sometimes have silly prototypes involving PASCAL, etc.
+ * use wrappers around the function to avoid compilation errors.
+ */
+
+static FILE *fopen_fun (char *f, char *m)
+{
+ return fopen (f, m);
+}
+static int fclose_fun (FILE *fp)
+{
+ return fclose (fp);
+}
+
+static void stdio_fopen (char *file, char *mode)
+{
+ (void) open_file_type (file, -1, mode, fopen_fun, fclose_fun, 0);
+}
+
+int _SLstdio_fdopen (char *file, int fd, char *mode)
+{
+ if (fd == -1)
+ {
+ _SLerrno_errno = EBADF;
+ (void) SLang_push_null ();
+ return -1;
+ }
+
+ return open_file_type (file, fd, mode, NULL, fclose_fun, SL_FDOPEN);
+}
+
+#ifdef HAVE_POPEN
+static int pclose_fun (FILE *fp)
+{
+ return pclose (fp);
+}
+
+static FILE *popen_fun (char *file, char *mode)
+{
+ return popen (file, mode);
+}
+
+static void stdio_popen (char *file, char *mode)
+{
+ (void) open_file_type (file, -1, mode, popen_fun, pclose_fun, SL_PIPE);
+}
+#endif
+
+/* returns pointer to file entry if it is open and consistent with
+ flags. Returns NULL otherwise */
+static SLang_MMT_Type *pop_fp (unsigned int flags, FILE **fp_ptr)
+{
+ SL_File_Table_Type *t;
+ SLang_MMT_Type *mmt;
+
+ *fp_ptr = NULL;
+
+ if (NULL == (mmt = SLang_pop_mmt (SLANG_FILE_PTR_TYPE)))
+ return NULL;
+
+ t = (SL_File_Table_Type *) SLang_object_from_mmt (mmt);
+ if ((t->flags & flags)
+ && (NULL != (*fp_ptr = t->fp)))
+ return mmt;
+
+ SLang_free_mmt (mmt);
+ return NULL;
+}
+
+static FILE *check_fp (SL_File_Table_Type *t, unsigned flags)
+{
+ if ((t != NULL) && (t->flags & flags))
+ return t->fp;
+
+ return NULL;
+}
+
+char *SLang_get_name_from_fileptr (SLang_MMT_Type *mmt)
+{
+ SL_File_Table_Type *ft;
+
+ ft = (SL_File_Table_Type *) SLang_object_from_mmt (mmt);
+ if (ft == NULL)
+ return NULL;
+ return ft->file;
+}
+
+int SLang_pop_fileptr (SLang_MMT_Type **mmt, FILE **fp)
+{
+ if (NULL == (*mmt = pop_fp (0xFFFF, fp)))
+ {
+#ifdef EBADF
+ _SLerrno_errno = EBADF;
+#endif
+ return -1;
+ }
+
+ return 0;
+}
+
+static int close_file_type (SL_File_Table_Type *t)
+{
+ int ret = 0;
+ FILE *fp;
+
+ if (t == NULL)
+ return -1;
+
+ fp = t->fp;
+
+ if (NULL == fp) ret = -1;
+ else
+ {
+ if (0 == (t->flags & SL_PIPE))
+ {
+ if (EOF == (ret = fclose (fp)))
+ _SLerrno_errno = errno;
+ }
+#ifdef HAVE_POPEN
+ else
+ {
+ if (-1 == (ret = pclose (fp)))
+ _SLerrno_errno = errno;
+ }
+#endif
+ }
+
+ if (t->file != NULL) SLang_free_slstring (t->file);
+ memset ((char *) t, 0, sizeof (SL_File_Table_Type));
+ return ret;
+}
+
+static int stdio_fclose (SL_File_Table_Type *t)
+{
+ int ret;
+
+ if (NULL == check_fp (t, 0xFFFF))
+ return -1;
+
+ ret = close_file_type (t);
+
+ t->flags = SL_INUSE;
+ return ret;
+}
+
+static int read_one_line (FILE *fp, char **strp, unsigned int *lenp)
+{
+ char buf[512];
+ char *str;
+ unsigned int len;
+
+ *strp = NULL;
+ len = 0;
+ str = NULL;
+
+ while (NULL != fgets (buf, sizeof (buf), fp))
+ {
+ unsigned int dlen;
+ char *new_str;
+ int done_flag;
+
+ dlen = strlen (buf);
+ /* Note: If the file contains embedded \0 characters, then this
+ * fails to work properly since dlen will not be correct.
+ */
+ done_flag = ((dlen + 1 < sizeof (buf))
+ || (buf[dlen - 1] == '\n'));
+
+ if (done_flag && (str == NULL))
+ {
+ /* Avoid the malloc */
+ str = buf;
+ len = dlen;
+ break;
+ }
+
+ if (NULL == (new_str = SLrealloc (str, len + dlen + 1)))
+ {
+ SLfree (str);
+ return -1;
+ }
+
+ str = new_str;
+ strcpy (str + len, buf);
+ len += dlen;
+
+ if (done_flag) break;
+ }
+
+ if (str == NULL)
+ return 0;
+
+ *strp = SLang_create_nslstring (str, len);
+ if (str != buf) SLfree (str);
+
+ if (*strp == NULL) return -1;
+
+ *lenp = len;
+ return 1;
+}
+
+/* returns number of characters read and pushes the string to the stack.
+ If it fails, it returns -1 */
+static int stdio_fgets (SLang_Ref_Type *ref, SL_File_Table_Type *t)
+{
+ char *s;
+ unsigned int len;
+ FILE *fp;
+ int status;
+
+ if (NULL == (fp = check_fp (t, SL_READ)))
+ return -1;
+
+ status = read_one_line (fp, &s, &len);
+ if (status <= 0)
+ return -1;
+
+ status = SLang_assign_to_ref (ref, SLANG_STRING_TYPE, (VOID_STAR)&s);
+ SLang_free_slstring (s);
+
+ if (status == -1)
+ return -1;
+
+ return (int) len;
+}
+
+static void stdio_fgetslines_internal (FILE *fp, unsigned int n)
+{
+ unsigned int num_lines, max_num_lines;
+ char **list;
+ SLang_Array_Type *at;
+ int inum_lines;
+
+ if (n > 1024)
+ max_num_lines = 1024;
+ else
+ {
+ max_num_lines = n;
+ if (max_num_lines == 0)
+ max_num_lines++;
+ }
+
+ list = (char **) SLmalloc (sizeof (char *) * max_num_lines);
+ if (list == NULL)
+ return;
+
+ num_lines = 0;
+ while (num_lines < n)
+ {
+ int status;
+ char *line;
+ unsigned int len;
+
+ status = read_one_line (fp, &line, &len);
+ if (status == -1)
+ goto return_error;
+
+ if (status == 0)
+ break;
+
+ if (max_num_lines == num_lines)
+ {
+ char **new_list;
+
+ if (max_num_lines + 4096 > n)
+ max_num_lines = n;
+ else
+ max_num_lines += 4096;
+
+ new_list = (char **) SLrealloc ((char *)list, sizeof (char *) * max_num_lines);
+ if (new_list == NULL)
+ {
+ SLang_free_slstring (line);
+ goto return_error;
+ }
+ list = new_list;
+ }
+
+ list[num_lines] = line;
+ num_lines++;
+ }
+
+ if (num_lines != max_num_lines)
+ {
+ char **new_list;
+
+ new_list = (char **)SLrealloc ((char *)list, sizeof (char *) * (num_lines + 1));
+ if (new_list == NULL)
+ goto return_error;
+
+ list = new_list;
+ }
+
+ inum_lines = (int) num_lines;
+ if (NULL == (at = SLang_create_array (SLANG_STRING_TYPE, 0, (VOID_STAR) list, &inum_lines, 1)))
+ goto return_error;
+
+ if (-1 == SLang_push_array (at, 1))
+ SLang_push_null ();
+ return;
+
+ return_error:
+ while (num_lines > 0)
+ {
+ num_lines--;
+ SLfree (list[num_lines]);
+ }
+ SLfree ((char *)list);
+ SLang_push_null ();
+}
+
+static void stdio_fgetslines (void)
+{
+ unsigned int n;
+ FILE *fp;
+ SLang_MMT_Type *mmt;
+
+ n = (unsigned int)-1;
+
+ if (SLang_Num_Function_Args == 2)
+ {
+ if (-1 == SLang_pop_uinteger (&n))
+ return;
+ }
+
+ if (NULL == (mmt = pop_fp (SL_READ, &fp)))
+ {
+ SLang_push_null ();
+ return;
+ }
+
+ stdio_fgetslines_internal (fp, n);
+ SLang_free_mmt (mmt);
+}
+
+
+static int stdio_fputs (char *s, SL_File_Table_Type *t)
+{
+ FILE *fp;
+
+ if (NULL == (fp = check_fp (t, SL_WRITE)))
+ return -1;
+
+ if (EOF == fputs(s, fp)) return -1;
+ return (int) strlen (s);
+}
+
+static int stdio_fflush (SL_File_Table_Type *t)
+{
+ FILE *fp;
+
+ if (NULL == (fp = check_fp (t, SL_WRITE)))
+ return -1;
+
+ if (EOF == fflush (fp))
+ {
+ _SLerrno_errno = errno;
+ return -1;
+ }
+
+ return 0;
+}
+
+/* Usage: n = fread (&str, data-type, nelems, fp); */
+static void stdio_fread (SLang_Ref_Type *ref, int *data_typep, unsigned int *num_elemns, SL_File_Table_Type *t)
+{
+ char *s;
+ FILE *fp;
+ int ret;
+ unsigned int num_read, num_to_read;
+ unsigned int nbytes;
+ SLang_Class_Type *cl;
+ unsigned int sizeof_type;
+ int data_type;
+
+ ret = -1;
+ s = NULL;
+ cl = NULL;
+
+ if (NULL == (fp = check_fp (t, SL_READ)))
+ goto the_return;
+
+ /* FIXME: priority = low : I should add some mechanism to support
+ * other types.
+ */
+ data_type = *data_typep;
+
+ cl = _SLclass_get_class ((unsigned char) data_type);
+
+ if (cl->cl_fread == NULL)
+ {
+ SLang_verror (SL_NOT_IMPLEMENTED,
+ "fread does not support %s objects",
+ cl->cl_name);
+ goto the_return;
+ }
+
+ sizeof_type = cl->cl_sizeof_type;
+
+ num_to_read = *num_elemns;
+ nbytes = (unsigned int) num_to_read * sizeof_type;
+
+ s = SLmalloc (nbytes + 1);
+ if (s == NULL)
+ goto the_return;
+
+ ret = cl->cl_fread (data_type, fp, (VOID_STAR)s, num_to_read, &num_read);
+
+ if ((num_read == 0)
+ && (num_read != num_to_read))
+ ret = -1;
+
+ if ((ret == -1) && ferror (fp))
+ _SLerrno_errno = errno;
+
+ if ((ret == 0)
+ && (num_read != num_to_read))
+ {
+ char *new_s;
+
+ nbytes = num_read * sizeof_type;
+ new_s = SLrealloc (s, nbytes + 1);
+ if (new_s == NULL)
+ ret = -1;
+ else
+ s = new_s;
+ }
+
+ if (ret == 0)
+ {
+ if (num_read == 1)
+ {
+ ret = SLang_assign_to_ref (ref, data_type, (VOID_STAR)s);
+ SLfree (s);
+ }
+ else if ((data_type == SLANG_CHAR_TYPE)
+ || (data_type == SLANG_UCHAR_TYPE))
+ {
+ SLang_BString_Type *bs;
+
+ bs = SLbstring_create_malloced ((unsigned char *)s, num_read, 1);
+ ret = SLang_assign_to_ref (ref, SLANG_BSTRING_TYPE, (VOID_STAR)&bs);
+ SLbstring_free (bs);
+ }
+ else
+ {
+ SLang_Array_Type *at;
+ int inum_read = (int) num_read;
+ at = SLang_create_array (data_type, 0, (VOID_STAR)s, &inum_read, 1);
+ ret = SLang_assign_to_ref (ref, SLANG_ARRAY_TYPE, (VOID_STAR)&at);
+ SLang_free_array (at);
+ }
+ s = NULL;
+ }
+
+ the_return:
+
+ if (s != NULL)
+ SLfree (s);
+
+ if (ret == -1)
+ SLang_push_integer (ret);
+ else
+ SLang_push_uinteger (num_read);
+}
+
+/* Usage: n = fwrite (str, fp); */
+static void stdio_fwrite (SL_File_Table_Type *t)
+{
+ FILE *fp;
+ unsigned char *s;
+ unsigned int num_to_write, num_write;
+ int ret;
+ SLang_BString_Type *b;
+ SLang_Array_Type *at;
+ SLang_Class_Type *cl;
+
+ ret = -1;
+ b = NULL;
+ at = NULL;
+
+ switch (SLang_peek_at_stack ())
+ {
+ case SLANG_BSTRING_TYPE:
+ case SLANG_STRING_TYPE:
+ if (-1 == SLang_pop_bstring (&b))
+ goto the_return;
+
+ if (NULL == (s = SLbstring_get_pointer (b, &num_to_write)))
+ goto the_return;
+
+ cl = _SLclass_get_class (SLANG_UCHAR_TYPE);
+ break;
+
+ default:
+ if (-1 == SLang_pop_array (&at, 1))
+ goto the_return;
+
+ cl = at->cl;
+ num_to_write = at->num_elements;
+ s = (unsigned char *) at->data;
+ }
+
+ if (NULL == (fp = check_fp (t, SL_WRITE)))
+ goto the_return;
+
+ if (cl->cl_fwrite == NULL)
+ {
+ SLang_verror (SL_NOT_IMPLEMENTED,
+ "fwrite does not support %s objects", cl->cl_name);
+ goto the_return;
+ }
+
+ ret = cl->cl_fwrite (cl->cl_data_type, fp, s, num_to_write, &num_write);
+
+ if ((ret == -1) && ferror (fp))
+ _SLerrno_errno = errno;
+
+ /* drop */
+ the_return:
+ if (b != NULL)
+ SLbstring_free (b);
+ if (at != NULL)
+ SLang_free_array (at);
+
+ if (ret == -1)
+ SLang_push_integer (ret);
+ else
+ SLang_push_uinteger (num_write);
+}
+
+static int stdio_fseek (SL_File_Table_Type *t, int *ofs, int *whence)
+{
+ FILE *fp;
+
+ if (NULL == (fp = check_fp (t, 0xFFFF)))
+ return -1;
+
+ if (-1 == fseek (fp, (long) *ofs, *whence))
+ {
+ _SLerrno_errno = errno;
+ return -1;
+ }
+
+ return 0;
+}
+
+static int stdio_ftell (SL_File_Table_Type *t)
+{
+ FILE *fp;
+ long ofs;
+
+ if (NULL == (fp = check_fp (t, 0xFFFF)))
+ return -1;
+
+ if (-1L == (ofs = ftell (fp)))
+ {
+ _SLerrno_errno = errno;
+ return -1;
+ }
+
+ return (int) ofs;
+}
+
+static int stdio_feof (SL_File_Table_Type *t)
+{
+ FILE *fp;
+
+ if (NULL == (fp = check_fp (t, 0xFFFF)))
+ return -1;
+
+ return feof (fp);
+}
+
+static int stdio_ferror (SL_File_Table_Type *t)
+{
+ FILE *fp;
+
+ if (NULL == (fp = check_fp (t, 0xFFFF)))
+ return -1;
+
+ return ferror (fp);
+}
+
+static void stdio_clearerr (SL_File_Table_Type *t)
+{
+ FILE *fp;
+
+ if (NULL != (fp = check_fp (t, 0xFFFF)))
+ clearerr (fp);
+}
+
+/* () = fprintf (fp, "FORMAT", arg...); */
+static int stdio_fprintf (void)
+{
+ char *s;
+ FILE *fp;
+ SLang_MMT_Type *mmt;
+ int status;
+
+ if (-1 == _SLstrops_do_sprintf_n (SLang_Num_Function_Args - 2))
+ return -1;
+
+ if (-1 == SLang_pop_slstring (&s))
+ return -1;
+
+ if (NULL == (mmt = pop_fp (SL_WRITE, &fp)))
+ {
+ SLang_free_slstring (s);
+ return -1;
+ }
+
+ if (EOF == fputs(s, fp))
+ status = -1;
+ else
+ status = (int) strlen (s);
+
+ SLang_free_mmt (mmt);
+ SLang_free_slstring (s);
+ return status;
+}
+
+static int stdio_printf (void)
+{
+ char *s;
+ int status;
+
+ if (-1 == _SLstrops_do_sprintf_n (SLang_Num_Function_Args - 1))
+ return -1;
+
+ if (-1 == SLang_pop_slstring (&s))
+ return -1;
+
+ if (EOF == fputs(s, stdout))
+ status = -1;
+ else
+ status = (int) strlen (s);
+
+ SLang_free_slstring (s);
+ return status;
+}
+
+
+#define F SLANG_FILE_PTR_TYPE
+#define R SLANG_REF_TYPE
+#define I SLANG_INT_TYPE
+#define V SLANG_VOID_TYPE
+#define S SLANG_STRING_TYPE
+#define B SLANG_BSTRING_TYPE
+#define U SLANG_UINT_TYPE
+#define D SLANG_DATATYPE_TYPE
+static SLang_Intrin_Fun_Type Stdio_Name_Table[] =
+{
+ MAKE_INTRINSIC_0("fgetslines", stdio_fgetslines, V),
+ MAKE_INTRINSIC_SS("fopen", stdio_fopen, V),
+ MAKE_INTRINSIC_1("feof", stdio_feof, I, F),
+ MAKE_INTRINSIC_1("ferror", stdio_ferror, I, F),
+ MAKE_INTRINSIC_1("fclose", stdio_fclose, I, F),
+ MAKE_INTRINSIC_2("fgets", stdio_fgets, I, R, F),
+ MAKE_INTRINSIC_1("fflush", stdio_fflush, I, F),
+ MAKE_INTRINSIC_2("fputs", stdio_fputs, I, S, F),
+ MAKE_INTRINSIC_0("fprintf", stdio_fprintf, I),
+ MAKE_INTRINSIC_0("printf", stdio_printf, I),
+ MAKE_INTRINSIC_3("fseek", stdio_fseek, I, F, I, I),
+ MAKE_INTRINSIC_1("ftell", stdio_ftell, I, F),
+ MAKE_INTRINSIC_1("clearerr", stdio_clearerr, V, F),
+ MAKE_INTRINSIC_4("fread", stdio_fread, V, R, D, U, F),
+ MAKE_INTRINSIC_1("fwrite", stdio_fwrite, V, F),
+#ifdef HAVE_POPEN
+ MAKE_INTRINSIC_SS("popen", stdio_popen, V),
+ MAKE_INTRINSIC_1("pclose", stdio_fclose, I, F),
+#endif
+ SLANG_END_INTRIN_FUN_TABLE
+};
+#undef F
+#undef I
+#undef R
+#undef V
+#undef S
+#undef B
+#undef U
+#undef D
+
+#ifndef SEEK_SET
+# define SEEK_SET 0
+#endif
+#ifndef SEEK_CUR
+# define SEEK_CUR 1
+#endif
+#ifndef SEEK_END
+# define SEEK_END 2
+#endif
+
+static SLang_IConstant_Type Stdio_Consts [] =
+{
+ MAKE_ICONSTANT("SEEK_SET", SEEK_SET),
+ MAKE_ICONSTANT("SEEK_END", SEEK_END),
+ MAKE_ICONSTANT("SEEK_CUR", SEEK_CUR),
+ SLANG_END_ICONST_TABLE
+};
+
+static void destroy_file_type (unsigned char type, VOID_STAR ptr)
+{
+ (void) type;
+ (void) close_file_type ((SL_File_Table_Type *) ptr);
+}
+
+
+struct _SLang_Foreach_Context_Type
+{
+ SLang_MMT_Type *mmt;
+ FILE *fp;
+#define CTX_USE_LINE 1
+#define CTX_USE_CHAR 2
+ unsigned char type;
+};
+
+
+static SLang_Foreach_Context_Type *
+cl_foreach_open (unsigned char type, unsigned int num)
+{
+ SLang_Foreach_Context_Type *c;
+ SLang_MMT_Type *mmt;
+ FILE *fp;
+
+ if (NULL == (mmt = pop_fp (SL_READ, &fp)))
+ return NULL;
+
+ type = CTX_USE_LINE;
+
+ switch (num)
+ {
+ char *s;
+
+ case 0:
+ type = CTX_USE_LINE;
+ break;
+
+ case 1:
+ if (-1 == SLang_pop_slstring (&s))
+ {
+ SLang_free_mmt (mmt);
+ return NULL;
+ }
+ if (0 == strcmp (s, "char"))
+ type = CTX_USE_CHAR;
+ else if (0 == strcmp (s, "line"))
+ type = CTX_USE_LINE;
+ else
+ {
+ SLang_verror (SL_NOT_IMPLEMENTED,
+ "using '%s' not supported by File_Type",
+ s);
+ SLang_free_slstring (s);
+ SLang_free_mmt (mmt);
+ return NULL;
+ }
+ SLang_free_slstring (s);
+ break;
+
+ default:
+ SLdo_pop_n (num);
+ SLang_verror (SL_NOT_IMPLEMENTED,
+ "Usage: foreach (File_Type) using ([line|char])");
+ SLang_free_mmt (mmt);
+ return NULL;
+ }
+
+ if (NULL == (c = (SLang_Foreach_Context_Type *) SLmalloc (sizeof (SLang_Foreach_Context_Type))))
+ {
+ SLang_free_mmt (mmt);
+ return NULL;
+ }
+ memset ((char *) c, 0, sizeof (SLang_Foreach_Context_Type));
+
+ c->type = type;
+ c->mmt = mmt;
+ c->fp = fp;
+
+ return c;
+}
+
+static void cl_foreach_close (unsigned char type, SLang_Foreach_Context_Type *c)
+{
+ (void) type;
+ if (c == NULL) return;
+ SLang_free_mmt (c->mmt);
+ SLfree ((char *) c);
+}
+
+static int cl_foreach (unsigned char type, SLang_Foreach_Context_Type *c)
+{
+ int status;
+ int ch;
+ unsigned int len;
+ char *s;
+
+ (void) type;
+
+ if (c == NULL)
+ return -1;
+
+ switch (c->type)
+ {
+ case CTX_USE_CHAR:
+ if (EOF == (ch = getc (c->fp)))
+ return 0;
+ if (-1 == SLang_push_uchar ((unsigned char) ch))
+ return -1;
+ return 1;
+
+ case CTX_USE_LINE:
+ status = read_one_line (c->fp, &s, &len);
+ if (status <= 0)
+ return status;
+ if (0 == _SLang_push_slstring (s))
+ return 1;
+ return -1;
+ }
+
+ return -1;
+}
+
+static int Stdio_Initialized;
+static SLang_MMT_Type *Stdio_Mmts[3];
+
+int SLang_init_stdio (void)
+{
+ unsigned int i;
+ SL_File_Table_Type *s;
+ SLang_Class_Type *cl;
+ char *names[3];
+
+ if (Stdio_Initialized)
+ return 0;
+
+ SL_File_Table = (SL_File_Table_Type *)SLcalloc(sizeof (SL_File_Table_Type), SL_MAX_FILES);
+ if (SL_File_Table == NULL)
+ return -1;
+
+ if (NULL == (cl = SLclass_allocate_class ("File_Type")))
+ return -1;
+ cl->cl_destroy = destroy_file_type;
+ cl->cl_foreach_open = cl_foreach_open;
+ cl->cl_foreach_close = cl_foreach_close;
+ cl->cl_foreach = cl_foreach;
+
+
+ if (-1 == SLclass_register_class (cl, SLANG_FILE_PTR_TYPE, sizeof (SL_File_Table_Type), SLANG_CLASS_TYPE_MMT))
+ return -1;
+
+ if ((-1 == SLadd_intrin_fun_table(Stdio_Name_Table, "__STDIO__"))
+ || (-1 == SLadd_iconstant_table (Stdio_Consts, NULL))
+ || (-1 == _SLerrno_init ()))
+ return -1;
+
+ names[0] = "stdin";
+ names[1] = "stdout";
+ names[2] = "stderr";
+
+ s = SL_File_Table;
+ s->fp = stdin; s->flags = SL_READ;
+
+ s++;
+ s->fp = stdout; s->flags = SL_WRITE;
+
+ s++;
+ s->fp = stderr; s->flags = SL_WRITE|SL_READ;
+
+ s = SL_File_Table;
+ for (i = 0; i < 3; i++)
+ {
+ if (NULL == (s->file = SLang_create_slstring (names[i])))
+ return -1;
+
+ if (NULL == (Stdio_Mmts[i] = SLang_create_mmt (SLANG_FILE_PTR_TYPE, (VOID_STAR) s)))
+ return -1;
+ SLang_inc_mmt (Stdio_Mmts[i]);
+
+ if (-1 == SLadd_intrinsic_variable (s->file, (VOID_STAR)&Stdio_Mmts[i], SLANG_FILE_PTR_TYPE, 1))
+ return -1;
+ s++;
+ }
+
+ Stdio_Initialized = 1;
+ return 0;
+}
+
diff --git a/mdk-stage1/slang/slstring.c b/mdk-stage1/slang/slstring.c
new file mode 100644
index 000000000..529c41827
--- /dev/null
+++ b/mdk-stage1/slang/slstring.c
@@ -0,0 +1,546 @@
+/* Copyright (c) 1998, 1999, 2001 John E. Davis
+ * This file is part of the S-Lang library.
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Perl Artistic License.
+ */
+#include "slinclud.h"
+
+#include "slang.h"
+#include "_slang.h"
+
+typedef struct _SLstring_Type
+{
+ struct _SLstring_Type *next;
+ unsigned int ref_count;
+ char bytes [1];
+}
+SLstring_Type;
+
+static SLstring_Type *String_Hash_Table [SLSTRING_HASH_TABLE_SIZE];
+static char Single_Char_Strings [256 * 2];
+
+#if _SLANG_OPTIMIZE_FOR_SPEED
+#define MAX_FREE_STORE_LEN 32
+static SLstring_Type *SLS_Free_Store [MAX_FREE_STORE_LEN];
+
+# define NUM_CACHED_STRINGS 601
+typedef struct
+{
+ unsigned long hash;
+ SLstring_Type *sls;
+ unsigned int len;
+}
+Cached_String_Type;
+static Cached_String_Type Cached_Strings [NUM_CACHED_STRINGS];
+
+#define GET_CACHED_STRING(s) \
+ (Cached_Strings + (unsigned int)(((unsigned long) (s)) % NUM_CACHED_STRINGS))
+
+_INLINE_
+static void cache_string (SLstring_Type *sls, unsigned int len, unsigned long hash)
+{
+ Cached_String_Type *cs;
+
+ cs = GET_CACHED_STRING(sls->bytes);
+ cs->sls = sls;
+ cs->hash = hash;
+ cs->len = len;
+}
+
+_INLINE_
+static void uncache_string (char *s)
+{
+ Cached_String_Type *cs;
+
+ cs = GET_CACHED_STRING(s);
+ if ((cs->sls != NULL)
+ && (cs->sls->bytes == s))
+ cs->sls = NULL;
+}
+#endif
+
+
+
+_INLINE_
+unsigned long _SLstring_hash (unsigned char *s, unsigned char *smax)
+{
+ register unsigned long h = 0;
+ register unsigned long sum = 0;
+ unsigned char *smax4;
+
+ smax4 = smax - 4;
+
+ while (s < smax4)
+ {
+ sum += s[0];
+ h = sum + (h << 1);
+ sum += s[1];
+ h = sum + (h << 1);
+ sum += s[2];
+ h = sum + (h << 1);
+ sum += s[3];
+ h = sum + (h << 1);
+
+ s += 4;
+ }
+
+ while (s < smax)
+ {
+ sum += *s++;
+ h ^= sum + (h << 3); /* slightly different */
+ }
+
+ return h;
+}
+
+unsigned long _SLcompute_string_hash (char *s)
+{
+#if _SLANG_OPTIMIZE_FOR_SPEED
+ Cached_String_Type *cs;
+ SLstring_Type *sls;
+
+ cs = GET_CACHED_STRING(s);
+ if (((sls = cs->sls) != NULL)
+ && (sls->bytes == s))
+ return cs->hash;
+#endif
+ return _SLstring_hash ((unsigned char *) s, (unsigned char *) s + strlen (s));
+}
+
+_INLINE_
+/* This routine works with any (long) string */
+static SLstring_Type *find_string (char *s, unsigned int len, unsigned long hash)
+{
+ SLstring_Type *sls;
+ char ch;
+
+ sls = String_Hash_Table [(unsigned int)(hash % SLSTRING_HASH_TABLE_SIZE)];
+
+ if (sls == NULL)
+ return NULL;
+
+ ch = s[0];
+ do
+ {
+ char *bytes = sls->bytes;
+
+ /* Note that we need to actually make sure that bytes[len] == 0.
+ * In this case, it is not enough to just compare pointers. In fact,
+ * this is called from create_nstring, etc... It is unlikely that the
+ * pointer is a slstring
+ */
+ if ((/* (s == bytes) || */ ((ch == bytes[0])
+ && (0 == strncmp (s, bytes, len))))
+ && (bytes [len] == 0))
+ break;
+
+ sls = sls->next;
+ }
+ while (sls != NULL);
+
+ return sls;
+}
+
+_INLINE_
+static SLstring_Type *find_slstring (char *s, unsigned long hash)
+{
+ SLstring_Type *sls;
+
+ sls = String_Hash_Table [(unsigned int)(hash % SLSTRING_HASH_TABLE_SIZE)];
+ while (sls != NULL)
+ {
+ if (s == sls->bytes)
+ return sls;
+
+ sls = sls->next;
+ }
+ return sls;
+}
+
+_INLINE_
+static SLstring_Type *allocate_sls (unsigned int len)
+{
+ SLstring_Type *sls;
+
+#if _SLANG_OPTIMIZE_FOR_SPEED
+ if ((len < MAX_FREE_STORE_LEN)
+ && (NULL != (sls = SLS_Free_Store [len])))
+ {
+ SLS_Free_Store[len] = NULL;
+ return sls;
+ }
+#endif
+ /* FIXME: use structure padding */
+ return (SLstring_Type *) SLmalloc (len + sizeof (SLstring_Type));
+}
+
+_INLINE_
+static void free_sls (SLstring_Type *sls, unsigned int len)
+{
+#if _SLANG_OPTIMIZE_FOR_SPEED
+ if ((len < MAX_FREE_STORE_LEN)
+ && (SLS_Free_Store[len] == NULL))
+ {
+ SLS_Free_Store [len] = sls;
+ return;
+ }
+#else
+ (void) len;
+#endif
+ SLfree ((char *)sls);
+}
+
+_INLINE_
+static char *create_long_string (char *s, unsigned int len, unsigned long hash)
+{
+ SLstring_Type *sls;
+
+ sls = find_string (s, len, hash);
+
+ if (sls != NULL)
+ {
+ sls->ref_count++;
+ s = sls->bytes;
+
+#if _SLANG_OPTIMIZE_FOR_SPEED
+ cache_string (sls, len, hash);
+#endif
+ return s;
+ }
+
+ sls = allocate_sls (len);
+ if (sls == NULL)
+ return NULL;
+
+ strncpy (sls->bytes, s, len);
+ sls->bytes[len] = 0;
+ sls->ref_count = 1;
+
+#if _SLANG_OPTIMIZE_FOR_SPEED
+ cache_string (sls, len, hash);
+#endif
+
+ hash = hash % SLSTRING_HASH_TABLE_SIZE;
+ sls->next = String_Hash_Table [(unsigned int)hash];
+ String_Hash_Table [(unsigned int)hash] = sls;
+
+ return sls->bytes;
+}
+
+_INLINE_
+static char *create_short_string (char *s, unsigned int len)
+{
+ char ch;
+
+ /* Note: if len is 0, then it does not matter what *s is. This is
+ * important for SLang_create_nslstring.
+ */
+ if (len) ch = *s; else ch = 0;
+
+ len = 2 * (unsigned int) ((unsigned char) ch);
+ Single_Char_Strings [len] = ch;
+ Single_Char_Strings [len + 1] = 0;
+ return Single_Char_Strings + len;
+}
+
+/* s cannot be NULL */
+_INLINE_
+static char *create_nstring (char *s, unsigned int len, unsigned long *hash_ptr)
+{
+ unsigned long hash;
+
+ if (len < 2)
+ return create_short_string (s, len);
+
+ hash = _SLstring_hash ((unsigned char *) s, (unsigned char *) (s + len));
+ *hash_ptr = hash;
+
+ return create_long_string (s, len, hash);
+}
+
+char *SLang_create_nslstring (char *s, unsigned int len)
+{
+ unsigned long hash;
+ return create_nstring (s, len, &hash);
+}
+
+char *_SLstring_make_hashed_string (char *s, unsigned int len, unsigned long *hashptr)
+{
+ unsigned long hash;
+
+ if (s == NULL) return NULL;
+
+ hash = _SLstring_hash ((unsigned char *) s, (unsigned char *) s + len);
+ *hashptr = hash;
+
+ if (len < 2)
+ return create_short_string (s, len);
+
+ return create_long_string (s, len, hash);
+}
+
+char *_SLstring_dup_hashed_string (char *s, unsigned long hash)
+{
+ unsigned int len;
+#if _SLANG_OPTIMIZE_FOR_SPEED
+ Cached_String_Type *cs;
+ SLstring_Type *sls;
+
+ if (s == NULL) return NULL;
+ if (s[0] == 0)
+ return create_short_string (s, 0);
+ if (s[1] == 0)
+ return create_short_string (s, 1);
+
+ cs = GET_CACHED_STRING(s);
+ if (((sls = cs->sls) != NULL)
+ && (sls->bytes == s))
+ {
+ sls->ref_count += 1;
+ return s;
+ }
+#else
+ if (s == NULL) return NULL;
+#endif
+
+ len = strlen (s);
+#if !_SLANG_OPTIMIZE_FOR_SPEED
+ if (len < 2) return create_short_string (s, len);
+#endif
+
+ return create_long_string (s, len, hash);
+}
+
+char *_SLstring_dup_slstring (char *s)
+{
+ SLstring_Type *sls;
+ unsigned int len;
+ unsigned long hash;
+#if _SLANG_OPTIMIZE_FOR_SPEED
+ Cached_String_Type *cs;
+
+ cs = GET_CACHED_STRING(s);
+ if (((sls = cs->sls) != NULL)
+ && (sls->bytes == s))
+ {
+ sls->ref_count += 1;
+ return s;
+ }
+#endif
+
+ if ((s == NULL) || ((len = strlen (s)) < 2))
+ return s;
+
+ hash = _SLstring_hash ((unsigned char *)s, (unsigned char *)(s + len));
+
+ sls = find_slstring (s, hash);
+ if (sls == NULL)
+ {
+ SLang_Error = SL_INTERNAL_ERROR;
+ return NULL;
+ }
+
+ sls->ref_count++;
+#if _SLANG_OPTIMIZE_FOR_SPEED
+ cache_string (sls, len, hash);
+#endif
+ return s;
+}
+
+static void free_sls_string (SLstring_Type *sls, char *s, unsigned int len,
+ unsigned long hash)
+{
+ SLstring_Type *sls1, *prev;
+
+#if _SLANG_OPTIMIZE_FOR_SPEED
+ uncache_string (s);
+#endif
+
+ hash = hash % SLSTRING_HASH_TABLE_SIZE;
+
+ sls1 = String_Hash_Table [(unsigned int) hash];
+
+ prev = NULL;
+
+ /* This should not fail. */
+ while (sls1 != sls)
+ {
+ prev = sls1;
+ sls1 = sls1->next;
+ }
+
+ if (prev != NULL)
+ prev->next = sls->next;
+ else
+ String_Hash_Table [(unsigned int) hash] = sls->next;
+
+ free_sls (sls, len);
+}
+
+_INLINE_
+static void free_long_string (char *s, unsigned int len, unsigned long hash)
+{
+ SLstring_Type *sls;
+
+ if (NULL == (sls = find_slstring (s, hash)))
+ {
+ SLang_doerror ("Application internal error: invalid attempt to free string");
+ return;
+ }
+
+ sls->ref_count--;
+ if (sls->ref_count != 0)
+ {
+#if _SLANG_OPTIMIZE_FOR_SPEED
+ /* cache_string (sls, len, hash); */
+#endif
+ return;
+ }
+
+
+ free_sls_string (sls, s, len, hash);
+}
+
+/* This routine may be passed NULL-- it is not an error. */
+void SLang_free_slstring (char *s)
+{
+ unsigned long hash;
+ unsigned int len;
+#if _SLANG_OPTIMIZE_FOR_SPEED
+ Cached_String_Type *cs;
+ SLstring_Type *sls;
+
+ cs = GET_CACHED_STRING(s);
+ if (((sls = cs->sls) != NULL)
+ && (sls->bytes == s))
+ {
+ if (sls->ref_count <= 1)
+ free_sls_string (sls, s, cs->len, cs->hash);
+ else
+ sls->ref_count -= 1;
+ return;
+ }
+#endif
+
+ if (s == NULL) return;
+
+ if ((len = strlen (s)) < 2)
+ return;
+
+ hash = _SLstring_hash ((unsigned char *)s, (unsigned char *) s + len);
+ free_long_string (s, len, hash);
+}
+
+char *SLang_create_slstring (char *s)
+{
+ unsigned long hash;
+#if _SLANG_OPTIMIZE_FOR_SPEED
+ Cached_String_Type *cs;
+ SLstring_Type *sls;
+
+ cs = GET_CACHED_STRING(s);
+ if (((sls = cs->sls) != NULL)
+ && (sls->bytes == s))
+ {
+ sls->ref_count += 1;
+ return s;
+ }
+#endif
+
+ if (s == NULL) return NULL;
+ return create_nstring (s, strlen (s), &hash);
+}
+
+void _SLfree_hashed_string (char *s, unsigned int len, unsigned long hash)
+{
+ if ((s == NULL) || (len < 2)) return;
+ free_long_string (s, len, hash);
+}
+
+
+char *_SLallocate_slstring (unsigned int len)
+{
+ SLstring_Type *sls = allocate_sls (len);
+ if (sls == NULL)
+ return NULL;
+
+ return sls->bytes;
+}
+
+void _SLunallocate_slstring (char *s, unsigned int len)
+{
+ SLstring_Type *sls;
+
+ if (s == NULL)
+ return;
+
+ sls = (SLstring_Type *) (s - offsetof(SLstring_Type,bytes[0]));
+ free_sls (sls, len);
+}
+
+char *_SLcreate_via_alloced_slstring (char *s, unsigned int len)
+{
+ unsigned long hash;
+ SLstring_Type *sls;
+
+ if (s == NULL)
+ return NULL;
+
+ if (len < 2)
+ {
+ char *s1 = create_short_string (s, len);
+ _SLunallocate_slstring (s, len);
+ return s1;
+ }
+
+ /* s is not going to be in the cache because when it was malloced, its
+ * value was unknown. This simplifies the coding.
+ */
+ hash = _SLstring_hash ((unsigned char *)s, (unsigned char *)s + len);
+ sls = find_string (s, len, hash);
+ if (sls != NULL)
+ {
+ sls->ref_count++;
+ _SLunallocate_slstring (s, len);
+ s = sls->bytes;
+
+#if _SLANG_OPTIMIZE_FOR_SPEED
+ cache_string (sls, len, hash);
+#endif
+ return s;
+ }
+
+ sls = (SLstring_Type *) (s - offsetof(SLstring_Type,bytes[0]));
+ sls->ref_count = 1;
+
+#if _SLANG_OPTIMIZE_FOR_SPEED
+ cache_string (sls, len, hash);
+#endif
+
+ hash = hash % SLSTRING_HASH_TABLE_SIZE;
+ sls->next = String_Hash_Table [(unsigned int)hash];
+ String_Hash_Table [(unsigned int)hash] = sls;
+
+ return s;
+}
+
+/* Note, a and b may be ordinary strings. The result is an slstring */
+char *SLang_concat_slstrings (char *a, char *b)
+{
+ unsigned int lena, len;
+ char *c;
+
+ lena = strlen (a);
+ len = lena + strlen (b);
+
+ c = _SLallocate_slstring (len);
+ if (c == NULL)
+ return NULL;
+
+ strcpy (c, a);
+ strcpy (c + lena, b);
+
+ return _SLcreate_via_alloced_slstring (c, len);
+}
+
diff --git a/mdk-stage1/slang/slstrops.c b/mdk-stage1/slang/slstrops.c
new file mode 100644
index 000000000..a57ef6389
--- /dev/null
+++ b/mdk-stage1/slang/slstrops.c
@@ -0,0 +1,1686 @@
+/* -*- mode: C; mode: fold; -*- */
+/* string manipulation functions for S-Lang. */
+/* Copyright (c) 1992, 1999, 2001 John E. Davis
+ * This file is part of the S-Lang library.
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Perl Artistic License.
+ */
+
+#include "slinclud.h"
+/*{{{ Include Files */
+
+#include <time.h>
+
+#ifndef __QNX__
+# if defined(__GO32__) || defined(__WATCOMC__)
+# include <dos.h>
+# include <bios.h>
+# endif
+#endif
+
+#if SLANG_HAS_FLOAT
+#include <math.h>
+#endif
+
+#include <string.h>
+#include <stdarg.h>
+#include <ctype.h>
+
+#ifndef isdigit
+# define isdigit(x) (((x) >= '0') && ((x) <= '9'))
+#endif
+
+#include "slang.h"
+#include "_slang.h"
+
+/*}}}*/
+
+#define USE_ALLOC_STSTRING 1
+
+/*{{{ Utility Functions */
+
+static char Utility_Char_Table [256];
+static unsigned char WhiteSpace_Lut[256];
+
+static void set_utility_char_table (char *pos) /*{{{*/
+{
+ register char *t = Utility_Char_Table, *tmax;
+ register unsigned char ch;
+
+ tmax = t + 256;
+ while (t < tmax) *t++ = 0;
+
+ t = Utility_Char_Table;
+ while ((ch = (unsigned char) *pos++) != 0) t[ch] = 1;
+}
+
+/*}}}*/
+
+_INLINE_
+static unsigned char *make_whitespace_lut (void)
+{
+ if (WhiteSpace_Lut[' '] != 1)
+ {
+ WhiteSpace_Lut[' '] = WhiteSpace_Lut['\r']
+ = WhiteSpace_Lut ['\n'] = WhiteSpace_Lut['\t']
+ = WhiteSpace_Lut ['\f'] = 1;
+ }
+ return WhiteSpace_Lut;
+}
+
+static unsigned char *make_lut (unsigned char *s, unsigned char *lut)
+{
+ int reverse = 0;
+
+ if (*s == '^')
+ {
+ reverse = 1;
+ s++;
+ }
+ SLmake_lut (lut, s, reverse);
+ return lut;
+}
+
+static unsigned int do_trim (char **beg, int do_beg,
+ char **end, int do_end,
+ char *white) /*{{{*/
+{
+ unsigned int len;
+ char *a, *b;
+
+ set_utility_char_table (white);
+
+ a = *beg;
+ len = strlen (a);
+ b = a + len;
+
+ if (do_beg)
+ while (Utility_Char_Table[(unsigned char) *a]) a++;
+
+ if (do_end)
+ {
+ b--;
+ while ((b >= a) && (Utility_Char_Table[(unsigned char) *b])) b--;
+ b++;
+ }
+
+ len = (unsigned int) (b - a);
+ *beg = a;
+ *end = b;
+ return len;
+}
+
+/*}}}*/
+
+/*}}}*/
+
+static int pop_3_strings (char **a, char **b, char **c)
+{
+ *a = *b = *c = NULL;
+ if (-1 == SLpop_string (c))
+ return -1;
+
+ if (-1 == SLpop_string (b))
+ {
+ SLfree (*c);
+ *c = NULL;
+ return -1;
+ }
+
+ if (-1 == SLpop_string (a))
+ {
+ SLfree (*b);
+ SLfree (*c);
+ *b = *c = NULL;
+ return -1;
+ }
+
+ return 0;
+}
+
+static void free_3_strings (char *a, char *b, char *c)
+{
+ SLfree (a);
+ SLfree (b);
+ SLfree (c);
+}
+
+static void strcat_cmd (void) /*{{{*/
+{
+ char *c, *c1;
+ int nargs;
+ int i;
+ char **ptrs;
+ unsigned int len;
+#if !USE_ALLOC_STSTRING
+ char buf[256];
+#endif
+ nargs = SLang_Num_Function_Args;
+ if (nargs <= 0) nargs = 2;
+
+ if (NULL == (ptrs = (char **)SLmalloc (nargs * sizeof (char *))))
+ return;
+
+ memset ((char *) ptrs, 0, sizeof (char *) * nargs);
+
+ c = NULL;
+ i = nargs;
+ len = 0;
+ while (i != 0)
+ {
+ char *s;
+
+ i--;
+ if (-1 == SLang_pop_slstring (&s))
+ goto free_and_return;
+ ptrs[i] = s;
+ len += strlen (s);
+ }
+#if USE_ALLOC_STSTRING
+ if (NULL == (c = _SLallocate_slstring (len)))
+ goto free_and_return;
+#else
+ len++; /* \0 char */
+ if (len <= sizeof (buf))
+ c = buf;
+ else if (NULL == (c = SLmalloc (len)))
+ goto free_and_return;
+#endif
+
+ c1 = c;
+ for (i = 0; i < nargs; i++)
+ {
+ strcpy (c1, ptrs[i]);
+ c1 += strlen (c1);
+ }
+
+ free_and_return:
+ for (i = 0; i < nargs; i++)
+ SLang_free_slstring (ptrs[i]);
+ SLfree ((char *) ptrs);
+
+#if USE_ALLOC_STSTRING
+ (void) _SLpush_alloced_slstring (c, len);
+#else
+ if (c != buf)
+ (void) SLang_push_malloced_string (c); /* NULL ok */
+ else
+ (void) SLang_push_string (c);
+#endif
+}
+
+/*}}}*/
+
+static int _SLang_push_nstring (char *a, unsigned int len)
+{
+ a = SLang_create_nslstring (a, len);
+ if (a == NULL)
+ return -1;
+
+ return _SLang_push_slstring (a);
+}
+
+
+static void strtrim_cmd_internal (char *str, int do_beg, int do_end)
+{
+ char *beg, *end, *white;
+ int free_str;
+ unsigned int len;
+
+ /* Go through SLpop_string to get a private copy since it will be
+ * modified.
+ */
+
+ free_str = 0;
+ if (SLang_Num_Function_Args == 2)
+ {
+ white = str;
+ if (-1 == SLang_pop_slstring (&str))
+ return;
+ free_str = 1;
+ }
+ else white = " \t\f\r\n";
+
+ beg = str;
+ len = do_trim (&beg, do_beg, &end, do_end, white);
+
+ (void) _SLang_push_nstring (beg, len);
+ if (free_str)
+ SLang_free_slstring (str);
+}
+
+
+static void strtrim_cmd (char *str)
+{
+ strtrim_cmd_internal (str, 1, 1);
+}
+
+static void strtrim_beg_cmd (char *str)
+{
+ strtrim_cmd_internal (str, 1, 0);
+}
+
+static void strtrim_end_cmd (char *str)
+{
+ strtrim_cmd_internal (str, 0, 1);
+}
+
+
+static void strcompress_cmd (void) /*{{{*/
+{
+ char *str, *white, *c;
+ unsigned char *s, *beg, *end;
+ unsigned int len;
+ char pref_char;
+
+ if (SLpop_string (&white)) return;
+ if (SLpop_string (&str))
+ {
+ SLfree (white);
+ return;
+ }
+
+ /* The first character of white is the preferred whitespace character */
+ pref_char = *white;
+
+ beg = (unsigned char *) str;
+ (void) do_trim ((char **) &beg, 1, (char **) &end, 1, white);
+ SLfree (white);
+
+ /* Determine the effective length */
+ len = 0;
+ s = (unsigned char *) beg;
+ while (s < end)
+ {
+ len++;
+ if (Utility_Char_Table[*s++])
+ {
+ while ((s < end) && Utility_Char_Table[*s]) s++;
+ }
+ }
+
+#if USE_ALLOC_STSTRING
+ c = _SLallocate_slstring (len);
+#else
+ c = SLmalloc (len + 1);
+#endif
+ if (c == NULL)
+ {
+ SLfree (str);
+ return;
+ }
+
+ s = (unsigned char *) c;
+
+ while (beg < end)
+ {
+ unsigned char ch = *beg++;
+
+ if (0 == Utility_Char_Table[ch])
+ {
+ *s++ = ch;
+ continue;
+ }
+
+ *s++ = (unsigned char) pref_char;
+
+ while ((beg < end) && Utility_Char_Table[*beg])
+ beg++;
+ }
+
+ *s = 0;
+
+#if USE_ALLOC_STSTRING
+ (void) _SLpush_alloced_slstring (c, len);
+#else
+ SLang_push_malloced_string(c);
+#endif
+
+ SLfree(str);
+}
+
+/*}}}*/
+
+static int str_replace_cmd_1 (char *orig, char *match, char *rep, unsigned int max_num_replaces,
+ char **new_strp) /*{{{*/
+{
+ char *s, *t, *new_str;
+ unsigned int rep_len, match_len, new_len;
+ unsigned int num_replaces;
+
+ *new_strp = NULL;
+
+ match_len = strlen (match);
+
+ if (match_len == 0)
+ return 0;
+
+ num_replaces = 0;
+ s = orig;
+ while (num_replaces < max_num_replaces)
+ {
+ s = strstr (s, match);
+ if (s == NULL)
+ break;
+ s += match_len;
+ num_replaces++;
+ }
+
+ if (num_replaces == 0)
+ return 0;
+
+ max_num_replaces = num_replaces;
+
+ rep_len = strlen (rep);
+
+ new_len = (strlen (orig) - num_replaces * match_len) + num_replaces * rep_len;
+ new_str = SLmalloc (new_len + 1);
+ if (new_str == NULL)
+ return -1;
+
+ s = orig;
+ t = new_str;
+
+ for (num_replaces = 0; num_replaces < max_num_replaces; num_replaces++)
+ {
+ char *next_s;
+ unsigned int len;
+
+ next_s = strstr (s, match); /* cannot be NULL */
+ len = (unsigned int) (next_s - s);
+ strncpy (t, s, len);
+ t += len;
+ strcpy (t, rep);
+ t += rep_len;
+
+ s = next_s + match_len;
+ }
+ strcpy (t, s);
+ *new_strp = new_str;
+
+ return (int) num_replaces;
+}
+
+/*}}}*/
+
+static void reverse_string (char *a)
+{
+ char *b;
+
+ b = a + strlen (a);
+ while (b > a)
+ {
+ char ch;
+
+ b--;
+ ch = *a;
+ *a++ = *b;
+ *b = ch;
+ }
+}
+
+static int strreplace_cmd (int *np)
+{
+ char *orig, *match, *rep;
+ char *new_str;
+ int max_num_replaces;
+ int ret;
+
+ max_num_replaces = *np;
+
+ if (-1 == pop_3_strings (&orig, &match, &rep))
+ return -1;
+
+ if (max_num_replaces < 0)
+ {
+ reverse_string (orig);
+ reverse_string (match);
+ reverse_string (rep);
+ ret = str_replace_cmd_1 (orig, match, rep, -max_num_replaces, &new_str);
+ if (ret > 0) reverse_string (new_str);
+ else if (ret == 0)
+ reverse_string (orig);
+ }
+ else ret = str_replace_cmd_1 (orig, match, rep, max_num_replaces, &new_str);
+
+ if (ret == 0)
+ {
+ if (-1 == SLang_push_malloced_string (orig))
+ ret = -1;
+ orig = NULL;
+ }
+ else if (ret > 0)
+ {
+ if (-1 == SLang_push_malloced_string (new_str))
+ ret = -1;
+ }
+
+ free_3_strings (orig, match, rep);
+ return ret;
+}
+
+static int str_replace_cmd (char *orig, char *match, char *rep)
+{
+ char *s;
+ int ret;
+
+ ret = str_replace_cmd_1 (orig, match, rep, 1, &s);
+ if (ret == 1)
+ (void) SLang_push_malloced_string (s);
+ return ret;
+}
+
+
+
+static void strtok_cmd (char *str)
+{
+ _SLString_List_Type sl;
+ unsigned char white_buf[256];
+ char *s;
+ unsigned char *white;
+
+ if (SLang_Num_Function_Args == 1)
+ white = make_whitespace_lut ();
+ else
+ {
+ white = white_buf;
+ make_lut ((unsigned char *)str, white);
+ if (-1 == SLang_pop_slstring (&str))
+ return;
+ }
+
+ if (-1 == _SLstring_list_init (&sl, 256, 1024))
+ goto the_return;
+
+ s = str;
+ while (*s != 0)
+ {
+ char *s0;
+
+ s0 = s;
+ /* Skip whitespace */
+ while ((*s0 != 0) && (0 != white[(unsigned char)*s0]))
+ s0++;
+
+ if (*s0 == 0)
+ break;
+
+ s = s0;
+ while ((*s != 0) && (0 == white[(unsigned char) *s]))
+ s++;
+
+ /* sl deleted upon failure */
+ if (-1 == _SLstring_list_append (&sl, SLang_create_nslstring (s0, (unsigned int) (s - s0))))
+ goto the_return;
+ }
+
+ /* Deletes sl */
+ (void) _SLstring_list_push (&sl);
+
+ the_return:
+ if (white == white_buf)
+ SLang_free_slstring (str);
+}
+
+/* This routine returns the string with text removed between single character
+ comment delimiters from the set b and e. */
+
+static void str_uncomment_string_cmd (char *str, char *b, char *e) /*{{{*/
+{
+ unsigned char chb, che;
+ unsigned char *s, *cbeg, *mark;
+
+ if (strlen(b) != strlen(e))
+ {
+ SLang_doerror ("Comment delimiter length mismatch.");
+ return;
+ }
+
+ set_utility_char_table (b);
+
+ if (NULL == (str = (char *) SLmake_string(str))) return;
+
+ s = (unsigned char *) str;
+
+ while ((chb = *s++) != 0)
+ {
+ if (Utility_Char_Table [chb] == 0) continue;
+
+ mark = s - 1;
+
+ cbeg = (unsigned char *) b;
+ while (*cbeg != chb) cbeg++;
+
+ che = (unsigned char) *(e + (int) (cbeg - (unsigned char *) b));
+
+ while (((chb = *s++) != 0) && (chb != che));
+
+ if (chb == 0)
+ {
+ /* end of string and end not found. Just truncate it a return; */
+ *mark = 0;
+ break;
+ }
+
+ strcpy ((char *) mark, (char *)s);
+ s = mark;
+ }
+ SLang_push_malloced_string (str);
+}
+
+/*}}}*/
+
+static void str_quote_string_cmd (char *str, char *quotes, int *slash_ptr) /*{{{*/
+{
+ char *q;
+ int slash;
+ unsigned int len;
+ register char *t, *s, *q1;
+ register unsigned char ch;
+
+ slash = *slash_ptr;
+
+ if ((slash > 255) || (slash < 0))
+ {
+ SLang_Error = SL_INVALID_PARM;
+ return;
+ }
+
+ /* setup the utility table to have 1s at quote char postitions. */
+ set_utility_char_table (quotes);
+
+ t = Utility_Char_Table;
+ t[(unsigned int) slash] = 1;
+
+ /* calculate length */
+ s = str;
+ len = 0;
+ while ((ch = (unsigned char) *s++) != 0) if (t[ch]) len++;
+ len += (unsigned int) (s - str);
+
+ if (NULL != (q = SLmalloc(len)))
+ {
+ s = str; q1 = q;
+ while ((ch = (unsigned char) *s++) != 0)
+ {
+ if (t[ch]) *q1++ = slash;
+ *q1++ = (char) ch;
+ }
+ *q1 = 0;
+ SLang_push_malloced_string(q);
+ }
+}
+
+/*}}}*/
+
+/* returns the position of substrin in a string or null */
+static int issubstr_cmd (char *a, char *b) /*{{{*/
+{
+ char *c;
+
+ if (NULL == (c = (char *) strstr(a, b)))
+ return 0;
+
+ return 1 + (int) (c - a);
+}
+
+/*}}}*/
+
+/* returns to stack string at pos n to n + m of a */
+static void substr_cmd (char *a, int *n_ptr, int *m_ptr) /*{{{*/
+{
+ int n, m;
+ int lena;
+
+ n = *n_ptr;
+ m = *m_ptr;
+
+ lena = strlen (a);
+ if (n > lena) n = lena + 1;
+ if (n < 1)
+ {
+ SLang_Error = SL_INVALID_PARM;
+ return;
+ }
+
+ n--;
+ if (m < 0) m = lena;
+ if (n + m > lena) m = lena - n;
+
+ (void) _SLang_push_nstring (a + n, (unsigned int) m);
+}
+
+/*}}}*/
+
+/* substitute char m at positin string n in string*/
+static void strsub_cmd (int *nptr, int *mptr) /*{{{*/
+{
+ char *a;
+ int n, m;
+ unsigned int lena;
+
+ if (-1 == SLpop_string (&a))
+ return;
+
+ n = *nptr;
+ m = *mptr;
+
+ lena = strlen (a);
+
+ if ((n <= 0) || (lena < (unsigned int) n))
+ {
+ SLang_Error = SL_INVALID_PARM;
+ SLfree(a);
+ return;
+ }
+
+ a[n - 1] = (char) m;
+
+ SLang_push_malloced_string (a);
+}
+
+/*}}}*/
+
+static void strup_cmd(void) /*{{{*/
+{
+ unsigned char c, *a;
+ char *str;
+
+ if (SLpop_string (&str))
+ return;
+
+ a = (unsigned char *) str;
+ while ((c = *a) != 0)
+ {
+ /* if ((*a >= 'a') && (*a <= 'z')) *a -= 32; */
+ *a = UPPER_CASE(c);
+ a++;
+ }
+
+ SLang_push_malloced_string (str);
+}
+
+/*}}}*/
+
+static int isdigit_cmd (char *what) /*{{{*/
+{
+ return isdigit((unsigned char)*what);
+}
+
+/*}}}*/
+static int toupper_cmd (int *ch) /*{{{*/
+{
+ return UPPER_CASE(*ch);
+}
+
+/*}}}*/
+
+static int tolower_cmd (int *ch) /*{{{*/
+{
+ return LOWER_CASE(*ch);
+}
+
+/*}}}*/
+
+static void strlow_cmd (void) /*{{{*/
+{
+ unsigned char c, *a;
+ char *str;
+
+ if (SLpop_string(&str)) return;
+ a = (unsigned char *) str;
+ while ((c = *a) != 0)
+ {
+ /* if ((*a >= 'a') && (*a <= 'z')) *a -= 32; */
+ *a = LOWER_CASE(c);
+ a++;
+ }
+
+ SLang_push_malloced_string ((char *) str);
+}
+
+/*}}}*/
+
+static SLang_Array_Type *do_strchop (char *str, int delim, int quote)
+{
+ int count;
+ char *s0, *elm;
+ register char *s1;
+ register unsigned char ch;
+ int quoted;
+ SLang_Array_Type *at;
+ char **data;
+
+ if ((quote < 0) || (quote > 255)
+ || (delim <= 0) || (delim > 255))
+ {
+ SLang_Error = SL_INVALID_PARM;
+ return NULL;
+ }
+
+ s1 = s0 = str;
+
+ quoted = 0;
+ count = 1; /* at least 1 */
+ while (1)
+ {
+ ch = (unsigned char) *s1++;
+ if ((ch == quote) && quote)
+ {
+ if (*s1 == 0)
+ break;
+
+ s1++;
+ continue;
+ }
+
+ if (ch == delim)
+ {
+ count++;
+ continue;
+ }
+
+ if (ch == 0)
+ break;
+ }
+
+ if (NULL == (at = SLang_create_array (SLANG_STRING_TYPE, 0, NULL, &count, 1)))
+ return NULL;
+
+ data = (char **)at->data;
+
+ count = 0;
+ s1 = s0;
+
+ while (1)
+ {
+ ch = (unsigned char) *s1;
+
+ if ((ch == quote) && quote)
+ {
+ s1++;
+ if (*s1 != 0) s1++;
+ quoted = 1;
+ continue;
+ }
+
+ if ((ch == delim) || (ch == 0))
+ {
+ if (quoted == 0)
+ elm = SLang_create_nslstring (s0, (unsigned int) (s1 - s0));
+ else
+ {
+ register char ch1, *p, *p1;
+ char *tmp;
+
+ tmp = SLmake_nstring (s0, (unsigned int)(s1 - s0));
+ if (tmp == NULL)
+ break;
+
+ /* Now unquote it */
+ p = p1 = tmp;
+ do
+ {
+ ch1 = *p1++;
+ if (ch1 == '\\') ch1 = *p1++;
+ *p++ = ch1;
+ }
+ while (ch1 != 0);
+ quoted = 0;
+
+ elm = SLang_create_slstring (tmp);
+ SLfree (tmp);
+ }
+
+ if (elm == NULL)
+ break;
+
+ data[count] = elm;
+ count++;
+
+ if (ch == 0)
+ return at;
+
+ s1++; /* skip past delim */
+ s0 = s1; /* and reset */
+ }
+ else s1++;
+ }
+
+ SLang_free_array (at);
+ return NULL;
+}
+
+static void strchop_cmd (char *str, int *q, int *d)
+{
+ (void) SLang_push_array (do_strchop (str, *q, *d), 1);
+}
+
+static void strchopr_cmd (char *str, int *q, int *d)
+{
+ SLang_Array_Type *at;
+
+ if (NULL != (at = do_strchop (str, *q, *d)))
+ {
+ char **d0, **d1;
+
+ d0 = (char **) at->data;
+ d1 = d0 + (at->num_elements - 1);
+
+ while (d0 < d1)
+ {
+ char *tmp;
+
+ tmp = *d0;
+ *d0 = *d1;
+ *d1 = tmp;
+ d0++;
+ d1--;
+ }
+ }
+ SLang_push_array (at, 1);
+}
+
+static int strcmp_cmd (char *a, char *b) /*{{{*/
+{
+ return strcmp(a, b);
+}
+
+/*}}}*/
+
+static int strncmp_cmd (char *a, char *b, int *n) /*{{{*/
+{
+ return strncmp(a, b, (unsigned int) *n);
+}
+
+/*}}}*/
+
+static int strlen_cmd (char *s) /*{{{*/
+{
+ return (int) strlen (s);
+}
+/*}}}*/
+
+static void extract_element_cmd (char *list, int *nth_ptr, int *delim_ptr)
+{
+ char buf[1024], *b;
+
+ b = buf;
+ if (-1 == SLextract_list_element (list, *nth_ptr, *delim_ptr, buf, sizeof(buf)))
+ b = NULL;
+
+ SLang_push_string (b);
+}
+
+/* sprintf functionality for S-Lang */
+
+static char *SLdo_sprintf (char *fmt) /*{{{*/
+{
+ register char *p = fmt, ch;
+ char *out = NULL, *outp = NULL;
+ char dfmt[1024]; /* used to hold part of format */
+ char *f;
+ VOID_STAR varp;
+ int want_width, width, precis, use_varp, int_var;
+ long long_var;
+ unsigned int len = 0, malloc_len = 0, dlen;
+ int do_free, guess_size;
+#if SLANG_HAS_FLOAT
+ int tmp1, tmp2, use_double;
+ double x;
+#endif
+ int use_long = 0;
+
+ while (1)
+ {
+ while ((ch = *p) != 0)
+ {
+ if (ch == '%')
+ break;
+ p++;
+ }
+
+ /* p points at '%' or 0 */
+
+ dlen = (unsigned int) (p - fmt);
+
+ if (len + dlen >= malloc_len)
+ {
+ malloc_len = len + dlen;
+ if (out == NULL) outp = SLmalloc(malloc_len + 1);
+ else outp = SLrealloc(out, malloc_len + 1);
+ if (NULL == outp)
+ return out;
+ out = outp;
+ outp = out + len;
+ }
+
+ strncpy(outp, fmt, dlen);
+ len += dlen;
+ outp = out + len;
+ *outp = 0;
+ if (ch == 0) break;
+
+ /* bump it beyond '%' */
+ ++p;
+ fmt = p;
+
+ f = dfmt;
+ *f++ = ch;
+ /* handle flag char */
+ ch = *p++;
+
+ /* Make sure cases such as "% #g" can be handled. */
+ if ((ch == '-') || (ch == '+') || (ch == ' ') || (ch == '#'))
+ {
+ *f++ = ch;
+ ch = *p++;
+ if ((ch == '-') || (ch == '+') || (ch == ' ') || (ch == '#'))
+ {
+ *f++ = ch;
+ ch = *p++;
+ }
+ }
+
+
+ /* width */
+ /* I have got to parse it myself so that I can see how big it needs
+ * to be.
+ */
+ want_width = width = 0;
+ if (ch == '*')
+ {
+ if (SLang_pop_integer(&width)) return (out);
+ want_width = 1;
+ ch = *p++;
+ }
+ else
+ {
+ if (ch == '0')
+ {
+ *f++ = '0';
+ ch = *p++;
+ }
+
+ while ((ch <= '9') && (ch >= '0'))
+ {
+ width = width * 10 + (ch - '0');
+ ch = *p++;
+ want_width = 1;
+ }
+ }
+
+ if (want_width)
+ {
+ sprintf(f, "%d", width);
+ f += strlen (f);
+ }
+ precis = 0;
+ /* precision -- also indicates max number of chars from string */
+ if (ch == '.')
+ {
+ *f++ = ch;
+ ch = *p++;
+ want_width = 0;
+ if (ch == '*')
+ {
+ if (SLang_pop_integer(&precis)) return (out);
+ ch = *p++;
+ want_width = 1;
+ }
+ else while ((ch <= '9') && (ch >= '0'))
+ {
+ precis = precis * 10 + (ch - '0');
+ ch = *p++;
+ want_width = 1;
+ }
+ if (want_width)
+ {
+ sprintf(f, "%d", precis);
+ f += strlen (f);
+ }
+ else precis = 0;
+ }
+
+ long_var = 0;
+ int_var = 0;
+ varp = NULL;
+ guess_size = 32;
+#if SLANG_HAS_FLOAT
+ use_double = 0;
+#endif
+ use_long = 0;
+ use_varp = 0;
+ do_free = 0;
+
+ if (ch == 'l')
+ {
+ use_long = 1;
+ ch = *p++;
+ }
+ else if (ch == 'h') ch = *p++; /* not supported */
+
+ /* Now the actual format specifier */
+ switch (ch)
+ {
+ case 'S':
+ _SLstring_intrinsic ();
+ ch = 's';
+ /* drop */
+ case 's':
+ if (SLang_pop_slstring((char **) &varp)) return (out);
+ do_free = 1;
+ guess_size = strlen((char *) varp);
+ use_varp = 1;
+ break;
+
+ case '%':
+ guess_size = 1;
+ do_free = 0;
+ use_varp = 1;
+ varp = (VOID_STAR) "%";
+ break;
+
+ case 'c': guess_size = 1;
+ use_long = 0;
+ /* drop */
+ case 'd':
+ case 'i':
+ case 'o':
+ case 'u':
+ case 'X':
+ case 'x':
+ if (SLang_pop_long (&long_var)) return(out);
+ if (use_long == 0)
+ int_var = (int) long_var;
+ else
+ *f++ = 'l';
+ break;
+
+ case 'f':
+ case 'e':
+ case 'g':
+ case 'E':
+ case 'G':
+#if SLANG_HAS_FLOAT
+ if (SLang_pop_double(&x, &tmp1, &tmp2)) return (out);
+ use_double = 1;
+ guess_size = 256;
+ (void) tmp1; (void) tmp2;
+ use_long = 0;
+ break;
+#endif
+ case 'p':
+ guess_size = 32;
+ /* Pointer type?? Why?? */
+ if (-1 == SLdo_pop ())
+ return out;
+ varp = (VOID_STAR) _SLStack_Pointer;
+ use_varp = 1;
+ use_long = 0;
+ break;
+
+ default:
+ SLang_doerror("Invalid Format.");
+ return(out);
+ }
+ *f++ = ch; *f = 0;
+
+ width = width + precis;
+ if (width > guess_size) guess_size = width;
+
+ if (len + guess_size > malloc_len)
+ {
+ outp = (char *) SLrealloc(out, len + guess_size + 1);
+ if (outp == NULL)
+ {
+ SLang_Error = SL_MALLOC_ERROR;
+ return (out);
+ }
+ out = outp;
+ outp = out + len;
+ malloc_len = len + guess_size;
+ }
+
+ if (use_varp)
+ {
+ sprintf(outp, dfmt, varp);
+ if (do_free) SLang_free_slstring ((char *)varp);
+ }
+#if SLANG_HAS_FLOAT
+ else if (use_double) sprintf(outp, dfmt, x);
+#endif
+ else if (use_long) sprintf (outp, dfmt, long_var);
+ else sprintf(outp, dfmt, int_var);
+
+ len += strlen(outp);
+ outp = out + len;
+ fmt = p;
+ }
+
+ if (out != NULL)
+ {
+ outp = SLrealloc (out, (unsigned int) (outp - out) + 1);
+ if (outp != NULL) out = outp;
+ }
+
+ return (out);
+}
+
+/*}}}*/
+
+int _SLstrops_do_sprintf_n (int n) /*{{{*/
+{
+ char *p;
+ char *fmt;
+ SLang_Object_Type *ptr;
+ int ofs;
+
+ if (-1 == (ofs = SLreverse_stack (n + 1)))
+ return -1;
+
+ ptr = _SLRun_Stack + ofs;
+
+ if (SLang_pop_slstring(&fmt))
+ return -1;
+
+ p = SLdo_sprintf (fmt);
+ SLang_free_slstring (fmt);
+
+ while (_SLStack_Pointer > ptr)
+ SLdo_pop ();
+
+ if (SLang_Error)
+ {
+ SLfree (p);
+ return -1;
+ }
+
+ return SLang_push_malloced_string (p);
+}
+
+/*}}}*/
+
+static void sprintf_n_cmd (int *n)
+{
+ _SLstrops_do_sprintf_n (*n);
+}
+
+static void sprintf_cmd (void)
+{
+ _SLstrops_do_sprintf_n (SLang_Num_Function_Args - 1); /* do not include format */
+}
+
+/* converts string s to a form that can be used in an eval */
+static void make_printable_string(char *s) /*{{{*/
+{
+ unsigned int len;
+ register char *s1 = s, ch, *ss1;
+ char *ss;
+
+ /* compute length */
+ len = 3;
+ while ((ch = *s1++) != 0)
+ {
+ if ((ch == '\n') || (ch == '\\') || (ch == '"')) len++;
+ len++;
+ }
+
+ if (NULL == (ss = SLmalloc(len)))
+ return;
+
+ s1 = s;
+ ss1 = ss;
+ *ss1++ = '"';
+ while ((ch = *s1++) != 0)
+ {
+ if (ch == '\n')
+ {
+ ch = 'n';
+ *ss1++ = '\\';
+ }
+ else if ((ch == '\\') || (ch == '"'))
+ {
+ *ss1++ = '\\';
+ }
+ *ss1++ = ch;
+ }
+ *ss1++ = '"';
+ *ss1 = 0;
+ if (-1 == SLang_push_string (ss))
+ SLfree (ss);
+}
+
+/*}}}*/
+
+static int is_list_element_cmd (char *list, char *elem, int *d_ptr)
+{
+ char ch;
+ int d, n;
+ unsigned int len;
+ char *lbeg, *lend;
+
+ d = *d_ptr;
+
+ len = strlen (elem);
+
+ n = 1;
+ lend = list;
+
+ while (1)
+ {
+ lbeg = lend;
+ while ((0 != (ch = *lend)) && (ch != (char) d)) lend++;
+
+ if ((lbeg + len == lend)
+ && (0 == strncmp (elem, lbeg, len)))
+ break;
+
+ if (ch == 0)
+ {
+ n = 0;
+ break;
+ }
+ lend++; /* skip delim */
+ n++;
+ }
+
+ return n;
+}
+
+/*}}}*/
+
+/* Regular expression routines for strings */
+static SLRegexp_Type regexp_reg;
+
+static int string_match_cmd (char *str, char *pat, int *nptr) /*{{{*/
+{
+ int n;
+ unsigned int len;
+ unsigned char rbuf[512], *match;
+
+ n = *nptr;
+
+ regexp_reg.case_sensitive = 1;
+ regexp_reg.buf = rbuf;
+ regexp_reg.pat = (unsigned char *) pat;
+ regexp_reg.buf_len = sizeof (rbuf);
+
+ if (SLang_regexp_compile (&regexp_reg))
+ {
+ SLang_verror (SL_INVALID_PARM, "Unable to compile pattern");
+ return -1;
+ }
+
+ n--;
+ len = strlen(str);
+ if ((n < 0) || ((unsigned int) n >= len))
+ {
+ /* SLang_Error = SL_INVALID_PARM; */
+ return 0;
+ }
+
+ str += n;
+ len -= n;
+
+ if (NULL == (match = SLang_regexp_match((unsigned char *) str, len, &regexp_reg)))
+ return 0;
+
+ /* adjust offsets */
+ regexp_reg.offset = n;
+
+ return (1 + (int) ((char *) match - str));
+}
+
+/*}}}*/
+
+static int string_match_nth_cmd (int *nptr) /*{{{*/
+{
+ int n, beg;
+
+ n = *nptr;
+
+ if ((n < 0) || (n > 9) || (regexp_reg.pat == NULL)
+ || ((beg = regexp_reg.beg_matches[n]) == -1))
+ {
+ SLang_Error = SL_INVALID_PARM;
+ return -1;
+ }
+ SLang_push_integer(beg + regexp_reg.offset);
+ return regexp_reg.end_matches[n];
+}
+
+/*}}}*/
+
+static char *create_delimited_string (char **list, unsigned int n,
+ char *delim)
+{
+ unsigned int len, dlen;
+ unsigned int i;
+ unsigned int num;
+ char *str, *s;
+
+ len = 1; /* allow room for \0 char */
+ num = 0;
+ for (i = 0; i < n; i++)
+ {
+ if (list[i] == NULL) continue;
+ len += strlen (list[i]);
+ num++;
+ }
+
+ dlen = strlen (delim);
+ if (num > 1)
+ len += (num - 1) * dlen;
+
+ if (NULL == (str = SLmalloc (len)))
+ return NULL;
+
+ *str = 0;
+ s = str;
+ i = 0;
+
+ while (num > 1)
+ {
+ while (list[i] == NULL)
+ i++;
+
+ strcpy (s, list[i]);
+ s += strlen (list[i]);
+ strcpy (s, delim);
+ s += dlen;
+ i++;
+ num--;
+ }
+
+ if (num)
+ {
+ while (list[i] == NULL)
+ i++;
+
+ strcpy (s, list[i]);
+ }
+
+ return str;
+}
+
+static void create_delimited_string_cmd (int *nptr)
+{
+ unsigned int n, i;
+ char **strings;
+ char *str;
+
+ str = NULL;
+
+ n = 1 + (unsigned int) *nptr; /* n includes delimiter */
+
+ if (NULL == (strings = (char **)SLmalloc (n * sizeof (char *))))
+ {
+ SLdo_pop_n (n);
+ return;
+ }
+ memset((char *)strings, 0, n * sizeof (char *));
+
+ i = n;
+ while (i != 0)
+ {
+ i--;
+ if (-1 == SLang_pop_slstring (strings + i))
+ goto return_error;
+ }
+
+ str = create_delimited_string (strings + 1, (n - 1), strings[0]);
+ /* drop */
+ return_error:
+ for (i = 0; i < n; i++) SLang_free_slstring (strings[i]);
+ SLfree ((char *)strings);
+
+ (void) SLang_push_malloced_string (str); /* NULL Ok */
+}
+
+static void strjoin_cmd (char *delim)
+{
+ SLang_Array_Type *at;
+ char *str;
+
+ if (-1 == SLang_pop_array_of_type (&at, SLANG_STRING_TYPE))
+ return;
+
+ str = create_delimited_string ((char **)at->data, at->num_elements, delim);
+ SLang_free_array (at);
+ (void) SLang_push_malloced_string (str); /* NULL Ok */
+}
+
+static void str_delete_chars_cmd (char *s, char *d)
+{
+ unsigned char lut[256];
+ unsigned char *s1, *s2;
+ unsigned char ch;
+
+ make_lut ((unsigned char *)d, lut);
+ if (NULL == (s = SLmake_string (s)))
+ return;
+
+ s1 = s2 = (unsigned char *) s;
+ while ((ch = *s2++) != 0)
+ {
+ if (0 == lut[ch])
+ *s1++ = ch;
+ }
+ *s1 = 0;
+
+ (void) SLang_push_malloced_string (s);
+}
+
+static unsigned char *make_lut_string (unsigned char *s)
+{
+ unsigned char lut[256];
+ unsigned char *l;
+ unsigned int i;
+
+ /* Complement-- a natural order is imposed */
+ make_lut (s, lut);
+ l = lut;
+ for (i = 1; i < 256; i++)
+ {
+ if (lut[i])
+ *l++ = (unsigned char) i;
+ }
+ *l = 0;
+ return (unsigned char *) SLmake_string ((char *)lut);
+}
+
+static unsigned char *make_str_range (unsigned char *s)
+{
+ unsigned char *s1, *range;
+ unsigned int num;
+ unsigned char ch;
+ int len;
+
+ if (*s == '^')
+ return make_lut_string (s);
+
+ num = 0;
+ s1 = s;
+ while ((ch = *s1++) != 0)
+ {
+ unsigned char ch1;
+
+ ch1 = *s1;
+ if (ch1 == '-')
+ {
+ s1++;
+ ch1 = *s1;
+ len = (int)ch1 - (int)ch;
+ if (len < 0)
+ len = -len;
+
+ num += (unsigned int) len;
+ if (ch1 != 0)
+ s1++;
+ }
+
+ num++;
+ }
+
+ range = (unsigned char *)SLmalloc (num + 1);
+ if (range == NULL)
+ return NULL;
+
+ s1 = s;
+ s = range;
+ while ((ch = *s1++) != 0)
+ {
+ unsigned char ch1;
+ unsigned int i;
+
+ ch1 = *s1;
+ if (ch1 != '-')
+ {
+ *s++ = ch;
+ continue;
+ }
+
+ s1++;
+ ch1 = *s1;
+
+ if (ch > ch1)
+ {
+ if (ch1 == 0)
+ ch1 = 1;
+
+ for (i = (unsigned int) ch; i >= (unsigned int) ch1; i--)
+ *s++ = (unsigned char) i;
+
+ if (*s1 == 0)
+ break;
+ }
+ else
+ {
+ for (i = (unsigned int) ch; i <= (unsigned int) ch1; i++)
+ *s++ = (unsigned char) i;
+ }
+ s1++;
+ }
+
+#if 0
+ if (range + num != s)
+ SLang_verror (SL_INTERNAL_ERROR, "make_str_range: num wrong");
+#endif
+ *s = 0;
+
+ return range;
+}
+
+static void strtrans_cmd (char *s, unsigned char *from, unsigned char *to)
+{
+ unsigned char map[256];
+ char *s1;
+ unsigned int i;
+ unsigned char ch;
+ unsigned char last_to;
+ unsigned char *from_range, *to_range;
+
+ for (i = 0; i < 256; i++) map[i] = (unsigned char) i;
+
+ if (*to == 0)
+ {
+ str_delete_chars_cmd (s, (char *)from);
+ return;
+ }
+
+ from_range = make_str_range (from);
+ if (from_range == NULL)
+ return;
+ to_range = make_str_range (to);
+ if (to_range == NULL)
+ {
+ SLfree ((char *)from_range);
+ return;
+ }
+
+ from = from_range;
+ to = to_range;
+
+ last_to = 0;
+ while ((ch = *from++) != 0)
+ {
+ unsigned char to_ch;
+
+ if (0 == (to_ch = *to++))
+ {
+ do
+ {
+ map[ch] = last_to;
+ }
+ while (0 != (ch = *from++));
+ break;
+ }
+
+ last_to = map[ch] = to_ch;
+ }
+
+ SLfree ((char *)from_range);
+ SLfree ((char *)to_range);
+
+ s = SLmake_string (s);
+ if (s == NULL)
+ return;
+
+ s1 = s;
+ while ((ch = (unsigned char) *s1) != 0)
+ *s1++ = (char) map[ch];
+
+ (void) SLang_push_malloced_string (s);
+}
+
+
+static SLang_Intrin_Fun_Type Strops_Table [] = /*{{{*/
+{
+ MAKE_INTRINSIC_I("create_delimited_string", create_delimited_string_cmd, SLANG_VOID_TYPE),
+ MAKE_INTRINSIC_SS("strcmp", strcmp_cmd, SLANG_INT_TYPE),
+ MAKE_INTRINSIC_SSI("strncmp", strncmp_cmd, SLANG_INT_TYPE),
+ MAKE_INTRINSIC_0("strcat", strcat_cmd, SLANG_VOID_TYPE),
+ MAKE_INTRINSIC_S("strlen", strlen_cmd, SLANG_INT_TYPE),
+ MAKE_INTRINSIC_SII("strchop", strchop_cmd, SLANG_VOID_TYPE),
+ MAKE_INTRINSIC_SII("strchopr", strchopr_cmd, SLANG_VOID_TYPE),
+ MAKE_INTRINSIC_I("strreplace", strreplace_cmd, SLANG_INT_TYPE),
+ MAKE_INTRINSIC_SSS("str_replace", str_replace_cmd, SLANG_INT_TYPE),
+ MAKE_INTRINSIC_SII("substr", substr_cmd, SLANG_VOID_TYPE),
+ MAKE_INTRINSIC_SS("is_substr", issubstr_cmd, SLANG_INT_TYPE),
+ MAKE_INTRINSIC_II("strsub", strsub_cmd, SLANG_VOID_TYPE),
+ MAKE_INTRINSIC_SII("extract_element", extract_element_cmd, SLANG_VOID_TYPE),
+ MAKE_INTRINSIC_SSI("is_list_element", is_list_element_cmd, SLANG_INT_TYPE),
+ MAKE_INTRINSIC_SSI("string_match", string_match_cmd, SLANG_INT_TYPE),
+ MAKE_INTRINSIC_I("string_match_nth", string_match_nth_cmd, SLANG_INT_TYPE),
+ MAKE_INTRINSIC_0("strlow", strlow_cmd, SLANG_VOID_TYPE),
+ MAKE_INTRINSIC_I("tolower", tolower_cmd, SLANG_INT_TYPE),
+ MAKE_INTRINSIC_I("toupper", toupper_cmd, SLANG_INT_TYPE),
+ MAKE_INTRINSIC_0("strup", strup_cmd, SLANG_VOID_TYPE),
+ MAKE_INTRINSIC_S("isdigit", isdigit_cmd, SLANG_INT_TYPE),
+ MAKE_INTRINSIC_S("strtrim", strtrim_cmd, SLANG_VOID_TYPE),
+ MAKE_INTRINSIC_S("strtrim_end", strtrim_end_cmd, SLANG_VOID_TYPE),
+ MAKE_INTRINSIC_S("strtrim_beg", strtrim_beg_cmd, SLANG_VOID_TYPE),
+ MAKE_INTRINSIC_0("strcompress", strcompress_cmd, SLANG_VOID_TYPE),
+ MAKE_INTRINSIC_I("Sprintf", sprintf_n_cmd, SLANG_VOID_TYPE),
+ MAKE_INTRINSIC_0("sprintf", sprintf_cmd, SLANG_VOID_TYPE),
+ MAKE_INTRINSIC_0("sscanf", _SLang_sscanf, SLANG_INT_TYPE),
+ MAKE_INTRINSIC_S("make_printable_string", make_printable_string, SLANG_VOID_TYPE),
+ MAKE_INTRINSIC_SSI("str_quote_string", str_quote_string_cmd, SLANG_VOID_TYPE),
+ MAKE_INTRINSIC_SSS("str_uncomment_string", str_uncomment_string_cmd, SLANG_VOID_TYPE),
+ MAKE_INTRINSIC_II("define_case", SLang_define_case, SLANG_VOID_TYPE),
+ MAKE_INTRINSIC_S("strtok", strtok_cmd, SLANG_VOID_TYPE),
+ MAKE_INTRINSIC_S("strjoin", strjoin_cmd, SLANG_VOID_TYPE),
+ MAKE_INTRINSIC_SSS("strtrans", strtrans_cmd, SLANG_VOID_TYPE),
+ MAKE_INTRINSIC_SS("str_delete_chars", str_delete_chars_cmd, SLANG_VOID_TYPE),
+
+ SLANG_END_INTRIN_FUN_TABLE
+};
+
+/*}}}*/
+
+int _SLang_init_slstrops (void)
+{
+ return SLadd_intrin_fun_table (Strops_Table, NULL);
+}
diff --git a/mdk-stage1/slang/slstruct.c b/mdk-stage1/slang/slstruct.c
new file mode 100644
index 000000000..33d182373
--- /dev/null
+++ b/mdk-stage1/slang/slstruct.c
@@ -0,0 +1,932 @@
+/* Structure type implementation */
+/* Copyright (c) 1998, 1999, 2001 John E. Davis
+ * This file is part of the S-Lang library.
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Perl Artistic License.
+ */
+#include "slinclud.h"
+
+#define SL_APP_WANTS_FOREACH
+#include "slang.h"
+#include "_slang.h"
+
+void _SLstruct_delete_struct (_SLang_Struct_Type *s)
+{
+ _SLstruct_Field_Type *field, *field_max;
+
+ if (s == NULL) return;
+
+ if (s->num_refs > 1)
+ {
+ s->num_refs -= 1;
+ return;
+ }
+
+ field = s->fields;
+ if (field != NULL)
+ {
+ field_max = field + s->nfields;
+
+ while (field < field_max)
+ {
+ SLang_free_object (&field->obj);
+ SLang_free_slstring (field->name); /* could be NULL */
+ field++;
+ }
+ SLfree ((char *) s->fields);
+ }
+ SLfree ((char *) s);
+}
+
+static _SLang_Struct_Type *allocate_struct (unsigned int nfields)
+{
+ _SLang_Struct_Type *s;
+ _SLstruct_Field_Type *f;
+ unsigned int i, size;
+
+ s = (_SLang_Struct_Type *) SLmalloc (sizeof (_SLang_Struct_Type));
+ if (s == NULL) return NULL;
+
+ SLMEMSET((char *) s, 0, sizeof (_SLang_Struct_Type));
+
+ size = nfields * sizeof(_SLstruct_Field_Type);
+ if (NULL == (f = (_SLstruct_Field_Type *) SLmalloc (size)))
+ {
+ SLfree ((char *) s);
+ return NULL;
+ }
+ SLMEMSET ((char *) f, 0, size);
+ s->nfields = nfields;
+ s->fields = f;
+
+ /* By default, all structs will be created with elements set to NULL. I
+ * do not know whether or not it is better to use SLANG_UNDEFINED_TYPE.
+ */
+ for (i = 0; i < nfields; i++)
+ f[i].obj.data_type = SLANG_NULL_TYPE;
+
+ return s;
+}
+
+static int push_struct_of_type (unsigned char type, _SLang_Struct_Type *s)
+{
+ SLang_Object_Type obj;
+
+ obj.data_type = type;
+ obj.v.struct_val = s;
+ s->num_refs += 1;
+
+ if (0 == SLang_push (&obj))
+ return 0;
+
+ s->num_refs -= 1;
+ return -1;
+}
+
+int _SLang_push_struct (_SLang_Struct_Type *s)
+{
+ return push_struct_of_type (SLANG_STRUCT_TYPE, s);
+}
+
+int _SLang_pop_struct (_SLang_Struct_Type **sp)
+{
+ SLang_Object_Type obj;
+ SLang_Class_Type *cl;
+ unsigned char type;
+
+ if (0 != SLang_pop (&obj))
+ return -1;
+
+ type = obj.data_type;
+ if (type != SLANG_STRUCT_TYPE)
+ {
+ cl = _SLclass_get_class (type);
+ if (cl->cl_struct_def == NULL)
+ {
+ *sp = NULL;
+ SLang_free_object (&obj);
+ SLang_verror (SL_TYPE_MISMATCH,
+ "Expecting struct type object. Found %s",
+ cl->cl_name);
+ return -1;
+ }
+ }
+
+ *sp = obj.v.struct_val;
+ return 0;
+}
+
+static void struct_destroy (unsigned char type, VOID_STAR vs)
+{
+ (void) type;
+ _SLstruct_delete_struct (*(_SLang_Struct_Type **) vs);
+}
+
+static int struct_push (unsigned char type, VOID_STAR ptr)
+{
+ return push_struct_of_type (type, *(_SLang_Struct_Type **) ptr);
+}
+
+static _SLstruct_Field_Type *find_field (_SLang_Struct_Type *s, char *name)
+{
+ _SLstruct_Field_Type *f, *fmax;
+
+ f = s->fields;
+ fmax = f + s->nfields;
+
+ while (f < fmax)
+ {
+ /* Since both these are slstrings, only compare pointer */
+ if (name == f->name)
+ return f;
+
+ f++;
+ }
+
+ return NULL;
+}
+
+static _SLstruct_Field_Type *pop_field (_SLang_Struct_Type *s, char *name)
+{
+ _SLstruct_Field_Type *f;
+
+ f = find_field (s, name);
+ if (f == NULL)
+ SLang_verror (SL_SYNTAX_ERROR, "struct has no field named %s", name);
+ return f;
+}
+
+int SLstruct_create_struct (unsigned int nfields,
+ char **field_names,
+ unsigned char *field_types,
+ VOID_STAR *field_values)
+{
+ _SLang_Struct_Type *s;
+ _SLstruct_Field_Type *f;
+ unsigned int i;
+
+ if (NULL == (s = allocate_struct (nfields)))
+ return -1;
+
+ f = s->fields;
+ for (i = 0; i < nfields; i++)
+ {
+ unsigned char type;
+ SLang_Class_Type *cl;
+ VOID_STAR value;
+ char *name = field_names [i];
+
+ if (name == NULL)
+ {
+ SLang_verror (SL_INVALID_PARM, "A struct field name cannot be NULL");
+ goto return_error;
+ }
+
+ if (NULL == (f->name = SLang_create_slstring (name)))
+ goto return_error;
+
+ if ((field_values == NULL)
+ || (NULL == (value = field_values [i])))
+ {
+ f++;
+ continue;
+ }
+
+ type = field_types[i];
+ cl = _SLclass_get_class (type);
+
+ if ((-1 == (cl->cl_push (type, value)))
+ || (-1 == SLang_pop (&f->obj)))
+ goto return_error;
+
+ f++;
+ }
+
+ if (0 == _SLang_push_struct (s))
+ return 0;
+ /* drop */
+
+ return_error:
+ _SLstruct_delete_struct (s);
+ return -1;
+}
+
+/* Interpreter interface */
+
+int _SLstruct_define_struct (void)
+{
+ int nfields;
+ _SLang_Struct_Type *s;
+ _SLstruct_Field_Type *f;
+
+ if (-1 == SLang_pop_integer (&nfields))
+ return -1;
+
+ if (nfields <= 0)
+ {
+ SLang_verror (SL_INVALID_PARM, "Number of struct fields must be > 0");
+ return -1;
+ }
+
+ if (NULL == (s = allocate_struct (nfields)))
+ return -1;
+
+ f = s->fields;
+ while (nfields)
+ {
+ char *name;
+
+ nfields--;
+ if (-1 == SLang_pop_slstring (&name))
+ {
+ _SLstruct_delete_struct (s);
+ return -1;
+ }
+ f[nfields].name = name;
+ }
+
+ if (-1 == _SLang_push_struct (s))
+ {
+ _SLstruct_delete_struct (s);
+ return -1;
+ }
+ return 0;
+}
+
+/* Simply make a struct that contains the same fields as struct s. Do not
+ * duplicate the field values.
+ */
+static _SLang_Struct_Type *make_struct_shell (_SLang_Struct_Type *s)
+{
+ _SLang_Struct_Type *new_s;
+ _SLstruct_Field_Type *new_f, *old_f;
+ unsigned int i, nfields;
+
+ nfields = s->nfields;
+ if (NULL == (new_s = allocate_struct (nfields)))
+ return NULL;
+
+ new_f = new_s->fields;
+ old_f = s->fields;
+
+ for (i = 0; i < nfields; i++)
+ {
+ if (NULL == (new_f[i].name = SLang_create_slstring (old_f[i].name)))
+ {
+ _SLstruct_delete_struct (new_s);
+ return NULL;
+ }
+ }
+ return new_s;
+}
+
+static int struct_init_array_object (unsigned char type, VOID_STAR addr)
+{
+ SLang_Class_Type *cl;
+ _SLang_Struct_Type *s;
+
+ cl = _SLclass_get_class (type);
+ if (NULL == (s = make_struct_shell (cl->cl_struct_def)))
+ return -1;
+
+ s->num_refs = 1;
+ *(_SLang_Struct_Type **) addr = s;
+ return 0;
+}
+
+static int
+typedefed_struct_datatype_deref (unsigned char type)
+{
+ SLang_Class_Type *cl;
+ _SLang_Struct_Type *s;
+
+ cl = _SLclass_get_class (type);
+ if (NULL == (s = make_struct_shell (cl->cl_struct_def)))
+ return -1;
+
+ if (-1 == push_struct_of_type (type, s))
+ {
+ _SLstruct_delete_struct (s);
+ return -1;
+ }
+
+ return 0;
+}
+
+static _SLang_Struct_Type *duplicate_struct (_SLang_Struct_Type *s)
+{
+ _SLang_Struct_Type *new_s;
+ _SLstruct_Field_Type *new_f, *f, *fmax;
+
+ new_s = make_struct_shell (s);
+
+ if (new_s == NULL)
+ return NULL;
+
+ f = s->fields;
+ fmax = f + s->nfields;
+ new_f = new_s->fields;
+
+ while (f < fmax)
+ {
+ SLang_Object_Type *obj;
+
+ obj = &f->obj;
+ if (obj->data_type != SLANG_UNDEFINED_TYPE)
+ {
+ if ((-1 == _SLpush_slang_obj (obj))
+ || (-1 == SLang_pop (&new_f->obj)))
+ {
+ _SLstruct_delete_struct (new_s);
+ return NULL;
+ }
+ }
+ new_f++;
+ f++;
+ }
+
+ return new_s;
+}
+
+static int struct_dereference (unsigned char type, VOID_STAR addr)
+{
+ _SLang_Struct_Type *s;
+
+ if (NULL == (s = duplicate_struct (*(_SLang_Struct_Type **) addr)))
+ return -1;
+
+ if (-1 == push_struct_of_type (type, s))
+ {
+ _SLstruct_delete_struct (s);
+ return -1;
+ }
+
+ return 0;
+}
+
+/*{{{ foreach */
+
+struct _SLang_Foreach_Context_Type
+{
+ _SLang_Struct_Type *s;
+ char *next_field_name;
+};
+
+static SLang_Foreach_Context_Type *
+struct_foreach_open (unsigned char type, unsigned int num)
+{
+ SLang_Foreach_Context_Type *c;
+ _SLang_Struct_Type *s;
+ char *next_name;
+
+ (void) type;
+
+ if (-1 == _SLang_pop_struct (&s))
+ return NULL;
+
+ switch (num)
+ {
+ case 0:
+ next_name = SLang_create_slstring ("next");
+ break;
+
+ case 1:
+ if (-1 == SLang_pop_slstring (&next_name))
+ next_name = NULL;
+ break;
+
+ default:
+ next_name = NULL;
+ SLang_verror (SL_NOT_IMPLEMENTED,
+ "'foreach (Struct_Type) using' requires single control value");
+ SLdo_pop_n (num);
+ break;
+ }
+
+ if (next_name == NULL)
+ {
+ _SLstruct_delete_struct (s);
+ return NULL;
+ }
+
+ c = (SLang_Foreach_Context_Type *)SLmalloc (sizeof (SLang_Foreach_Context_Type));
+ if (c == NULL)
+ {
+ _SLstruct_delete_struct (s);
+ SLang_free_slstring (next_name);
+ return NULL;
+ }
+ memset ((char *) c, 0, sizeof (SLang_Foreach_Context_Type));
+
+ c->next_field_name = next_name;
+ c->s = s;
+
+ return c;
+}
+
+static void struct_foreach_close (unsigned char type, SLang_Foreach_Context_Type *c)
+{
+ (void) type;
+ if (c == NULL) return;
+
+ SLang_free_slstring (c->next_field_name);
+ if (c->s != NULL) _SLstruct_delete_struct (c->s);
+ SLfree ((char *) c);
+}
+
+static int struct_foreach (unsigned char type, SLang_Foreach_Context_Type *c)
+{
+ _SLstruct_Field_Type *f;
+ _SLang_Struct_Type *next_s;
+
+ (void) type;
+
+ if (c == NULL)
+ return -1;
+
+ if (c->s == NULL)
+ return 0; /* done */
+
+ if (-1 == _SLang_push_struct (c->s))
+ return -1;
+
+ /* Now get the next one ready for the next foreach loop */
+
+ next_s = NULL;
+ if (NULL != (f = find_field (c->s, c->next_field_name)))
+ {
+ SLang_Class_Type *cl;
+
+ cl = _SLclass_get_class (f->obj.data_type);
+ /* Note that I cannot simply look for SLANG_STRUCT_TYPE since the
+ * user may have typedefed another struct type. So, look at the
+ * class methods.
+ */
+ if (cl->cl_foreach_open == struct_foreach_open)
+ {
+ next_s = f->obj.v.struct_val;
+ next_s->num_refs += 1;
+ }
+ }
+
+ _SLstruct_delete_struct (c->s);
+ c->s = next_s;
+
+ /* keep going */
+ return 1;
+}
+
+/*}}}*/
+
+static int struct_sput (unsigned char type, char *name)
+{
+ _SLang_Struct_Type *s;
+ _SLstruct_Field_Type *f;
+ SLang_Object_Type obj;
+
+ (void) type;
+
+ if (-1 == _SLang_pop_struct (&s))
+ return -1;
+
+ if ((NULL == (f = pop_field (s, name)))
+ || (-1 == SLang_pop (&obj)))
+ {
+ _SLstruct_delete_struct (s);
+ return -1;
+ }
+
+ SLang_free_object (&f->obj);
+ f->obj = obj;
+ _SLstruct_delete_struct (s);
+ return 0;
+}
+
+static int struct_sget (unsigned char type, char *name)
+{
+ _SLang_Struct_Type *s;
+ _SLstruct_Field_Type *f;
+ int ret;
+
+ (void) type;
+
+ if (-1 == _SLang_pop_struct (&s))
+ return -1;
+
+ if (NULL == (f = pop_field (s, name)))
+ {
+ _SLstruct_delete_struct (s);
+ return -1;
+ }
+
+ ret = _SLpush_slang_obj (&f->obj);
+ _SLstruct_delete_struct (s);
+ return ret;
+}
+
+static int struct_typecast
+ (unsigned char a_type, VOID_STAR ap, unsigned int na,
+ unsigned char b_type, VOID_STAR bp)
+{
+ _SLang_Struct_Type **a, **b;
+ unsigned int i;
+
+ (void) a_type;
+ (void) b_type;
+
+ a = (_SLang_Struct_Type **) ap;
+ b = (_SLang_Struct_Type **) bp;
+ for (i = 0; i < na; i++)
+ {
+ b[i] = a[i];
+ if (a[i] != NULL)
+ a[i]->num_refs += 1;
+ }
+
+ return 1;
+}
+
+int _SLstruct_define_typedef (void)
+{
+ char *type_name;
+ _SLang_Struct_Type *s, *s1;
+ SLang_Class_Type *cl;
+
+ if (-1 == SLang_pop_slstring (&type_name))
+ return -1;
+
+ if (-1 == _SLang_pop_struct (&s))
+ {
+ SLang_free_slstring (type_name);
+ return -1;
+ }
+
+ if (NULL == (s1 = make_struct_shell (s)))
+ {
+ SLang_free_slstring (type_name);
+ _SLstruct_delete_struct (s);
+ return -1;
+ }
+
+ _SLstruct_delete_struct (s);
+
+ if (NULL == (cl = SLclass_allocate_class (type_name)))
+ {
+ SLang_free_slstring (type_name);
+ _SLstruct_delete_struct (s1);
+ return -1;
+ }
+ SLang_free_slstring (type_name);
+
+ cl->cl_struct_def = s1;
+ cl->cl_init_array_object = struct_init_array_object;
+ cl->cl_datatype_deref = typedefed_struct_datatype_deref;
+ cl->cl_destroy = struct_destroy;
+ cl->cl_push = struct_push;
+ cl->cl_dereference = struct_dereference;
+ cl->cl_foreach_open = struct_foreach_open;
+ cl->cl_foreach_close = struct_foreach_close;
+ cl->cl_foreach = struct_foreach;
+
+ cl->cl_sget = struct_sget;
+ cl->cl_sput = struct_sput;
+
+ if (-1 == SLclass_register_class (cl,
+ SLANG_VOID_TYPE, /* any open slot */
+ sizeof (_SLang_Struct_Type),
+ SLANG_CLASS_TYPE_PTR))
+ {
+ /* FIXME: Priority=low */
+ /* There is a memory leak here if this fails... */
+ return -1;
+ }
+ /* Note: typecast from a user type struct type allowed but not the other
+ * way.
+ */
+ if (-1 == SLclass_add_typecast (cl->cl_data_type, SLANG_STRUCT_TYPE, struct_typecast, 1))
+ return -1;
+
+ return 0;
+}
+
+static int
+struct_datatype_deref (unsigned char stype)
+{
+ (void) stype;
+
+ if (SLang_peek_at_stack () == SLANG_ARRAY_TYPE)
+ {
+ SLang_Array_Type *at;
+ int status;
+
+ if (-1 == SLang_pop_array_of_type (&at, SLANG_STRING_TYPE))
+ return -1;
+
+ status = SLstruct_create_struct (at->num_elements,
+ (char **) at->data, NULL, NULL);
+
+ SLang_free_array (at);
+ return status;
+ }
+
+ SLang_push_integer (SLang_Num_Function_Args);
+ return _SLstruct_define_struct ();
+}
+
+static int register_struct (void)
+{
+ SLang_Class_Type *cl;
+
+ if (NULL == (cl = SLclass_allocate_class ("Struct_Type")))
+ return -1;
+
+ (void) SLclass_set_destroy_function (cl, struct_destroy);
+ (void) SLclass_set_push_function (cl, struct_push);
+ cl->cl_dereference = struct_dereference;
+ cl->cl_datatype_deref = struct_datatype_deref;
+
+ cl->cl_foreach_open = struct_foreach_open;
+ cl->cl_foreach_close = struct_foreach_close;
+ cl->cl_foreach = struct_foreach;
+
+ cl->cl_sget = struct_sget;
+ cl->cl_sput = struct_sput;
+
+ if (-1 == SLclass_register_class (cl, SLANG_STRUCT_TYPE, sizeof (_SLang_Struct_Type),
+ SLANG_CLASS_TYPE_PTR))
+ return -1;
+
+ return 0;
+}
+
+static void get_struct_field_names (_SLang_Struct_Type *s)
+{
+ SLang_Array_Type *a;
+ char **data;
+ int i, nfields;
+ _SLstruct_Field_Type *f;
+
+ nfields = (int) s->nfields;
+
+ if (NULL == (a = SLang_create_array (SLANG_STRING_TYPE, 0, NULL, &nfields, 1)))
+ return;
+
+ f = s->fields;
+ data = (char **) a->data;
+ for (i = 0; i < nfields; i++)
+ {
+ /* Since we are dealing with hashed strings, the next call should not
+ * fail. If it does, the interpreter will handle it at some other
+ * level.
+ */
+ data [i] = SLang_create_slstring (f[i].name);
+ }
+
+ SLang_push_array (a, 1);
+}
+
+static int push_struct_fields (_SLang_Struct_Type *s)
+{
+ _SLstruct_Field_Type *f, *fmax;
+ int num;
+
+ f = s->fields;
+ fmax = f + s->nfields;
+
+ num = 0;
+ while (fmax > f)
+ {
+ fmax--;
+ if (-1 == _SLpush_slang_obj (&fmax->obj))
+ break;
+
+ num++;
+ }
+
+ return num;
+}
+
+/* Syntax: set_struct_field (s, name, value); */
+static void struct_set_field (void)
+{
+ _SLang_Struct_Type *s;
+ _SLstruct_Field_Type *f;
+ SLang_Object_Type obj;
+ char *name;
+
+ if (-1 == SLang_pop (&obj))
+ return;
+
+ if (-1 == SLang_pop_slstring (&name))
+ {
+ SLang_free_object (&obj);
+ return;
+ }
+
+ if (-1 == _SLang_pop_struct (&s))
+ {
+ SLang_free_slstring (name);
+ SLang_free_object (&obj);
+ return;
+ }
+
+ if (NULL == (f = pop_field (s, name)))
+ {
+ _SLstruct_delete_struct (s);
+ SLang_free_slstring (name);
+ SLang_free_object (&obj);
+ return;
+ }
+
+ SLang_free_object (&f->obj);
+ f->obj = obj;
+
+ _SLstruct_delete_struct (s);
+ SLang_free_slstring (name);
+}
+
+/* Syntax: set_struct_fields (s, values....); */
+static void set_struct_fields (void)
+{
+ unsigned int n;
+ _SLang_Struct_Type *s;
+ _SLstruct_Field_Type *f;
+
+ n = (unsigned int) SLang_Num_Function_Args;
+
+ if (-1 == SLreverse_stack (n))
+ return;
+
+ n--;
+ if (-1 == _SLang_pop_struct (&s))
+ {
+ SLdo_pop_n (n);
+ return;
+ }
+
+ if (n > s->nfields)
+ {
+ SLdo_pop_n (n);
+ SLang_verror (SL_INVALID_PARM, "Too many values for structure");
+ _SLstruct_delete_struct (s);
+ return;
+ }
+
+ f = s->fields;
+ while (n > 0)
+ {
+ SLang_Object_Type obj;
+
+ if (-1 == SLang_pop (&obj))
+ break;
+
+ SLang_free_object (&f->obj);
+ f->obj = obj;
+
+ f++;
+ n--;
+ }
+
+ _SLstruct_delete_struct (s);
+}
+
+static void get_struct_field (char *name)
+{
+ (void) struct_sget (0, name);
+}
+
+static int is_struct_type (void)
+{
+ SLang_Object_Type obj;
+ unsigned char type;
+ int status;
+
+ if (-1 == SLang_pop (&obj))
+ return -1;
+
+ type = obj.data_type;
+ if (type == SLANG_STRUCT_TYPE)
+ status = 1;
+ else
+ status = (NULL != _SLclass_get_class (type)->cl_struct_def);
+ SLang_free_object (&obj);
+ return status;
+}
+
+
+static SLang_Intrin_Fun_Type Struct_Table [] =
+{
+ MAKE_INTRINSIC_1("get_struct_field_names", get_struct_field_names, SLANG_VOID_TYPE, SLANG_STRUCT_TYPE),
+ MAKE_INTRINSIC_1("get_struct_field", get_struct_field, SLANG_VOID_TYPE, SLANG_STRING_TYPE),
+ MAKE_INTRINSIC_1("_push_struct_field_values", push_struct_fields, SLANG_INT_TYPE, SLANG_STRUCT_TYPE),
+ MAKE_INTRINSIC_0("set_struct_field", struct_set_field, SLANG_VOID_TYPE),
+ MAKE_INTRINSIC_0("set_struct_fields", set_struct_fields, SLANG_VOID_TYPE),
+ MAKE_INTRINSIC_0("is_struct_type", is_struct_type, SLANG_INT_TYPE),
+ /* MAKE_INTRINSIC_I("_create_struct", create_struct, SLANG_VOID_TYPE), */
+ SLANG_END_INTRIN_FUN_TABLE
+};
+
+int _SLstruct_init (void)
+{
+ if ((-1 == SLadd_intrin_fun_table (Struct_Table, NULL))
+ || (-1 == register_struct ()))
+ return -1;
+
+ return 0;
+}
+
+void _SLstruct_pop_args (int *np)
+{
+ SLang_Array_Type *at;
+ int i, n;
+ _SLang_Struct_Type **data;
+
+ n = *np;
+
+ if (n < 0)
+ {
+ SLang_Error = SL_INVALID_PARM;
+ return;
+ }
+
+ data = (_SLang_Struct_Type **) SLmalloc ((n + 1) * sizeof (_SLang_Struct_Type *));
+ if (data == NULL)
+ {
+ SLdo_pop_n (n);
+ return;
+ }
+
+ memset ((char *)data, 0, n * sizeof (_SLang_Struct_Type *));
+
+ i = n;
+ while (i > 0)
+ {
+ _SLang_Struct_Type *s;
+ _SLstruct_Field_Type *f;
+
+ i--;
+
+ if (NULL == (s = allocate_struct (1)))
+ goto return_error;
+
+ data[i] = s;
+ s->num_refs += 1; /* keeping a copy */
+
+ f = s->fields;
+ if (NULL == (f->name = SLang_create_slstring ("value")))
+ goto return_error;
+
+ if (-1 == SLang_pop (&f->obj))
+ goto return_error;
+ }
+
+ if (NULL == (at = SLang_create_array (SLANG_STRUCT_TYPE, 0,
+ (VOID_STAR) data, &n, 1)))
+ goto return_error;
+
+ (void) SLang_push_array (at, 1);
+ return;
+
+ return_error:
+ for (i = 0; i < n; i++)
+ {
+ _SLang_Struct_Type *s;
+
+ s = data[i];
+ if (s != NULL)
+ _SLstruct_delete_struct (s);
+ }
+
+ SLfree ((char *) data);
+}
+
+void _SLstruct_push_args (SLang_Array_Type *at)
+{
+ _SLang_Struct_Type **sp;
+ unsigned int num;
+
+ if (at->data_type != SLANG_STRUCT_TYPE)
+ {
+ SLang_Error = SL_TYPE_MISMATCH;
+ return;
+ }
+
+ sp = (_SLang_Struct_Type **) at->data;
+ num = at->num_elements;
+
+ while ((SLang_Error == 0) && (num > 0))
+ {
+ _SLang_Struct_Type *s;
+
+ num--;
+ if (NULL == (s = *sp++))
+ {
+ SLang_push_null ();
+ continue;
+ }
+
+ /* I should check to see if the value field is present, but... */
+ (void) _SLpush_slang_obj (&s->fields->obj);
+ }
+}
diff --git a/mdk-stage1/slang/sltermin.c b/mdk-stage1/slang/sltermin.c
new file mode 100644
index 000000000..f9c64f0b2
--- /dev/null
+++ b/mdk-stage1/slang/sltermin.c
@@ -0,0 +1,1155 @@
+/* This file contains enough terminfo reading capabilities sufficient for
+ * the slang SLtt interface.
+ */
+
+/* Copyright (c) 1992, 1999, 2001 John E. Davis
+ * This file is part of the S-Lang library.
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Perl Artistic License.
+ */
+
+#include "slinclud.h"
+
+#include "slang.h"
+#include "_slang.h"
+
+/*
+ * The majority of the comments found in the file were taken from the
+ * term(4) man page on an SGI.
+ */
+
+/* Short integers are stored in two 8-bit bytes. The first byte contains
+ * the least significant 8 bits of the value, and the second byte contains
+ * the most significant 8 bits. (Thus, the value represented is
+ * 256*second+first.) The value -1 is represented by 0377,0377, and the
+ * value -2 is represented by 0376,0377; other negative values are illegal.
+ * The -1 generally means that a capability is missing from this terminal.
+ * The -2 means that the capability has been cancelled in the terminfo
+ * source and also is to be considered missing.
+ */
+
+static int make_integer (unsigned char *buf)
+{
+ register int lo, hi;
+ lo = (int) *buf++; hi = (int) *buf;
+ if (hi == 0377)
+ {
+ if (lo == 0377) return -1;
+ if (lo == 0376) return -2;
+ }
+ return lo + 256 * hi;
+}
+
+/*
+ * The compiled file is created from the source file descriptions of the
+ * terminals (see the -I option of infocmp) by using the terminfo compiler,
+ * tic, and read by the routine setupterm [see curses(3X).] The file is
+ * divided into six parts in the following order: the header, terminal
+ * names, boolean flags, numbers, strings, and string table.
+ *
+ * The header section begins the file. This section contains six short
+ * integers in the format described below. These integers are (1) the magic
+ * number (octal 0432); (2) the size, in bytes, of the names section; (3)
+ * the number of bytes in the boolean section; (4) the number of short
+ * integers in the numbers section; (5) the number of offsets (short
+ * integers) in the strings section; (6) the size, in bytes, of the string
+ * table.
+ */
+
+#define MAGIC 0432
+
+/* In this structure, all char * fields are malloced EXCEPT if the
+ * structure is SLTERMCAP. In that case, only terminal_names is malloced
+ * and the other fields are pointers into it.
+ */
+struct _SLterminfo_Type
+{
+#define SLTERMINFO 1
+#define SLTERMCAP 2
+ unsigned int flags;
+
+ unsigned int name_section_size;
+ char *terminal_names;
+
+ unsigned int boolean_section_size;
+ unsigned char *boolean_flags;
+
+ unsigned int num_numbers;
+ unsigned char *numbers;
+
+ unsigned int num_string_offsets;
+ unsigned char *string_offsets;
+
+ unsigned int string_table_size;
+ char *string_table;
+
+};
+
+static char *tcap_getstr (char *, SLterminfo_Type *);
+static int tcap_getnum (char *, SLterminfo_Type *);
+static int tcap_getflag (char *, SLterminfo_Type *);
+static int tcap_getent (char *, SLterminfo_Type *);
+
+static FILE *open_terminfo (char *file, SLterminfo_Type *h)
+{
+ FILE *fp;
+ unsigned char buf[12];
+
+ /* Alan Cox reported a security problem here if the application using the
+ * library is setuid. So, I need to make sure open the file as a normal
+ * user. Unfortunately, there does not appear to be a portable way of
+ * doing this, so I am going to use 'setfsgid' and 'setfsuid', which
+ * are not portable.
+ *
+ * I will also look into the use of setreuid, seteuid and setregid, setegid.
+ * FIXME: Priority=medium
+ */
+ fp = fopen (file, "rb");
+ if (fp == NULL) return NULL;
+
+ if ((12 == fread ((char *) buf, 1, 12, fp) && (MAGIC == make_integer (buf))))
+ {
+ h->name_section_size = make_integer (buf + 2);
+ h->boolean_section_size = make_integer (buf + 4);
+ h->num_numbers = make_integer (buf + 6);
+ h->num_string_offsets = make_integer (buf + 8);
+ h->string_table_size = make_integer (buf + 10);
+ }
+ else
+ {
+ fclose (fp);
+ fp = NULL;
+ }
+ return fp;
+}
+
+/*
+ * The terminal names section comes next. It contains the first line of the
+ * terminfo description, listing the various names for the terminal,
+ * separated by the bar ( | ) character (see term(5)). The section is
+ * terminated with an ASCII NUL character.
+ */
+
+/* returns pointer to malloced space */
+static unsigned char *read_terminfo_section (FILE *fp, unsigned int size)
+{
+ char *s;
+
+ if (NULL == (s = (char *) SLmalloc (size))) return NULL;
+ if (size != fread (s, 1, size, fp))
+ {
+ SLfree (s);
+ return NULL;
+ }
+ return (unsigned char *) s;
+}
+
+static char *read_terminal_names (FILE *fp, SLterminfo_Type *t)
+{
+ return t->terminal_names = (char *) read_terminfo_section (fp, t->name_section_size);
+}
+
+/*
+ * The boolean flags have one byte for each flag. This byte is either 0 or
+ * 1 as the flag is present or absent. The value of 2 means that the flag
+ * has been cancelled. The capabilities are in the same order as the file
+ * <term.h>.
+ */
+
+static unsigned char *read_boolean_flags (FILE *fp, SLterminfo_Type *t)
+{
+ /* Between the boolean section and the number section, a null byte is
+ * inserted, if necessary, to ensure that the number section begins on an
+ * even byte offset. All short integers are aligned on a short word
+ * boundary.
+ */
+
+ unsigned int size = (t->name_section_size + t->boolean_section_size) % 2;
+ size += t->boolean_section_size;
+
+ return t->boolean_flags = read_terminfo_section (fp, size);
+}
+
+/*
+ * The numbers section is similar to the boolean flags section. Each
+ * capability takes up two bytes, and is stored as a short integer. If the
+ * value represented is -1 or -2, the capability is taken to be missing.
+ */
+
+static unsigned char *read_numbers (FILE *fp, SLterminfo_Type *t)
+{
+ return t->numbers = read_terminfo_section (fp, 2 * t->num_numbers);
+}
+
+/* The strings section is also similar. Each capability is stored as a
+ * short integer, in the format above. A value of -1 or -2 means the
+ * capability is missing. Otherwise, the value is taken as an offset from
+ * the beginning of the string table. Special characters in ^X or \c
+ * notation are stored in their interpreted form, not the printing
+ * representation. Padding information ($<nn>) and parameter information
+ * (%x) are stored intact in uninterpreted form.
+ */
+
+static unsigned char *read_string_offsets (FILE *fp, SLterminfo_Type *t)
+{
+ return t->string_offsets = (unsigned char *) read_terminfo_section (fp, 2 * t->num_string_offsets);
+}
+
+/* The final section is the string table. It contains all the values of
+ * string capabilities referenced in the string section. Each string is
+ * null terminated.
+ */
+
+static char *read_string_table (FILE *fp, SLterminfo_Type *t)
+{
+ return t->string_table = (char *) read_terminfo_section (fp, t->string_table_size);
+}
+
+/*
+ * Compiled terminfo(4) descriptions are placed under the directory
+ * /usr/share/lib/terminfo. In order to avoid a linear search of a huge
+ * UNIX system directory, a two-level scheme is used:
+ * /usr/share/lib/terminfo/c/name where name is the name of the terminal,
+ * and c is the first character of name. Thus, att4425 can be found in the
+ * file /usr/share/lib/terminfo/a/att4425. Synonyms for the same terminal
+ * are implemented by multiple links to the same compiled file.
+ */
+
+#define MAX_TI_DIRS 7
+static char *Terminfo_Dirs [MAX_TI_DIRS] =
+{
+ NULL, /* $HOME/.terminfo */
+ NULL, /* $TERMINFO */
+ "/usr/share/terminfo",
+ "/usr/lib/terminfo",
+ "/usr/share/lib/terminfo",
+ "/etc/terminfo",
+ "/usr/local/lib/terminfo"
+};
+
+SLterminfo_Type *_SLtt_tigetent (char *term)
+{
+ char *tidir;
+ int i;
+ FILE *fp = NULL;
+ char file[1024];
+ static char home_ti [1024];
+ char *home;
+ SLterminfo_Type *ti;
+
+ if (
+ (term == NULL)
+#ifdef SLANG_UNTIC
+ && (SLang_Untic_Terminfo_File == NULL)
+#endif
+ )
+ return NULL;
+
+ if (NULL == (ti = (SLterminfo_Type *) SLmalloc (sizeof (SLterminfo_Type))))
+ {
+ return NULL;
+ }
+
+#ifdef SLANG_UNTIC
+ if (SLang_Untic_Terminfo_File != NULL)
+ {
+ fp = open_terminfo (SLang_Untic_Terminfo_File, ti);
+ goto fp_open_label;
+ }
+ else
+#endif
+ /* If we are on a termcap based system, use termcap */
+ if (0 == tcap_getent (term, ti)) return ti;
+
+ if (NULL != (home = getenv ("HOME")))
+ {
+ strncpy (home_ti, home, sizeof (home_ti) - 11);
+ home_ti [sizeof(home_ti) - 11] = 0;
+ strcat (home_ti, "/.terminfo");
+ Terminfo_Dirs [0] = home_ti;
+ }
+
+ Terminfo_Dirs[1] = getenv ("TERMINFO");
+ i = 0;
+ while (i < MAX_TI_DIRS)
+ {
+ tidir = Terminfo_Dirs[i];
+ if ((tidir != NULL)
+ && (sizeof (file) > strlen (tidir) + 2 + strlen (term)))
+ {
+ sprintf (file, "%s/%c/%s", tidir, *term, term);
+ if (NULL != (fp = open_terminfo (file, ti)))
+ break;
+ }
+ i++;
+ }
+#ifdef SLANG_UNTIC
+ fp_open_label:
+#endif
+
+ if (fp != NULL)
+ {
+ if (NULL != read_terminal_names (fp, ti))
+ {
+ if (NULL != read_boolean_flags (fp, ti))
+ {
+ if (NULL != read_numbers (fp, ti))
+ {
+ if (NULL != read_string_offsets (fp, ti))
+ {
+ if (NULL != read_string_table (fp, ti))
+ {
+ /* success */
+ fclose (fp);
+ ti->flags = SLTERMINFO;
+ return ti;
+ }
+ SLfree ((char *)ti->string_offsets);
+ }
+ SLfree ((char *)ti->numbers);
+ }
+ SLfree ((char *)ti->boolean_flags);
+ }
+ SLfree ((char *)ti->terminal_names);
+ }
+ fclose (fp);
+ }
+
+ SLfree ((char *)ti);
+ return NULL;
+}
+
+#ifdef SLANG_UNTIC
+# define UNTIC_COMMENT(x) ,x
+#else
+# define UNTIC_COMMENT(x)
+#endif
+
+typedef struct
+{
+ char name[3];
+ int offset;
+#ifdef SLANG_UNTIC
+ char *comment;
+#endif
+}
+Tgetstr_Map_Type;
+
+/* I need to add: K1-5, %0-5(not important), @8, &8... */
+static Tgetstr_Map_Type Tgetstr_Map [] =
+{
+ {"!1", 212 UNTIC_COMMENT("shifted key")},
+ {"!2", 213 UNTIC_COMMENT("shifted key")},
+ {"!3", 214 UNTIC_COMMENT("shifted key")},
+ {"#1", 198 UNTIC_COMMENT("shifted key")},
+ {"#2", 199 UNTIC_COMMENT("Key S-Home")},
+ {"#3", 200 UNTIC_COMMENT("Key S-Insert")},
+ {"#4", 201 UNTIC_COMMENT("Key S-Left")},
+ {"%0", 177 UNTIC_COMMENT("redo key")},
+ {"%1", 168 UNTIC_COMMENT("help key")},
+ {"%2", 169 UNTIC_COMMENT("mark key")},
+ {"%3", 170 UNTIC_COMMENT("message key")},
+ {"%4", 171 UNTIC_COMMENT("move key")},
+ {"%5", 172 UNTIC_COMMENT("next key")},
+ {"%6", 173 UNTIC_COMMENT("open key")},
+ {"%7", 174 UNTIC_COMMENT("options key")},
+ {"%8", 175 UNTIC_COMMENT("previous key")},
+ {"%9", 176 UNTIC_COMMENT("print key")},
+ {"%a", 202 UNTIC_COMMENT("shifted key")},
+ {"%b", 203 UNTIC_COMMENT("shifted key")},
+ {"%c", 204 UNTIC_COMMENT("Key S-Next")},
+ {"%d", 205 UNTIC_COMMENT("shifted key")},
+ {"%e", 206 UNTIC_COMMENT("Key S-Previous")},
+ {"%f", 207 UNTIC_COMMENT("shifted key")},
+ {"%g", 208 UNTIC_COMMENT("shifted key")},
+ {"%h", 209 UNTIC_COMMENT("shifted key")},
+ {"%i", 210 UNTIC_COMMENT("Key S-Right")},
+ {"%j", 211 UNTIC_COMMENT("shifted key")},
+ {"&0", 187 UNTIC_COMMENT("shifted key")},
+ {"&1", 178 UNTIC_COMMENT("reference key")},
+ {"&2", 179 UNTIC_COMMENT("refresh key")},
+ {"&3", 180 UNTIC_COMMENT("replace key")},
+ {"&4", 181 UNTIC_COMMENT("restart key")},
+ {"&5", 182 UNTIC_COMMENT("resume key")},
+ {"&6", 183 UNTIC_COMMENT("save key")},
+ {"&7", 184 UNTIC_COMMENT("suspend key")},
+ {"&8", 185 UNTIC_COMMENT("undo key")},
+ {"&9", 186 UNTIC_COMMENT("shifted key")},
+ {"*0", 197 UNTIC_COMMENT("shifted key")},
+ {"*1", 188 UNTIC_COMMENT("shifted key")},
+ {"*2", 189 UNTIC_COMMENT("shifted key")},
+ {"*3", 190 UNTIC_COMMENT("shifted key")},
+ {"*4", 191 UNTIC_COMMENT("Key S-Delete")},
+ {"*5", 192 UNTIC_COMMENT("shifted key")},
+ {"*6", 193 UNTIC_COMMENT("select key")},
+ {"*7", 194 UNTIC_COMMENT("Key S-End")},
+ {"*8", 195 UNTIC_COMMENT("shifted key")},
+ {"*9", 196 UNTIC_COMMENT("shifted key")},
+ {"@0", 167 UNTIC_COMMENT("find key")},
+ {"@1", 158 UNTIC_COMMENT("begin key")},
+ {"@2", 159 UNTIC_COMMENT("cancel key")},
+ {"@3", 160 UNTIC_COMMENT("close key")},
+ {"@4", 161 UNTIC_COMMENT("command key")},
+ {"@5", 162 UNTIC_COMMENT("copy key")},
+ {"@6", 163 UNTIC_COMMENT("create key")},
+ {"@7", 164 UNTIC_COMMENT("Key End")},
+ {"@8", 165 UNTIC_COMMENT("enter/send key")},
+ {"@9", 166 UNTIC_COMMENT("exit key")},
+ {"AB", 360 UNTIC_COMMENT("set ANSI color background")},
+ {"AF", 359 UNTIC_COMMENT("set ANSI color foreground")},
+ {"AL", 110 UNTIC_COMMENT("parm_insert_line")},
+ {"CC", 9 UNTIC_COMMENT("terminal settable cmd character in prototype !?")},
+ {"CM", 15 UNTIC_COMMENT("memory relative cursor addressing")},
+ {"CW", 277 UNTIC_COMMENT("define a window #1 from #2, #3 to #4, #5")},
+ {"DC", 105 UNTIC_COMMENT("delete #1 chars")},
+ {"DI", 280 UNTIC_COMMENT("dial number #1")},
+ {"DK", 275 UNTIC_COMMENT("display clock at (#1,#2)")},
+ {"DL", 106 UNTIC_COMMENT("parm_delete_line")},
+ {"DO", 107 UNTIC_COMMENT("down #1 lines")},
+ {"F1", 216 UNTIC_COMMENT("key_f11")},
+ {"F2", 217 UNTIC_COMMENT("key_f12")},
+ {"F3", 218 UNTIC_COMMENT("key_f13")},
+ {"F4", 219 UNTIC_COMMENT("key_f14")},
+ {"F5", 220 UNTIC_COMMENT("key_f15")},
+ {"F6", 221 UNTIC_COMMENT("key_f16")},
+ {"F7", 222 UNTIC_COMMENT("key_f17")},
+ {"F8", 223 UNTIC_COMMENT("key_f18")},
+ {"F9", 224 UNTIC_COMMENT("key_f19")},
+ {"FA", 225 UNTIC_COMMENT("key_f20")},
+ {"FB", 226 UNTIC_COMMENT("F21 function key")},
+ {"FC", 227 UNTIC_COMMENT("F22 function key")},
+ {"FD", 228 UNTIC_COMMENT("F23 function key")},
+ {"FE", 229 UNTIC_COMMENT("F24 function key")},
+ {"FF", 230 UNTIC_COMMENT("F25 function key")},
+ {"FG", 231 UNTIC_COMMENT("F26 function key")},
+ {"FH", 232 UNTIC_COMMENT("F27 function key")},
+ {"FI", 233 UNTIC_COMMENT("F28 function key")},
+ {"FJ", 234 UNTIC_COMMENT("F29 function key")},
+ {"FK", 235 UNTIC_COMMENT("F30 function key")},
+ {"FL", 236 UNTIC_COMMENT("F31 function key")},
+ {"FM", 237 UNTIC_COMMENT("F32 function key")},
+ {"FN", 238 UNTIC_COMMENT("F33 function key")},
+ {"FO", 239 UNTIC_COMMENT("F34 function key")},
+ {"FP", 240 UNTIC_COMMENT("F35 function key")},
+ {"FQ", 241 UNTIC_COMMENT("F36 function key")},
+ {"FR", 242 UNTIC_COMMENT("F37 function key")},
+ {"FS", 243 UNTIC_COMMENT("F38 function key")},
+ {"FT", 244 UNTIC_COMMENT("F39 function key")},
+ {"FU", 245 UNTIC_COMMENT("F40 function key")},
+ {"FV", 246 UNTIC_COMMENT("F41 function key")},
+ {"FW", 247 UNTIC_COMMENT("F42 function key")},
+ {"FX", 248 UNTIC_COMMENT("F43 function key")},
+ {"FY", 249 UNTIC_COMMENT("F44 function key")},
+ {"FZ", 250 UNTIC_COMMENT("F45 function key")},
+ {"Fa", 251 UNTIC_COMMENT("F46 function key")},
+ {"Fb", 252 UNTIC_COMMENT("F47 function key")},
+ {"Fc", 253 UNTIC_COMMENT("F48 function key")},
+ {"Fd", 254 UNTIC_COMMENT("F49 function key")},
+ {"Fe", 255 UNTIC_COMMENT("F50 function key")},
+ {"Ff", 256 UNTIC_COMMENT("F51 function key")},
+ {"Fg", 257 UNTIC_COMMENT("F52 function key")},
+ {"Fh", 258 UNTIC_COMMENT("F53 function key")},
+ {"Fi", 259 UNTIC_COMMENT("F54 function key")},
+ {"Fj", 260 UNTIC_COMMENT("F55 function key")},
+ {"Fk", 261 UNTIC_COMMENT("F56 function key")},
+ {"Fl", 262 UNTIC_COMMENT("F57 function key")},
+ {"Fm", 263 UNTIC_COMMENT("F58 function key")},
+ {"Fn", 264 UNTIC_COMMENT("F59 function key")},
+ {"Fo", 265 UNTIC_COMMENT("F60 function key")},
+ {"Fp", 266 UNTIC_COMMENT("F61 function key")},
+ {"Fq", 267 UNTIC_COMMENT("F62 function key")},
+ {"Fr", 268 UNTIC_COMMENT("F63 function key")},
+ {"G1", 400 UNTIC_COMMENT("single upper right")},
+ {"G2", 398 UNTIC_COMMENT("single upper left")},
+ {"G3", 399 UNTIC_COMMENT("single lower left")},
+ {"G4", 401 UNTIC_COMMENT("single lower right")},
+ {"GC", 408 UNTIC_COMMENT("single intersection")},
+ {"GD", 405 UNTIC_COMMENT("tee pointing down")},
+ {"GH", 406 UNTIC_COMMENT("single horizontal line")},
+ {"GL", 403 UNTIC_COMMENT("tee pointing left")},
+ {"GR", 402 UNTIC_COMMENT("tee pointing right")},
+ {"GU", 404 UNTIC_COMMENT("tee pointing up")},
+ {"GV", 407 UNTIC_COMMENT("single vertical line")},
+ {"Gm", 358 UNTIC_COMMENT("Curses should get button events")},
+ {"HU", 279 UNTIC_COMMENT("hang-up phone")},
+ {"IC", 108 UNTIC_COMMENT("insert #1 chars")},
+ {"Ic", 299 UNTIC_COMMENT("initialize color #1 to (#2,#3,#4)")},
+ {"Ip", 300 UNTIC_COMMENT("Initialize color pair #1 to fg=(#2,#3,#4), bg=(#5,#6,#7)")},
+ {"K1", 139 UNTIC_COMMENT("upper left of keypad")},
+ {"K2", 141 UNTIC_COMMENT("center of keypad")},
+ {"K3", 140 UNTIC_COMMENT("upper right of keypad")},
+ {"K4", 142 UNTIC_COMMENT("lower left of keypad")},
+ {"K5", 143 UNTIC_COMMENT("lower right of keypad")},
+ {"Km", 355 UNTIC_COMMENT("Mouse event has occurred")},
+ {"LE", 111 UNTIC_COMMENT("move #1 chars to the left")},
+ {"LF", 157 UNTIC_COMMENT("turn off soft labels")},
+ {"LO", 156 UNTIC_COMMENT("turn on soft labels")},
+ {"Lf", 273 UNTIC_COMMENT("label format")},
+ {"MC", 270 UNTIC_COMMENT("clear right and left soft margins")},
+ {"ML", 271 UNTIC_COMMENT("set left soft margin")},
+ {"ML", 368 UNTIC_COMMENT("Set both left and right margins to #1, #2")},
+ {"MR", 272 UNTIC_COMMENT("set right soft margin")},
+ {"MT", 369 UNTIC_COMMENT("Sets both top and bottom margins to #1, #2")},
+ {"Mi", 356 UNTIC_COMMENT("Mouse status information")},
+ {"PA", 285 UNTIC_COMMENT("pause for 2-3 seconds")},
+ {"PU", 283 UNTIC_COMMENT("select pulse dialling")},
+ {"QD", 281 UNTIC_COMMENT("dial number #1 without checking")},
+ {"RA", 152 UNTIC_COMMENT("turn off automatic margins")},
+ {"RC", 276 UNTIC_COMMENT("remove clock")},
+ {"RF", 215 UNTIC_COMMENT("send next input char (for ptys)")},
+ {"RI", 112 UNTIC_COMMENT("parm_right_cursor")},
+ {"RQ", 357 UNTIC_COMMENT("Request mouse position")},
+ {"RX", 150 UNTIC_COMMENT("turn off xon/xoff handshaking")},
+ {"S1", 378 UNTIC_COMMENT("Display PC character")},
+ {"S2", 379 UNTIC_COMMENT("Enter PC character display mode")},
+ {"S3", 380 UNTIC_COMMENT("Exit PC character display mode")},
+ {"S4", 381 UNTIC_COMMENT("Enter PC scancode mode")},
+ {"S5", 382 UNTIC_COMMENT("Exit PC scancode mode")},
+ {"S6", 383 UNTIC_COMMENT("PC terminal options")},
+ {"S7", 384 UNTIC_COMMENT("Escape for scancode emulation")},
+ {"S8", 385 UNTIC_COMMENT("Alternate escape for scancode emulation")},
+ {"SA", 151 UNTIC_COMMENT("turn on automatic margins")},
+ {"SC", 274 UNTIC_COMMENT("set clock, #1 hrs #2 mins #3 secs")},
+ {"SF", 109 UNTIC_COMMENT("scroll forward #1 lines")},
+ {"SR", 113 UNTIC_COMMENT("scroll back #1 lines")},
+ {"SX", 149 UNTIC_COMMENT("turn on xon/xoff handshaking")},
+ {"Sb", 303 UNTIC_COMMENT("set background (color)")},
+ {"Sf", 302 UNTIC_COMMENT("set foreground (color)")},
+ {"TO", 282 UNTIC_COMMENT("select touch tone dialing")},
+ {"UP", 114 UNTIC_COMMENT("up #1 lines")},
+ {"WA", 286 UNTIC_COMMENT("wait for dial-tone")},
+ {"WG", 278 UNTIC_COMMENT("go to window #1")},
+ {"XF", 154 UNTIC_COMMENT("XOFF character")},
+ {"XN", 153 UNTIC_COMMENT("XON character")},
+ {"Xh", 386 UNTIC_COMMENT("Enter horizontal highlight mode")},
+ {"Xl", 387 UNTIC_COMMENT("Enter left highlight mode")},
+ {"Xo", 388 UNTIC_COMMENT("Enter low highlight mode")},
+ {"Xr", 389 UNTIC_COMMENT("Enter right highlight mode")},
+ {"Xt", 390 UNTIC_COMMENT("Enter top highlight mode")},
+ {"Xv", 391 UNTIC_COMMENT("Enter vertical highlight mode")},
+ {"Xy", 370 UNTIC_COMMENT("Repeat bit image cell #1 #2 times")},
+ {"YZ", 377 UNTIC_COMMENT("Set page length to #1 lines")},
+ {"Yv", 372 UNTIC_COMMENT("Move to beginning of same row")},
+ {"Yw", 373 UNTIC_COMMENT("Give name for color #1")},
+ {"Yx", 374 UNTIC_COMMENT("Define rectangualar bit image region")},
+ {"Yy", 375 UNTIC_COMMENT("End a bit-image region")},
+ {"Yz", 376 UNTIC_COMMENT("Change to ribbon color #1")},
+ {"ZA", 304 UNTIC_COMMENT("Change number of characters per inch")},
+ {"ZB", 305 UNTIC_COMMENT("Change number of lines per inch")},
+ {"ZC", 306 UNTIC_COMMENT("Change horizontal resolution")},
+ {"ZD", 307 UNTIC_COMMENT("Change vertical resolution")},
+ {"ZE", 308 UNTIC_COMMENT("Define a character")},
+ {"ZF", 309 UNTIC_COMMENT("Enter double-wide mode")},
+ {"ZG", 310 UNTIC_COMMENT("Enter draft-quality mode")},
+ {"ZH", 311 UNTIC_COMMENT("Enter italic mode")},
+ {"ZI", 312 UNTIC_COMMENT("Start leftward carriage motion")},
+ {"ZJ", 313 UNTIC_COMMENT("Start micro-motion mode")},
+ {"ZK", 314 UNTIC_COMMENT("Enter NLQ mode")},
+ {"ZL", 315 UNTIC_COMMENT("Wnter normal-quality mode")},
+ {"ZM", 316 UNTIC_COMMENT("Enter shadow-print mode")},
+ {"ZN", 317 UNTIC_COMMENT("Enter subscript mode")},
+ {"ZO", 318 UNTIC_COMMENT("Enter superscript mode")},
+ {"ZP", 319 UNTIC_COMMENT("Start upward carriage motion")},
+ {"ZQ", 320 UNTIC_COMMENT("End double-wide mode")},
+ {"ZR", 321 UNTIC_COMMENT("End italic mode")},
+ {"ZS", 322 UNTIC_COMMENT("End left-motion mode")},
+ {"ZT", 323 UNTIC_COMMENT("End micro-motion mode")},
+ {"ZU", 324 UNTIC_COMMENT("End shadow-print mode")},
+ {"ZV", 325 UNTIC_COMMENT("End subscript mode")},
+ {"ZW", 326 UNTIC_COMMENT("End superscript mode")},
+ {"ZX", 327 UNTIC_COMMENT("End reverse character motion")},
+ {"ZY", 328 UNTIC_COMMENT("Like column_address in micro mode")},
+ {"ZZ", 329 UNTIC_COMMENT("Like cursor_down in micro mode")},
+ {"Za", 330 UNTIC_COMMENT("Like cursor_left in micro mode")},
+ {"Zb", 331 UNTIC_COMMENT("Like cursor_right in micro mode")},
+ {"Zc", 332 UNTIC_COMMENT("Like row_address in micro mode")},
+ {"Zd", 333 UNTIC_COMMENT("Like cursor_up in micro mode")},
+ {"Ze", 334 UNTIC_COMMENT("Match software bits to print-head pins")},
+ {"Zf", 335 UNTIC_COMMENT("Like parm_down_cursor in micro mode")},
+ {"Zg", 336 UNTIC_COMMENT("Like parm_left_cursor in micro mode")},
+ {"Zh", 337 UNTIC_COMMENT("Like parm_right_cursor in micro mode")},
+ {"Zi", 338 UNTIC_COMMENT("Like parm_up_cursor in micro mode")},
+ {"Zj", 339 UNTIC_COMMENT("Select character set")},
+ {"Zk", 340 UNTIC_COMMENT("Set bottom margin at current line")},
+ {"Zl", 341 UNTIC_COMMENT("Set bottom margin at line #1 or #2 lines from bottom")},
+ {"Zm", 342 UNTIC_COMMENT("Set left (right) margin at column #1 (#2)")},
+ {"Zn", 343 UNTIC_COMMENT("Set right margin at column #1")},
+ {"Zo", 344 UNTIC_COMMENT("Set top margin at current line")},
+ {"Zp", 345 UNTIC_COMMENT("Set top (bottom) margin at row #1 (#2)")},
+ {"Zq", 346 UNTIC_COMMENT("Start printing bit image braphics")},
+ {"Zr", 347 UNTIC_COMMENT("Start character set definition")},
+ {"Zs", 348 UNTIC_COMMENT("Stop printing bit image graphics")},
+ {"Zt", 349 UNTIC_COMMENT("End definition of character aet")},
+ {"Zu", 350 UNTIC_COMMENT("List of subscriptable characters")},
+ {"Zv", 351 UNTIC_COMMENT("List of superscriptable characters")},
+ {"Zw", 352 UNTIC_COMMENT("Printing any of these chars causes CR")},
+ {"Zx", 353 UNTIC_COMMENT("No motion for subsequent character")},
+ {"Zy", 354 UNTIC_COMMENT("List of character set names")},
+ {"Zz", 371 UNTIC_COMMENT("Move to next row of the bit image")},
+ {"ac", 146 UNTIC_COMMENT("acs_chars")},
+ {"ae", 38 UNTIC_COMMENT("exit_alt_charset_mode")},
+ {"al", 53 UNTIC_COMMENT("insert line")},
+ {"as", 25 UNTIC_COMMENT("enter_alt_charset_mode")},
+ {"bc", 395 UNTIC_COMMENT("move left, if not ^H")},
+ {"bl", 1 UNTIC_COMMENT("audible signal (bell)")},
+ {"bt", 0 UNTIC_COMMENT("back tab")},
+ {"bx", 411 UNTIC_COMMENT("box chars primary set")},
+ {"cb", 269 UNTIC_COMMENT("Clear to beginning of line")},
+ {"cd", 7 UNTIC_COMMENT("clear to end of screen")},
+ {"ce", 6 UNTIC_COMMENT("clr_eol")},
+ {"ch", 8 UNTIC_COMMENT("horizontal position #1, absolute")},
+ {"ci", 363 UNTIC_COMMENT("Init sequence for multiple codesets")},
+ {"cl", 5 UNTIC_COMMENT("clear screen and home cursor")},
+ {"cm", 10 UNTIC_COMMENT("move to row #1 columns #2")},
+ {"cr", 2 UNTIC_COMMENT("carriage return")},
+ {"cs", 3 UNTIC_COMMENT("change region to line #1 to line #2")},
+ {"ct", 4 UNTIC_COMMENT("clear all tab stops")},
+ {"cv", 127 UNTIC_COMMENT("vertical position #1 absolute")},
+ {"dc", 21 UNTIC_COMMENT("delete character")},
+ {"dl", 22 UNTIC_COMMENT("delete line")},
+ {"dm", 29 UNTIC_COMMENT("enter delete mode")},
+ {"do", 11 UNTIC_COMMENT("down one line")},
+ {"ds", 23 UNTIC_COMMENT("disable status line")},
+ {"dv", 362 UNTIC_COMMENT("Indicate language/codeset support")},
+ {"eA", 155 UNTIC_COMMENT("enable alternate char set")},
+ {"ec", 37 UNTIC_COMMENT("erase #1 characters")},
+ {"ed", 41 UNTIC_COMMENT("end delete mode")},
+ {"ei", 42 UNTIC_COMMENT("exit insert mode")},
+ {"ff", 46 UNTIC_COMMENT("hardcopy terminal page eject")},
+ {"fh", 284 UNTIC_COMMENT("flash switch hook")},
+ {"fs", 47 UNTIC_COMMENT("return from status line")},
+ {"hd", 24 UNTIC_COMMENT("half a line down")},
+ {"ho", 12 UNTIC_COMMENT("home cursor (if no cup)")},
+ {"hu", 137 UNTIC_COMMENT("half a line up")},
+ {"i1", 48 UNTIC_COMMENT("initialization string")},
+ {"i2", 392 UNTIC_COMMENT("secondary initialization string")},
+ {"i3", 50 UNTIC_COMMENT("initialization string")},
+ {"iP", 138 UNTIC_COMMENT("path name of program for initialization")},
+ {"ic", 52 UNTIC_COMMENT("insert character")},
+ {"if", 51 UNTIC_COMMENT("name of initialization file")},
+ {"im", 31 UNTIC_COMMENT("enter insert mode")},
+ {"ip", 54 UNTIC_COMMENT("insert padding after inserted character")},
+ {"is", 49 UNTIC_COMMENT("initialization string")},
+ {"k0", 65 UNTIC_COMMENT("F0 function key")},
+ {"k1", 66 UNTIC_COMMENT("F1 function key")},
+ {"k2", 68 UNTIC_COMMENT("F2 function key")},
+ {"k3", 69 UNTIC_COMMENT("F3 function key")},
+ {"k4", 70 UNTIC_COMMENT("F4 function key")},
+ {"k5", 71 UNTIC_COMMENT("F5 function key")},
+ {"k6", 72 UNTIC_COMMENT("F6 function key")},
+ {"k7", 73 UNTIC_COMMENT("F7 function key")},
+ {"k8", 74 UNTIC_COMMENT("F8 fucntion key")},
+ {"k9", 75 UNTIC_COMMENT("F9 function key")},
+ {"k;", 67 UNTIC_COMMENT("F10 function key")},
+ {"kA", 78 UNTIC_COMMENT("insert-line key")},
+ {"kB", 148 UNTIC_COMMENT("back-tab key")},
+ {"kC", 57 UNTIC_COMMENT("clear-screen or erase key")},
+ {"kD", 59 UNTIC_COMMENT("delete-character key")},
+ {"kE", 63 UNTIC_COMMENT("clear-to-end-of-line key")},
+ {"kF", 84 UNTIC_COMMENT("scroll-forward key")},
+ {"kH", 80 UNTIC_COMMENT("last-line key")},
+ {"kI", 77 UNTIC_COMMENT("insert-character key")},
+ {"kL", 60 UNTIC_COMMENT("delete-line key")},
+ {"kM", 62 UNTIC_COMMENT("sent by rmir or smir in insert mode")},
+ {"kN", 81 UNTIC_COMMENT("next-page key")},
+ {"kP", 82 UNTIC_COMMENT("prev-page key")},
+ {"kR", 85 UNTIC_COMMENT("scroll-backward key")},
+ {"kS", 64 UNTIC_COMMENT("clear-to-end-of-screen key")},
+ {"kT", 86 UNTIC_COMMENT("set-tab key")},
+ {"ka", 56 UNTIC_COMMENT("clear-all-tabs key")},
+ {"kb", 55 UNTIC_COMMENT("backspace key")},
+ {"kd", 61 UNTIC_COMMENT("down-arrow key")},
+ {"ke", 88 UNTIC_COMMENT("leave 'keyboard_transmit' mode")},
+ {"kh", 76 UNTIC_COMMENT("home key")},
+ {"kl", 79 UNTIC_COMMENT("left-arrow key")},
+ {"ko", 396 UNTIC_COMMENT("list of self-mapped keycaps")},
+ {"kr", 83 UNTIC_COMMENT("right-arrow key")},
+ {"ks", 89 UNTIC_COMMENT("enter 'keyboard_transmit' mode")},
+ {"kt", 58 UNTIC_COMMENT("clear-tab key")},
+ {"ku", 87 UNTIC_COMMENT("up-arrow key")},
+ {"l0", 90 UNTIC_COMMENT("label on function key f0 if not f0")},
+ {"l1", 91 UNTIC_COMMENT("label on function key f1 if not f1")},
+ {"l2", 93 UNTIC_COMMENT("label on function key f2 if not f2")},
+ {"l3", 94 UNTIC_COMMENT("label on function key f3 if not f3")},
+ {"l4", 95 UNTIC_COMMENT("label on function key f4 if not f4")},
+ {"l5", 96 UNTIC_COMMENT("lable on function key f5 if not f5")},
+ {"l6", 97 UNTIC_COMMENT("label on function key f6 if not f6")},
+ {"l7", 98 UNTIC_COMMENT("label on function key f7 if not f7")},
+ {"l8", 99 UNTIC_COMMENT("label on function key f8 if not f8")},
+ {"l9", 100 UNTIC_COMMENT("label on function key f9 if not f9")},
+ {"la", 92 UNTIC_COMMENT("label on function key f10 if not f10")},
+ {"le", 14 UNTIC_COMMENT("move left one space")},
+ {"ll", 18 UNTIC_COMMENT("last line, first column (if no cup)")},
+ {"ma", 397 UNTIC_COMMENT("map arrow keys rogue(1) motion keys")},
+ {"mb", 26 UNTIC_COMMENT("turn on blinking")},
+ {"md", 27 UNTIC_COMMENT("turn on bold (extra bright) mode")},
+ {"me", 39 UNTIC_COMMENT("turn off all attributes")},
+ {"mh", 30 UNTIC_COMMENT("turn on half-bright mode")},
+ {"mk", 32 UNTIC_COMMENT("turn on blank mode (characters invisible)")},
+ {"ml", 409 UNTIC_COMMENT("memory lock above")},
+ {"mm", 102 UNTIC_COMMENT("turn on meta mode (8th-bit on)")},
+ {"mo", 101 UNTIC_COMMENT("turn off meta mode")},
+ {"mp", 33 UNTIC_COMMENT("turn on protected mode")},
+ {"mr", 34 UNTIC_COMMENT("turn on reverse video mode")},
+ {"mu", 410 UNTIC_COMMENT("memory unlock")},
+ {"nd", 17 UNTIC_COMMENT("move right one space")},
+ {"nl", 394 UNTIC_COMMENT("use to move down")},
+ {"nw", 103 UNTIC_COMMENT("newline (behave like cr followed by lf)")},
+ {"oc", 298 UNTIC_COMMENT("Set all color pairs to the original ones")},
+ {"op", 297 UNTIC_COMMENT("Set default pair to its original value")},
+ {"pO", 144 UNTIC_COMMENT("turn on printer for #1 bytes")},
+ {"pc", 104 UNTIC_COMMENT("padding char (instead of null)")},
+ {"pf", 119 UNTIC_COMMENT("turn off printer")},
+ {"pk", 115 UNTIC_COMMENT("program function key #1 to type string #2")},
+ {"pl", 116 UNTIC_COMMENT("program function key #1 to execute string #2")},
+ {"pn", 147 UNTIC_COMMENT("program label #1 to show string #2")},
+ {"po", 120 UNTIC_COMMENT("turn on printer")},
+ {"ps", 118 UNTIC_COMMENT("print contents of screen")},
+ {"px", 117 UNTIC_COMMENT("program function key #1 to transmit string #2")},
+ {"r1", 122 UNTIC_COMMENT("reset string")},
+ {"r2", 123 UNTIC_COMMENT("reset string")},
+ {"r3", 124 UNTIC_COMMENT("reset string")},
+ {"rP", 145 UNTIC_COMMENT("like ip but when in insert mode")},
+ {"rc", 126 UNTIC_COMMENT("restore cursor to last position of sc")},
+ {"rf", 125 UNTIC_COMMENT("name of reset file")},
+ {"rp", 121 UNTIC_COMMENT("repeat char #1 #2 times")},
+ {"rs", 393 UNTIC_COMMENT("terminal reset string")},
+ {"s0", 364 UNTIC_COMMENT("Shift to code set 0 (EUC set 0, ASCII)")},
+ {"s1", 365 UNTIC_COMMENT("Shift to code set 1")},
+ {"s2", 366 UNTIC_COMMENT("Shift to code set 2")},
+ {"s3", 367 UNTIC_COMMENT("Shift to code set 3")},
+ {"sa", 131 UNTIC_COMMENT("define video attributes #1-#9 (PG9)")},
+ {"sc", 128 UNTIC_COMMENT("save current cursor position")},
+ {"se", 43 UNTIC_COMMENT("exit standout mode")},
+ {"sf", 129 UNTIC_COMMENT("scroll text up")},
+ {"so", 35 UNTIC_COMMENT("begin standout mode")},
+ {"sp", 301 UNTIC_COMMENT("Set current color pair to #1")},
+ {"sr", 130 UNTIC_COMMENT("scroll text down")},
+ {"st", 132 UNTIC_COMMENT("set a tab in every row, current columns")},
+ {"ta", 134 UNTIC_COMMENT("tab to next 8-space hardware tab stop")},
+ {"te", 40 UNTIC_COMMENT("strings to end programs using cup")},
+ {"ti", 28 UNTIC_COMMENT("string to start programs using cup")},
+ {"ts", 135 UNTIC_COMMENT("move to status line")},
+ {"u0", 287 UNTIC_COMMENT("User string #0")},
+ {"u1", 288 UNTIC_COMMENT("User string #1")},
+ {"u2", 289 UNTIC_COMMENT("User string #2")},
+ {"u3", 290 UNTIC_COMMENT("User string #3")},
+ {"u4", 291 UNTIC_COMMENT("User string #4")},
+ {"u5", 292 UNTIC_COMMENT("User string #5")},
+ {"u6", 293 UNTIC_COMMENT("User string #6")},
+ {"u7", 294 UNTIC_COMMENT("User string #7")},
+ {"u8", 295 UNTIC_COMMENT("User string #8")},
+ {"u9", 296 UNTIC_COMMENT("User string #9")},
+ {"uc", 136 UNTIC_COMMENT("underline char and move past it")},
+ {"ue", 44 UNTIC_COMMENT("exit underline mode")},
+ {"up", 19 UNTIC_COMMENT("up one line")},
+ {"us", 36 UNTIC_COMMENT("begin underline mode")},
+ {"vb", 45 UNTIC_COMMENT("visible bell (may not move cursor)")},
+ {"ve", 16 UNTIC_COMMENT("make cursor appear normal (undo civis/cvvis)")},
+ {"vi", 13 UNTIC_COMMENT("make cursor invisible")},
+ {"vs", 20 UNTIC_COMMENT("make cursor very visible")},
+ {"wi", 133 UNTIC_COMMENT("current window is lines #1-#2 cols #3-#4")},
+ {"xl", 361 UNTIC_COMMENT("Program function key #1 to type string #2 and show string #3")},
+ {"", -1 UNTIC_COMMENT(NULL)}
+};
+
+static int compute_cap_offset (char *cap, SLterminfo_Type *t, Tgetstr_Map_Type *map, unsigned int max_ofs)
+{
+ char cha, chb;
+
+ (void) t;
+ cha = *cap++; chb = *cap;
+
+ while (*map->name != 0)
+ {
+ if ((cha == *map->name) && (chb == *(map->name + 1)))
+ {
+ if (map->offset >= (int) max_ofs) return -1;
+ return map->offset;
+ }
+ map++;
+ }
+ return -1;
+}
+
+char *_SLtt_tigetstr (SLterminfo_Type *t, char *cap)
+{
+ int offset;
+
+ if (t == NULL)
+ return NULL;
+
+ if (t->flags == SLTERMCAP) return tcap_getstr (cap, t);
+
+ offset = compute_cap_offset (cap, t, Tgetstr_Map, t->num_string_offsets);
+ if (offset < 0) return NULL;
+ offset = make_integer (t->string_offsets + 2 * offset);
+ if (offset < 0) return NULL;
+ return t->string_table + offset;
+}
+
+static Tgetstr_Map_Type Tgetnum_Map[] =
+{
+ {"BT", 30 UNTIC_COMMENT("number of buttons on mouse")},
+ {"Co", 13 UNTIC_COMMENT("maximum numbers of colors on screen")},
+ {"MW", 12 UNTIC_COMMENT("maxumum number of defineable windows")},
+ {"NC", 15 UNTIC_COMMENT("video attributes that can't be used with colors")},
+ {"Nl", 8 UNTIC_COMMENT("number of labels on screen")},
+ {"Ya", 16 UNTIC_COMMENT("numbers of bytes buffered before printing")},
+ {"Yb", 17 UNTIC_COMMENT("spacing of pins vertically in pins per inch")},
+ {"Yc", 18 UNTIC_COMMENT("spacing of dots horizontally in dots per inch")},
+ {"Yd", 19 UNTIC_COMMENT("maximum value in micro_..._address")},
+ {"Ye", 20 UNTIC_COMMENT("maximum value in parm_..._micro")},
+ {"Yf", 21 UNTIC_COMMENT("character size when in micro mode")},
+ {"Yg", 22 UNTIC_COMMENT("line size when in micro mode")},
+ {"Yh", 23 UNTIC_COMMENT("numbers of pins in print-head")},
+ {"Yi", 24 UNTIC_COMMENT("horizontal resolution in units per line")},
+ {"Yj", 25 UNTIC_COMMENT("vertical resolution in units per line")},
+ {"Yk", 26 UNTIC_COMMENT("horizontal resolution in units per inch")},
+ {"Yl", 27 UNTIC_COMMENT("vertical resolution in units per inch")},
+ {"Ym", 28 UNTIC_COMMENT("print rate in chars per second")},
+ {"Yn", 29 UNTIC_COMMENT("character step size when in double wide mode")},
+ {"Yo", 31 UNTIC_COMMENT("number of passed for each bit-image row")},
+ {"Yp", 32 UNTIC_COMMENT("type of bit-image device")},
+ {"co", 0 UNTIC_COMMENT("number of columns in aline")},
+ {"dB", 36 UNTIC_COMMENT("padding required for ^H")},
+ {"dC", 34 UNTIC_COMMENT("pad needed for CR")},
+ {"dN", 35 UNTIC_COMMENT("pad needed for LF")},
+ {"dT", 37 UNTIC_COMMENT("padding required for ^I")},
+ {"it", 1 UNTIC_COMMENT("tabs initially every # spaces")},
+ {"kn", 38 UNTIC_COMMENT("count of function keys")},
+ {"lh", 9 UNTIC_COMMENT("rows in each label")},
+ {"li", 2 UNTIC_COMMENT("number of lines on screen or page")},
+ {"lm", 3 UNTIC_COMMENT("lines of memory if > line. 0 => varies")},
+ {"lw", 10 UNTIC_COMMENT("columns in each label")},
+ {"ma", 11 UNTIC_COMMENT("maximum combined attributes terminal can handle")},
+ {"pa", 14 UNTIC_COMMENT("maximum number of color-pairs on the screen")},
+ {"pb", 5 UNTIC_COMMENT("lowest baud rate where padding needed")},
+ {"sg", 4 UNTIC_COMMENT("number of blank chars left by smso or rmso")},
+ {"ug", 33 UNTIC_COMMENT("number of blanks left by ul")},
+ {"vt", 6 UNTIC_COMMENT("virtual terminal number (CB/unix)")},
+ {"ws", 7 UNTIC_COMMENT("columns in status line")},
+ {"", -1 UNTIC_COMMENT(NULL)}
+};
+
+int _SLtt_tigetnum (SLterminfo_Type *t, char *cap)
+{
+ int offset;
+
+ if (t == NULL)
+ return -1;
+
+ if (t->flags == SLTERMCAP) return tcap_getnum (cap, t);
+
+ offset = compute_cap_offset (cap, t, Tgetnum_Map, t->num_numbers);
+ if (offset < 0) return -1;
+ return make_integer (t->numbers + 2 * offset);
+}
+
+static Tgetstr_Map_Type Tgetflag_Map[] =
+{
+ {"5i", 22 UNTIC_COMMENT("printer won't echo on screen")},
+ {"HC", 23 UNTIC_COMMENT("cursor is hard to see")},
+ {"MT", 40 UNTIC_COMMENT("has meta key")},
+ {"ND", 26 UNTIC_COMMENT("scrolling region is non-destructive")},
+ {"NL", 41 UNTIC_COMMENT("move down with \n")},
+ {"NP", 25 UNTIC_COMMENT("pad character does not exist")},
+ {"NR", 24 UNTIC_COMMENT("smcup does not reverse rmcup")},
+ {"YA", 30 UNTIC_COMMENT("only positive motion for hpa/mhpa caps")},
+ {"YB", 31 UNTIC_COMMENT("using cr turns off micro mode")},
+ {"YC", 32 UNTIC_COMMENT("printer needs operator to change character set")},
+ {"YD", 33 UNTIC_COMMENT("only positive motion for vpa/mvpa caps")},
+ {"YE", 34 UNTIC_COMMENT("printing in last column causes cr")},
+ {"YF", 35 UNTIC_COMMENT("changing character pitch changes resolution")},
+ {"YG", 36 UNTIC_COMMENT("changing line pitch changes resolution")},
+ {"am", 1 UNTIC_COMMENT("terminal has automatic margins")},
+ {"bs", 37 UNTIC_COMMENT("uses ^H to move left")},
+ {"bw", 0 UNTIC_COMMENT("cub1 wraps from column 0 to last column")},
+ {"cc", 27 UNTIC_COMMENT("terminal can re-define existing colors")},
+ {"da", 11 UNTIC_COMMENT("display may be retained above the screen")},
+ {"db", 12 UNTIC_COMMENT("display may be retained below the screen")},
+ {"eo", 5 UNTIC_COMMENT("can erase overstrikes with a blank")},
+ {"es", 16 UNTIC_COMMENT("escape can be used on the status line")},
+ {"gn", 6 UNTIC_COMMENT("generic line type")},
+ {"hc", 7 UNTIC_COMMENT("hardcopy terminal")},
+ {"hl", 29 UNTIC_COMMENT("terminal uses only HLS color notation (tektronix)")},
+ {"hs", 9 UNTIC_COMMENT("has extra status line")},
+ {"hz", 18 UNTIC_COMMENT("can't print ~'s (hazeltine)")},
+ {"in", 10 UNTIC_COMMENT("insert mode distinguishes nulls")},
+ {"km", 8 UNTIC_COMMENT("Has a meta key, sets msb high")},
+ {"mi", 13 UNTIC_COMMENT("safe to move while in insert mode")},
+ {"ms", 14 UNTIC_COMMENT("safe to move while in standout mode")},
+ {"nc", 39 UNTIC_COMMENT("no way to go to start of line")},
+ {"ns", 38 UNTIC_COMMENT("crt cannot scroll")},
+ {"nx", 21 UNTIC_COMMENT("padding won't work, xon/xoff required")},
+ {"os", 15 UNTIC_COMMENT("terminal can overstrike")},
+ {"pt", 42 UNTIC_COMMENT("has 8-char tabs invoked with ^I")},
+ {"ul", 19 UNTIC_COMMENT("underline character overstrikes")},
+ {"ut", 28 UNTIC_COMMENT("screen erased with background color")},
+ {"xb", 2 UNTIC_COMMENT("beehive (f1=escape, f2=ctrl C)")},
+ {"xn", 4 UNTIC_COMMENT("newline ignored after 80 cols (concept)")},
+ {"xo", 20 UNTIC_COMMENT("terminal uses xon/xoff handshaking")},
+ {"xr", 43 UNTIC_COMMENT("return clears the line")},
+ {"xs", 3 UNTIC_COMMENT("standout not erased by overwriting (hp)")},
+ {"xt", 17 UNTIC_COMMENT("tabs destructive, magic so char (t1061)")},
+ {"", -1 UNTIC_COMMENT(NULL)}
+};
+
+int _SLtt_tigetflag (SLterminfo_Type *t, char *cap)
+{
+ int offset;
+
+ if (t == NULL) return -1;
+
+ if (t->flags == SLTERMCAP) return tcap_getflag (cap, t);
+
+ offset = compute_cap_offset (cap, t, Tgetflag_Map, t->boolean_section_size);
+
+ if (offset < 0) return -1;
+ return (int) *(t->boolean_flags + offset);
+}
+
+/* These are my termcap routines. They only work with the TERMCAP environment
+ * variable. This variable must contain the termcap entry and NOT the file.
+ */
+
+static int tcap_getflag (char *cap, SLterminfo_Type *t)
+{
+ char a, b;
+ char *f = (char *) t->boolean_flags;
+ char *fmax;
+
+ if (f == NULL) return 0;
+ fmax = f + t->boolean_section_size;
+
+ a = *cap;
+ b = *(cap + 1);
+ while (f < fmax)
+ {
+ if ((a == f[0]) && (b == f[1]))
+ return 1;
+ f += 2;
+ }
+ return 0;
+}
+
+static char *tcap_get_cap (unsigned char *cap, unsigned char *caps, unsigned int len)
+{
+ unsigned char c0, c1;
+ unsigned char *caps_max;
+
+ c0 = cap[0];
+ c1 = cap[1];
+
+ if (caps == NULL) return NULL;
+ caps_max = caps + len;
+ while (caps < caps_max)
+ {
+ if ((c0 == caps[0]) && (c1 == caps[1]))
+ {
+ return (char *) caps + 3;
+ }
+ caps += (int) caps[2];
+ }
+ return NULL;
+}
+
+static int tcap_getnum (char *cap, SLterminfo_Type *t)
+{
+ cap = tcap_get_cap ((unsigned char *) cap, t->numbers, t->num_numbers);
+ if (cap == NULL) return -1;
+ return atoi (cap);
+}
+
+static char *tcap_getstr (char *cap, SLterminfo_Type *t)
+{
+ return tcap_get_cap ((unsigned char *) cap, (unsigned char *) t->string_table, t->string_table_size);
+}
+
+static int tcap_extract_field (unsigned char *t0)
+{
+ register unsigned char ch, *t = t0;
+ while (((ch = *t) != 0) && (ch != ':')) t++;
+ if (ch == ':') return (int) (t - t0);
+ return -1;
+}
+
+int SLtt_Try_Termcap = 1;
+static int tcap_getent (char *term, SLterminfo_Type *ti)
+{
+ unsigned char *termcap, ch;
+ unsigned char *buf, *b;
+ unsigned char *t;
+ int len;
+
+ if (SLtt_Try_Termcap == 0) return -1;
+#if 1
+ /* XFREE86 xterm sets the TERMCAP environment variable to an invalid
+ * value. Specifically, it lacks the tc= string.
+ */
+ if (!strncmp (term, "xterm", 5))
+ return -1;
+#endif
+ termcap = (unsigned char *) getenv ("TERMCAP");
+ if ((termcap == NULL) || (*termcap == '/')) return -1;
+
+ /* We have a termcap so lets use it provided it does not have a reference
+ * to another terminal via tc=. In that case, use terminfo. The alternative
+ * would be to parse the termcap file which I do not want to do right now.
+ * Besides, this is a terminfo based system and if the termcap were parsed
+ * terminfo would almost never get a chance to run. In addition, the tc=
+ * thing should not occur if tset is used to set the termcap entry.
+ */
+ t = termcap;
+ while ((len = tcap_extract_field (t)) != -1)
+ {
+ if ((len > 3) && (t[0] == 't') && (t[1] == 'c') && (t[2] == '='))
+ return -1;
+ t += (len + 1);
+ }
+
+ /* malloc some extra space just in case it is needed. */
+ len = strlen ((char *) termcap) + 256;
+ if (NULL == (buf = (unsigned char *) SLmalloc ((unsigned int) len))) return -1;
+
+ b = buf;
+
+ /* The beginning of the termcap entry contains the names of the entry.
+ * It is terminated by a colon.
+ */
+
+ ti->terminal_names = (char *) b;
+ t = termcap;
+ len = tcap_extract_field (t);
+ if (len < 0)
+ {
+ SLfree ((char *)buf);
+ return -1;
+ }
+ strncpy ((char *) b, (char *) t, (unsigned int) len);
+ b[len] = 0;
+ b += len + 1;
+ ti->name_section_size = len;
+
+ /* Now, we are really at the start of the termcap entries. Point the
+ * termcap variable here since we want to refer to this a number of times.
+ */
+ termcap = t + (len + 1);
+
+ /* Process strings first. */
+ ti->string_table = (char *) b;
+ t = termcap;
+ while (-1 != (len = tcap_extract_field (t)))
+ {
+ unsigned char *b1;
+ unsigned char *tmax;
+
+ /* We are looking for: XX=something */
+ if ((len < 4) || (t[2] != '=') || (*t == '.'))
+ {
+ t += len + 1;
+ continue;
+ }
+ tmax = t + len;
+ b1 = b;
+
+ while (t < tmax)
+ {
+ ch = *t++;
+ if ((ch == '\\') && (t < tmax))
+ {
+ t = (unsigned char *) _SLexpand_escaped_char ((char *) t, (char *) &ch);
+ }
+ else if ((ch == '^') && (t < tmax))
+ {
+ ch = *t++;
+ if (ch == '?') ch = 127;
+ else ch = (ch | 0x20) - ('a' - 1);
+ }
+ *b++ = ch;
+ }
+ /* Null terminate it. */
+ *b++ = 0;
+ len = (int) (b - b1);
+ b1[2] = (unsigned char) len; /* replace the = by the length */
+ /* skip colon to next field. */
+ t++;
+ }
+ ti->string_table_size = (int) (b - (unsigned char *) ti->string_table);
+
+ /* Now process the numbers. */
+
+ t = termcap;
+ ti->numbers = b;
+ while (-1 != (len = tcap_extract_field (t)))
+ {
+ unsigned char *b1;
+ unsigned char *tmax;
+
+ /* We are looking for: XX#NUMBER */
+ if ((len < 4) || (t[2] != '#') || (*t == '.'))
+ {
+ t += len + 1;
+ continue;
+ }
+ tmax = t + len;
+ b1 = b;
+
+ while (t < tmax)
+ {
+ *b++ = *t++;
+ }
+ /* Null terminate it. */
+ *b++ = 0;
+ len = (int) (b - b1);
+ b1[2] = (unsigned char) len; /* replace the # by the length */
+ t++;
+ }
+ ti->num_numbers = (int) (b - ti->numbers);
+
+ /* Now process the flags. */
+ t = termcap;
+ ti->boolean_flags = b;
+ while (-1 != (len = tcap_extract_field (t)))
+ {
+ /* We are looking for: XX#NUMBER */
+ if ((len != 2) || (*t == '.') || (*t <= ' '))
+ {
+ t += len + 1;
+ continue;
+ }
+ b[0] = t[0];
+ b[1] = t[1];
+ t += 3;
+ b += 2;
+ }
+ ti->boolean_section_size = (int) (b - ti->boolean_flags);
+ ti->flags = SLTERMCAP;
+ return 0;
+}
+
+
+/* These routines are provided only for backward binary compatability.
+ * They will vanish in V2.x
+ */
+char *SLtt_tigetent (char *s)
+{
+ return (char *) _SLtt_tigetent (s);
+}
+
+extern char *SLtt_tigetstr (char *s, char **p)
+{
+ if (p == NULL)
+ return NULL;
+ return _SLtt_tigetstr ((SLterminfo_Type *) *p, s);
+}
+
+extern int SLtt_tigetnum (char *s, char **p)
+{
+ if (p == NULL)
+ return -1;
+ return _SLtt_tigetnum ((SLterminfo_Type *) *p, s);
+}
+
+
diff --git a/mdk-stage1/slang/sltime.c b/mdk-stage1/slang/sltime.c
new file mode 100644
index 000000000..14fc6ec16
--- /dev/null
+++ b/mdk-stage1/slang/sltime.c
@@ -0,0 +1,310 @@
+/* time related system calls */
+/* Copyright (c) 1992, 1999, 2001 John E. Davis
+ * This file is part of the S-Lang library.
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Perl Artistic License.
+ */
+
+#include "slinclud.h"
+
+#include <sys/types.h>
+#include <time.h>
+
+#if defined(__BORLANDC__)
+# include <dos.h>
+#endif
+#if defined(__GO32__) || defined(__WATCOMC__)
+# include <dos.h>
+# include <bios.h>
+#endif
+
+#include <errno.h>
+
+#include "slang.h"
+#include "_slang.h"
+
+#ifdef __WIN32__
+#include <windows.h>
+/* Sleep is defined badly in MSVC... */
+# ifdef _MSC_VER
+# define sleep(n) _sleep((n)*1000)
+# else
+# ifdef sleep
+# undef sleep
+# endif
+# define sleep(x) if(x)Sleep((x)*1000)
+# endif
+#endif
+
+
+#if defined(IBMPC_SYSTEM)
+/* For other system (Unix and VMS), _SLusleep is in sldisply.c */
+int _SLusleep (unsigned long s)
+{
+ sleep (s/1000000L);
+ s = s % 1000000L;
+
+# if defined(__WIN32__)
+ Sleep (s/1000);
+#else
+# if defined(__IBMC__)
+ DosSleep(s/1000);
+# else
+# if defined(_MSC_VER)
+ _sleep (s/1000);
+# endif
+# endif
+#endif
+ return 0;
+}
+#endif
+
+#if defined(__IBMC__) && !defined(_AIX)
+/* sleep is not a standard function in VA3. */
+unsigned int sleep (unsigned int seconds)
+{
+ DosSleep(1000L * ((long)seconds));
+ return 0;
+}
+#endif
+
+static char *ctime_cmd (unsigned long *tt)
+{
+ char *t;
+
+ t = ctime ((time_t *) tt);
+ t[24] = 0; /* knock off \n */
+ return (t);
+}
+
+static void sleep_cmd (void)
+{
+ unsigned int secs;
+#if SLANG_HAS_FLOAT
+ unsigned long usecs;
+ double x;
+
+ if (-1 == SLang_pop_double (&x, NULL, NULL))
+ return;
+
+ if (x < 0.0)
+ x = 0.0;
+ secs = (unsigned int) x;
+ sleep (secs);
+ x -= (double) secs;
+ usecs = (unsigned long) (1e6 * x);
+ if (usecs > 0) _SLusleep (usecs);
+#else
+ if (-1 == SLang_pop_uinteger (&secs))
+ return;
+ if (secs != 0) sleep (secs);
+#endif
+}
+
+static unsigned long _time_cmd (void)
+{
+ return (unsigned long) time (NULL);
+}
+
+#if defined(__GO32__)
+static char *djgpp_current_time (void) /*{{{*/
+{
+ union REGS rg;
+ unsigned int year;
+ unsigned char month, day, weekday, hour, minute, sec;
+ char days[] = "SunMonTueWedThuFriSat";
+ char months[] = "JanFebMarAprMayJunJulAugSepOctNovDec";
+ static char the_date[26];
+
+ rg.h.ah = 0x2A;
+#ifndef __WATCOMC__
+ int86(0x21, &rg, &rg);
+ year = rg.x.cx & 0xFFFF;
+#else
+ int386(0x21, &rg, &rg);
+ year = rg.x.ecx & 0xFFFF;
+#endif
+
+ month = 3 * (rg.h.dh - 1);
+ day = rg.h.dl;
+ weekday = 3 * rg.h.al;
+
+ rg.h.ah = 0x2C;
+
+#ifndef __WATCOMC__
+ int86(0x21, &rg, &rg);
+#else
+ int386(0x21, &rg, &rg);
+#endif
+
+ hour = rg.h.ch;
+ minute = rg.h.cl;
+ sec = rg.h.dh;
+
+ /* we want this form: Thu Apr 14 15:43:39 1994\n */
+ sprintf(the_date, "%.3s %.3s%3d %02d:%02d:%02d %d\n",
+ days + weekday, months + month,
+ day, hour, minute, sec, year);
+ return the_date;
+}
+
+/*}}}*/
+
+#endif
+
+char *SLcurrent_time_string (void) /*{{{*/
+{
+ char *the_time;
+#ifndef __GO32__
+ time_t myclock;
+
+ myclock = time((time_t *) 0);
+ the_time = (char *) ctime(&myclock);
+#else
+ the_time = djgpp_current_time ();
+#endif
+ /* returns the form Sun Sep 16 01:03:52 1985\n\0 */
+ the_time[24] = '\0';
+ return(the_time);
+}
+
+/*}}}*/
+
+static int push_tm_struct (struct tm *tms)
+{
+ char *field_names [9];
+ unsigned char field_types[9];
+ VOID_STAR field_values [9];
+ int int_values [9];
+ unsigned int i;
+
+ if (tms == NULL)
+ return SLang_push_null ();
+
+ field_names [0] = "tm_sec"; int_values [0] = tms->tm_sec;
+ field_names [1] = "tm_min"; int_values [1] = tms->tm_min;
+ field_names [2] = "tm_hour"; int_values [2] = tms->tm_hour;
+ field_names [3] = "tm_mday"; int_values [3] = tms->tm_mday;
+ field_names [4] = "tm_mon"; int_values [4] = tms->tm_mon;
+ field_names [5] = "tm_year"; int_values [5] = tms->tm_year;
+ field_names [6] = "tm_wday"; int_values [6] = tms->tm_wday;
+ field_names [7] = "tm_yday"; int_values [7] = tms->tm_yday;
+ field_names [8] = "tm_isdst"; int_values [8] = tms->tm_isdst;
+
+ for (i = 0; i < 9; i++)
+ {
+ field_types [i] = SLANG_INT_TYPE;
+ field_values [i] = (VOID_STAR) (int_values + i);
+ }
+
+ return SLstruct_create_struct (9, field_names, field_types, field_values);
+}
+
+
+static void localtime_cmd (long *t)
+{
+ time_t tt = (time_t) *t;
+ (void) push_tm_struct (localtime (&tt));
+}
+
+static void gmtime_cmd (long *t)
+{
+#ifdef HAVE_GMTIME
+ time_t tt = (time_t) *t;
+ (void) push_tm_struct (gmtime (&tt));
+#else
+ localtime_cmd (t);
+#endif
+}
+
+#ifdef HAVE_TIMES
+
+# ifdef HAVE_SYS_TIMES_H
+# include <sys/times.h>
+# endif
+
+#include <limits.h>
+
+#ifdef CLK_TCK
+# define SECS_PER_TICK (1.0/(double)CLK_TCK)
+#else
+# ifdef CLOCKS_PER_SEC
+# define SECS_PER_TICK (1.0/(double)CLOCKS_PER_SEC)
+# else
+# define SECS_PER_TICK (1.0/60.0)
+# endif
+#endif
+
+static void times_cmd (void)
+{
+ double dvals[4];
+ struct tms t;
+ VOID_STAR field_values[4];
+ char *field_names[4];
+ unsigned int i;
+ unsigned char field_types[4];
+
+ (void) times (&t);
+
+ field_names[0] = "tms_utime"; dvals[0] = (double)t.tms_utime;
+ field_names[1] = "tms_stime"; dvals[1] = (double)t.tms_stime;
+ field_names[2] = "tms_cutime"; dvals[2] = (double)t.tms_cutime;
+ field_names[3] = "tms_cstime"; dvals[3] = (double)t.tms_cstime;
+
+ for (i = 0; i < 4; i++)
+ {
+ dvals[i] *= SECS_PER_TICK;
+ field_values[i] = (VOID_STAR) &dvals[i];
+ field_types[i] = SLANG_DOUBLE_TYPE;
+ }
+ (void) SLstruct_create_struct (4, field_names, field_types, field_values);
+}
+
+static struct tms Tic_TMS;
+
+static void tic_cmd (void)
+{
+ (void) times (&Tic_TMS);
+}
+
+static double toc_cmd (void)
+{
+ struct tms t;
+ double d;
+
+ (void) times (&t);
+ d = ((t.tms_utime - Tic_TMS.tms_utime)
+ + (t.tms_stime - Tic_TMS.tms_stime)) * SECS_PER_TICK;
+ Tic_TMS = t;
+ return d;
+}
+
+#endif /* HAVE_TIMES */
+
+
+static SLang_Intrin_Fun_Type Time_Funs_Table [] =
+{
+ MAKE_INTRINSIC_1("ctime", ctime_cmd, SLANG_STRING_TYPE, SLANG_ULONG_TYPE),
+ MAKE_INTRINSIC_0("sleep", sleep_cmd, SLANG_VOID_TYPE),
+ MAKE_INTRINSIC_0("_time", _time_cmd, SLANG_ULONG_TYPE),
+ MAKE_INTRINSIC_0("time", SLcurrent_time_string, SLANG_STRING_TYPE),
+ MAKE_INTRINSIC_1("localtime", localtime_cmd, SLANG_VOID_TYPE, SLANG_LONG_TYPE),
+ MAKE_INTRINSIC_1("gmtime", gmtime_cmd, SLANG_VOID_TYPE, SLANG_LONG_TYPE),
+
+#ifdef HAVE_TIMES
+ MAKE_INTRINSIC_0("times", times_cmd, SLANG_VOID_TYPE),
+ MAKE_INTRINSIC_0("tic", tic_cmd, SLANG_VOID_TYPE),
+ MAKE_INTRINSIC_0("toc", toc_cmd, SLANG_DOUBLE_TYPE),
+#endif
+ SLANG_END_INTRIN_FUN_TABLE
+};
+
+int _SLang_init_sltime (void)
+{
+#ifdef HAVE_TIMES
+ (void) tic_cmd ();
+#endif
+ return SLadd_intrin_fun_table (Time_Funs_Table, NULL);
+}
+
diff --git a/mdk-stage1/slang/sltoken.c b/mdk-stage1/slang/sltoken.c
new file mode 100644
index 000000000..c9852e68a
--- /dev/null
+++ b/mdk-stage1/slang/sltoken.c
@@ -0,0 +1,1702 @@
+/* Copyright (c) 1998, 1999, 2001 John E. Davis
+ * This file is part of the S-Lang library.
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Perl Artistic License.
+ */
+#include "slinclud.h"
+
+#include "slang.h"
+#include "_slang.h"
+
+#define MAX_TOKEN_LEN 254
+#define MAX_FILE_LINE_LEN 256
+
+static char Empty_Line[1] = {0};
+
+static int Default_Compile_Line_Num_Info;
+static char *Input_Line = Empty_Line;
+static char *Input_Line_Pointer;
+
+static SLPreprocess_Type *This_SLpp;
+
+static SLang_Load_Type *LLT;
+
+static char *map_token_to_string (_SLang_Token_Type *tok)
+{
+ char *s;
+ static char numbuf [32];
+ unsigned char type;
+ s = NULL;
+
+ if (tok != NULL) type = tok->type;
+ else type = 0;
+
+ switch (type)
+ {
+ case 0:
+ s = "??";
+ break;
+
+ case CHAR_TOKEN:
+ case SHORT_TOKEN:
+ case INT_TOKEN:
+ case LONG_TOKEN:
+ s = numbuf;
+ sprintf (s, "%ld", tok->v.long_val);
+ break;
+
+ case UCHAR_TOKEN:
+ case USHORT_TOKEN:
+ case UINT_TOKEN:
+ case ULONG_TOKEN:
+ s = numbuf;
+ sprintf (s, "%lu", (unsigned long)tok->v.long_val);
+ break;
+
+ case OBRACKET_TOKEN: s = "["; break;
+ case CBRACKET_TOKEN: s = "]"; break;
+ case OPAREN_TOKEN: s = "("; break;
+ case CPAREN_TOKEN: s = ")"; break;
+ case OBRACE_TOKEN: s = "{"; break;
+ case CBRACE_TOKEN: s = "}"; break;
+ case DEREF_TOKEN: s = "@"; break;
+ case POUND_TOKEN: s = "#"; break;
+ case COMMA_TOKEN: s = ","; break;
+ case SEMICOLON_TOKEN: s = ";"; break;
+ case COLON_TOKEN: s = ":"; break;
+
+#if SLANG_HAS_FLOAT
+ case FLOAT_TOKEN:
+ case DOUBLE_TOKEN:
+ case COMPLEX_TOKEN:
+#endif
+ case IDENT_TOKEN:
+ if ((tok->free_sval_flag == 0) || (tok->num_refs == 0))
+ break;
+ /* drop */
+ default:
+ s = tok->v.s_val;
+ break;
+ }
+
+ if (s == NULL)
+ {
+ s = numbuf;
+ sprintf (s, "(0x%02X)", type);
+ }
+
+ return s;
+}
+
+static char *make_line_file_error (char *buf, unsigned int buflen,
+ _SLang_Token_Type *tok, char *dsc, int line, char *file)
+{
+#if _SLANG_HAS_DEBUG_CODE
+ if (tok != NULL) line = tok->line_number;
+#endif
+ if (file == NULL) file = "??";
+
+ (void) _SLsnprintf (buf, buflen, "%s: found '%s', line %d, file: %s",
+ dsc, map_token_to_string (tok), line, file);
+
+ return buf;
+}
+
+void _SLparse_error(char *str, _SLang_Token_Type *tok, int flag)
+{
+ char buf [1024];
+
+ if (str == NULL)
+ str = "Parse Error";
+
+ make_line_file_error (buf, sizeof (buf), tok, str, LLT->line_num, (char *) LLT->name);
+
+ if ((flag == 0) && SLang_Error)
+ return;
+
+ SLang_verror (SL_SYNTAX_ERROR, "%s", buf);
+}
+
+static void do_line_file_error (int line, char *file)
+{
+ SLang_verror (SL_SYNTAX_ERROR,
+ "called from line %d, file: %s", line, file);
+}
+
+#define ALPHA_CHAR 1
+#define DIGIT_CHAR 2
+#define EXCL_CHAR 3
+#define SEP_CHAR 4
+#define OP_CHAR 5
+#define DOT_CHAR 6
+#define BOLDOT_CHAR 7
+#define DQUOTE_CHAR 8
+#define QUOTE_CHAR 9
+#define COMMENT_CHAR 10
+#define NL_CHAR 11
+#define BAD_CHAR 12
+#define WHITE_CHAR 13
+
+#define CHAR_EOF 255
+
+#define CHAR_CLASS(c) (Char_Type_Table[(c)][0])
+#define CHAR_DATA(c) (Char_Type_Table[(c)][1])
+
+/* In this table, if a single character can represent an operator, e.g.,
+ * '&' (BAND_TOKEN), then it must be placed before multiple-character
+ * operators that begin with the same character, e.g., "&=". See
+ * get_op_token to see how this is exploited.
+ *
+ * The third character null terminates the operator string. This is for
+ * the token structure.
+ */
+static char Operators [29][4] =
+{
+#define OFS_EXCL 0
+ {'!', '=', 0, NE_TOKEN},
+#define OFS_POUND 1
+ {'#', 0, 0, POUND_TOKEN},
+#define OFS_BAND 2
+ {'&', 0, 0, BAND_TOKEN},
+ {'&', '&', 0, EOF_TOKEN},
+ {'&', '=', 0, BANDEQS_TOKEN},
+#define OFS_STAR 5
+ {'*', 0, 0, TIMES_TOKEN},
+ {'*', '=', 0, TIMESEQS_TOKEN},
+#define OFS_PLUS 7
+ {'+', 0, 0, ADD_TOKEN},
+ {'+', '+', 0, PLUSPLUS_TOKEN},
+ {'+', '=', 0, PLUSEQS_TOKEN},
+#define OFS_MINUS 10
+ {'-', 0, 0, SUB_TOKEN},
+ {'-', '-', 0, MINUSMINUS_TOKEN},
+ {'-', '=', 0, MINUSEQS_TOKEN},
+ {'-', '>', 0, NAMESPACE_TOKEN},
+#define OFS_DIV 14
+ {'/', 0, 0, DIV_TOKEN},
+ {'/', '=', 0, DIVEQS_TOKEN},
+#define OFS_LT 16
+ {'<', 0, 0, LT_TOKEN},
+ {'<', '=', 0, LE_TOKEN},
+#define OFS_EQS 18
+ {'=', 0, 0, ASSIGN_TOKEN},
+ {'=', '=', 0, EQ_TOKEN},
+#define OFS_GT 20
+ {'>', 0, 0, GT_TOKEN},
+ {'>', '=', 0, GE_TOKEN},
+#define OFS_AT 22
+ {'@', 0, 0, DEREF_TOKEN},
+#define OFS_POW 23
+ {'^', 0, 0, POW_TOKEN},
+#define OFS_BOR 24
+ {'|', 0, 0, BOR_TOKEN},
+ {'|', '|', 0, EOF_TOKEN},
+ {'|', '=', 0, BOREQS_TOKEN},
+#define OFS_BNOT 27
+ {'~', 0, 0, BNOT_TOKEN},
+ { 0, 0, 0, EOF_TOKEN}
+};
+
+static unsigned char Char_Type_Table[256][2] =
+{
+ { NL_CHAR, 0 }, /* 0x0 */ { BAD_CHAR, 0 }, /* 0x1 */
+ { BAD_CHAR, 0 }, /* 0x2 */ { BAD_CHAR, 0 }, /* 0x3 */
+ { BAD_CHAR, 0 }, /* 0x4 */ { BAD_CHAR, 0 }, /* 0x5 */
+ { BAD_CHAR, 0 }, /* 0x6 */ { BAD_CHAR, 0 }, /* 0x7 */
+ { WHITE_CHAR, 0 }, /* 0x8 */ { WHITE_CHAR, 0 }, /* 0x9 */
+ { NL_CHAR, 0 }, /* \n */ { WHITE_CHAR, 0 }, /* 0xb */
+ { WHITE_CHAR, 0 }, /* 0xc */ { WHITE_CHAR, 0 }, /* \r */
+ { BAD_CHAR, 0 }, /* 0xe */ { BAD_CHAR, 0 }, /* 0xf */
+ { BAD_CHAR, 0 }, /* 0x10 */ { BAD_CHAR, 0 }, /* 0x11 */
+ { BAD_CHAR, 0 }, /* 0x12 */ { BAD_CHAR, 0 }, /* 0x13 */
+ { BAD_CHAR, 0 }, /* 0x14 */ { BAD_CHAR, 0 }, /* 0x15 */
+ { BAD_CHAR, 0 }, /* 0x16 */ { BAD_CHAR, 0 }, /* 0x17 */
+ { BAD_CHAR, 0 }, /* 0x18 */ { BAD_CHAR, 0 }, /* 0x19 */
+ { BAD_CHAR, 0 }, /* 0x1a */ { BAD_CHAR, 0 }, /* 0x1b */
+ { BAD_CHAR, 0 }, /* 0x1c */ { BAD_CHAR, 0 }, /* 0x1d */
+ { BAD_CHAR, 0 }, /* 0x1e */ { BAD_CHAR, 0 }, /* 0x1f */
+ { WHITE_CHAR, 0 }, /* 0x20 */ { EXCL_CHAR, OFS_EXCL }, /* ! */
+ { DQUOTE_CHAR, 0 }, /* " */ { OP_CHAR, OFS_POUND }, /* # */
+ { ALPHA_CHAR, 0 }, /* $ */ { NL_CHAR, 0 },/* % */
+ { OP_CHAR, OFS_BAND }, /* & */ { QUOTE_CHAR, 0 }, /* ' */
+ { SEP_CHAR, OPAREN_TOKEN }, /* ( */ { SEP_CHAR, CPAREN_TOKEN }, /* ) */
+ { OP_CHAR, OFS_STAR }, /* * */ { OP_CHAR, OFS_PLUS}, /* + */
+ { SEP_CHAR, COMMA_TOKEN }, /* , */ { OP_CHAR, OFS_MINUS }, /* - */
+ { DOT_CHAR, 0 }, /* . */ { OP_CHAR, OFS_DIV }, /* / */
+ { DIGIT_CHAR, 0 }, /* 0 */ { DIGIT_CHAR, 0 }, /* 1 */
+ { DIGIT_CHAR, 0 }, /* 2 */ { DIGIT_CHAR, 0 }, /* 3 */
+ { DIGIT_CHAR, 0 }, /* 4 */ { DIGIT_CHAR, 0 }, /* 5 */
+ { DIGIT_CHAR, 0 }, /* 6 */ { DIGIT_CHAR, 0 }, /* 7 */
+ { DIGIT_CHAR, 0 }, /* 8 */ { DIGIT_CHAR, 0 }, /* 9 */
+ { SEP_CHAR, COLON_TOKEN }, /* : */ { SEP_CHAR, SEMICOLON_TOKEN }, /* ; */
+ { OP_CHAR, OFS_LT }, /* < */ { OP_CHAR, OFS_EQS }, /* = */
+ { OP_CHAR, OFS_GT }, /* > */ { BAD_CHAR, 0 }, /* ? */
+ { OP_CHAR, OFS_AT}, /* @ */ { ALPHA_CHAR, 0 }, /* A */
+ { ALPHA_CHAR, 0 }, /* B */ { ALPHA_CHAR, 0 }, /* C */
+ { ALPHA_CHAR, 0 }, /* D */ { ALPHA_CHAR, 0 }, /* E */
+ { ALPHA_CHAR, 0 }, /* F */ { ALPHA_CHAR, 0 }, /* G */
+ { ALPHA_CHAR, 0 }, /* H */ { ALPHA_CHAR, 0 }, /* I */
+ { ALPHA_CHAR, 0 }, /* J */ { ALPHA_CHAR, 0 }, /* K */
+ { ALPHA_CHAR, 0 }, /* L */ { ALPHA_CHAR, 0 }, /* M */
+ { ALPHA_CHAR, 0 }, /* N */ { ALPHA_CHAR, 0 }, /* O */
+ { ALPHA_CHAR, 0 }, /* P */ { ALPHA_CHAR, 0 }, /* Q */
+ { ALPHA_CHAR, 0 }, /* R */ { ALPHA_CHAR, 0 }, /* S */
+ { ALPHA_CHAR, 0 }, /* T */ { ALPHA_CHAR, 0 }, /* U */
+ { ALPHA_CHAR, 0 }, /* V */ { ALPHA_CHAR, 0 }, /* W */
+ { ALPHA_CHAR, 0 }, /* X */ { ALPHA_CHAR, 0 }, /* Y */
+ { ALPHA_CHAR, 0 }, /* Z */ { SEP_CHAR, OBRACKET_TOKEN }, /* [ */
+ { BAD_CHAR, 0 }, /* \ */ { SEP_CHAR, CBRACKET_TOKEN }, /* ] */
+ { OP_CHAR, OFS_POW }, /* ^ */ { ALPHA_CHAR, 0 }, /* _ */
+ { BAD_CHAR, 0 }, /* ` */ { ALPHA_CHAR, 0 }, /* a */
+ { ALPHA_CHAR, 0 }, /* b */ { ALPHA_CHAR, 0 }, /* c */
+ { ALPHA_CHAR, 0 }, /* d */ { ALPHA_CHAR, 0 }, /* e */
+ { ALPHA_CHAR, 0 }, /* f */ { ALPHA_CHAR, 0 }, /* g */
+ { ALPHA_CHAR, 0 }, /* h */ { ALPHA_CHAR, 0 }, /* i */
+ { ALPHA_CHAR, 0 }, /* j */ { ALPHA_CHAR, 0 }, /* k */
+ { ALPHA_CHAR, 0 }, /* l */ { ALPHA_CHAR, 0 }, /* m */
+ { ALPHA_CHAR, 0 }, /* n */ { ALPHA_CHAR, 0 }, /* o */
+ { ALPHA_CHAR, 0 }, /* p */ { ALPHA_CHAR, 0 }, /* q */
+ { ALPHA_CHAR, 0 }, /* r */ { ALPHA_CHAR, 0 }, /* s */
+ { ALPHA_CHAR, 0 }, /* t */ { ALPHA_CHAR, 0 }, /* u */
+ { ALPHA_CHAR, 0 }, /* v */ { ALPHA_CHAR, 0 }, /* w */
+ { ALPHA_CHAR, 0 }, /* x */ { ALPHA_CHAR, 0 }, /* y */
+ { ALPHA_CHAR, 0 }, /* z */ { SEP_CHAR, OBRACE_TOKEN }, /* { */
+ { OP_CHAR, OFS_BOR }, /* | */ { SEP_CHAR, CBRACE_TOKEN }, /* } */
+ { OP_CHAR, OFS_BNOT }, /* ~ */ { BAD_CHAR, 0 }, /* 0x7f */
+
+ { ALPHA_CHAR, 0 }, /* € */ { ALPHA_CHAR, 0 }, /*  */
+ { ALPHA_CHAR, 0 }, /* ‚ */ { ALPHA_CHAR, 0 }, /* ƒ */
+ { ALPHA_CHAR, 0 }, /* „ */ { ALPHA_CHAR, 0 }, /* … */
+ { ALPHA_CHAR, 0 }, /* † */ { ALPHA_CHAR, 0 }, /* ‡ */
+ { ALPHA_CHAR, 0 }, /* ˆ */ { ALPHA_CHAR, 0 }, /* ‰ */
+ { ALPHA_CHAR, 0 }, /* Š */ { ALPHA_CHAR, 0 }, /* ‹ */
+ { ALPHA_CHAR, 0 }, /* Œ */ { ALPHA_CHAR, 0 }, /*  */
+ { ALPHA_CHAR, 0 }, /* Ž */ { ALPHA_CHAR, 0 }, /*  */
+ { ALPHA_CHAR, 0 }, /*  */ { ALPHA_CHAR, 0 }, /* ‘ */
+ { ALPHA_CHAR, 0 }, /* ’ */ { ALPHA_CHAR, 0 }, /* “ */
+ { ALPHA_CHAR, 0 }, /* ” */ { ALPHA_CHAR, 0 }, /* • */
+ { ALPHA_CHAR, 0 }, /* – */ { ALPHA_CHAR, 0 }, /* — */
+ { ALPHA_CHAR, 0 }, /* ˜ */ { ALPHA_CHAR, 0 }, /* ™ */
+ { ALPHA_CHAR, 0 }, /* š */ { ALPHA_CHAR, 0 }, /* › */
+ { ALPHA_CHAR, 0 }, /* œ */ { ALPHA_CHAR, 0 }, /*  */
+ { ALPHA_CHAR, 0 }, /* ž */ { ALPHA_CHAR, 0 }, /* Ÿ */
+ { ALPHA_CHAR, 0 }, /*   */ { ALPHA_CHAR, 0 }, /* ¡ */
+ { ALPHA_CHAR, 0 }, /* ¢ */ { ALPHA_CHAR, 0 }, /* £ */
+ { ALPHA_CHAR, 0 }, /* ¤ */ { ALPHA_CHAR, 0 }, /* ¥ */
+ { ALPHA_CHAR, 0 }, /* ¦ */ { ALPHA_CHAR, 0 }, /* § */
+ { ALPHA_CHAR, 0 }, /* ¨ */ { ALPHA_CHAR, 0 }, /* © */
+ { ALPHA_CHAR, 0 }, /* ª */ { ALPHA_CHAR, 0 }, /* « */
+ { ALPHA_CHAR, 0 }, /* ¬ */ { ALPHA_CHAR, 0 }, /* ­ */
+ { ALPHA_CHAR, 0 }, /* ® */ { ALPHA_CHAR, 0 }, /* ¯ */
+ { ALPHA_CHAR, 0 }, /* ° */ { ALPHA_CHAR, 0 }, /* ± */
+ { ALPHA_CHAR, 0 }, /* ² */ { ALPHA_CHAR, 0 }, /* ³ */
+ { ALPHA_CHAR, 0 }, /* ´ */ { ALPHA_CHAR, 0 }, /* µ */
+ { ALPHA_CHAR, 0 }, /* ¶ */ { ALPHA_CHAR, 0 }, /* · */
+ { ALPHA_CHAR, 0 }, /* ¸ */ { ALPHA_CHAR, 0 }, /* ¹ */
+ { ALPHA_CHAR, 0 }, /* º */ { ALPHA_CHAR, 0 }, /* » */
+ { ALPHA_CHAR, 0 }, /* ¼ */ { ALPHA_CHAR, 0 }, /* ½ */
+ { ALPHA_CHAR, 0 }, /* ¾ */ { ALPHA_CHAR, 0 }, /* ¿ */
+ { ALPHA_CHAR, 0 }, /* À */ { ALPHA_CHAR, 0 }, /* Á */
+ { ALPHA_CHAR, 0 }, /* Â */ { ALPHA_CHAR, 0 }, /* Ã */
+ { ALPHA_CHAR, 0 }, /* Ä */ { ALPHA_CHAR, 0 }, /* Å */
+ { ALPHA_CHAR, 0 }, /* Æ */ { ALPHA_CHAR, 0 }, /* Ç */
+ { ALPHA_CHAR, 0 }, /* È */ { ALPHA_CHAR, 0 }, /* É */
+ { ALPHA_CHAR, 0 }, /* Ê */ { ALPHA_CHAR, 0 }, /* Ë */
+ { ALPHA_CHAR, 0 }, /* Ì */ { ALPHA_CHAR, 0 }, /* Í */
+ { ALPHA_CHAR, 0 }, /* Î */ { ALPHA_CHAR, 0 }, /* Ï */
+ { ALPHA_CHAR, 0 }, /* Ð */ { ALPHA_CHAR, 0 }, /* Ñ */
+ { ALPHA_CHAR, 0 }, /* Ò */ { ALPHA_CHAR, 0 }, /* Ó */
+ { ALPHA_CHAR, 0 }, /* Ô */ { ALPHA_CHAR, 0 }, /* Õ */
+ { ALPHA_CHAR, 0 }, /* Ö */ { ALPHA_CHAR, 0 }, /* × */
+ { ALPHA_CHAR, 0 }, /* Ø */ { ALPHA_CHAR, 0 }, /* Ù */
+ { ALPHA_CHAR, 0 }, /* Ú */ { ALPHA_CHAR, 0 }, /* Û */
+ { ALPHA_CHAR, 0 }, /* Ü */ { ALPHA_CHAR, 0 }, /* Ý */
+ { ALPHA_CHAR, 0 }, /* Þ */ { ALPHA_CHAR, 0 }, /* ß */
+ { ALPHA_CHAR, 0 }, /* à */ { ALPHA_CHAR, 0 }, /* á */
+ { ALPHA_CHAR, 0 }, /* â */ { ALPHA_CHAR, 0 }, /* ã */
+ { ALPHA_CHAR, 0 }, /* ä */ { ALPHA_CHAR, 0 }, /* å */
+ { ALPHA_CHAR, 0 }, /* æ */ { ALPHA_CHAR, 0 }, /* ç */
+ { ALPHA_CHAR, 0 }, /* è */ { ALPHA_CHAR, 0 }, /* é */
+ { ALPHA_CHAR, 0 }, /* ê */ { ALPHA_CHAR, 0 }, /* ë */
+ { ALPHA_CHAR, 0 }, /* ì */ { ALPHA_CHAR, 0 }, /* í */
+ { ALPHA_CHAR, 0 }, /* î */ { ALPHA_CHAR, 0 }, /* ï */
+ { ALPHA_CHAR, 0 }, /* ð */ { ALPHA_CHAR, 0 }, /* ñ */
+ { ALPHA_CHAR, 0 }, /* ò */ { ALPHA_CHAR, 0 }, /* ó */
+ { ALPHA_CHAR, 0 }, /* ô */ { ALPHA_CHAR, 0 }, /* õ */
+ { ALPHA_CHAR, 0 }, /* ö */ { ALPHA_CHAR, 0 }, /* ÷ */
+ { ALPHA_CHAR, 0 }, /* ø */ { ALPHA_CHAR, 0 }, /* ù */
+ { ALPHA_CHAR, 0 }, /* ú */ { ALPHA_CHAR, 0 }, /* û */
+ { ALPHA_CHAR, 0 }, /* ü */ { ALPHA_CHAR, 0 }, /* ý */
+ { ALPHA_CHAR, 0 }, /* þ */ { ALPHA_CHAR, 0 }, /* ÿ */
+};
+
+int _SLcheck_identifier_syntax (char *name)
+{
+ unsigned char *p;
+
+ p = (unsigned char *) name;
+ if (ALPHA_CHAR == Char_Type_Table[*p][0]) while (1)
+ {
+ unsigned ch;
+ unsigned char type;
+
+ ch = *++p;
+
+ type = Char_Type_Table [ch][0];
+ if ((type != ALPHA_CHAR) && (type != DIGIT_CHAR))
+ {
+ if (ch == 0)
+ return 0;
+ break;
+ }
+ }
+
+ SLang_verror (SL_SYNTAX_ERROR,
+ "Name %s contains an illegal character", name);
+ return -1;
+}
+
+static unsigned char prep_get_char (void)
+{
+ register unsigned char ch;
+
+ if (0 != (ch = *Input_Line_Pointer++))
+ return ch;
+
+ Input_Line_Pointer--;
+ return 0;
+}
+
+static void unget_prep_char (unsigned char ch)
+{
+ if ((Input_Line_Pointer != Input_Line)
+ && (ch != 0))
+ Input_Line_Pointer--;
+ /* *Input_Line_Pointer = ch; -- Do not modify the Input_Line */
+}
+
+#include "keywhash.c"
+
+static int get_ident_token (_SLang_Token_Type *tok, unsigned char *s, unsigned int len)
+{
+ unsigned char ch;
+ unsigned char type;
+ Keyword_Table_Type *table;
+
+ while (1)
+ {
+ ch = prep_get_char ();
+ type = CHAR_CLASS (ch);
+ if ((type != ALPHA_CHAR) && (type != DIGIT_CHAR))
+ {
+ unget_prep_char (ch);
+ break;
+ }
+ s [len++] = ch;
+ }
+
+ s[len] = 0;
+
+ /* check if keyword */
+ table = is_keyword ((char *) s, len);
+ if (table != NULL)
+ {
+ tok->v.s_val = table->name;
+ return (tok->type = table->type);
+ }
+
+ tok->v.s_val = _SLstring_make_hashed_string ((char *)s, len, &tok->hash);
+ tok->free_sval_flag = 1;
+ return (tok->type = IDENT_TOKEN);
+}
+
+static int get_number_token (_SLang_Token_Type *tok, unsigned char *s, unsigned int len)
+{
+ unsigned char ch;
+ unsigned char type;
+
+ /* Look for pattern [0-9.xX]*([eE][-+]?[digits])?[ijfhul]? */
+ while (1)
+ {
+ ch = prep_get_char ();
+
+ type = CHAR_CLASS (ch);
+ if ((type != DIGIT_CHAR) && (type != DOT_CHAR))
+ {
+ if ((ch != 'x') && (ch != 'X'))
+ break;
+ /* It must be hex */
+ do
+ {
+ if (len == (MAX_TOKEN_LEN - 1))
+ goto too_long_return_error;
+
+ s[len++] = ch;
+ ch = prep_get_char ();
+ type = CHAR_CLASS (ch);
+ }
+ while ((type == DIGIT_CHAR) || (type == ALPHA_CHAR));
+ break;
+ }
+ if (len == (MAX_TOKEN_LEN - 1))
+ goto too_long_return_error;
+ s [len++] = ch;
+ }
+
+ /* At this point, type and ch are synchronized */
+
+ if ((ch == 'e') || (ch == 'E'))
+ {
+ if (len == (MAX_TOKEN_LEN - 1))
+ goto too_long_return_error;
+ s[len++] = ch;
+ ch = prep_get_char ();
+ if ((ch == '+') || (ch == '-'))
+ {
+ if (len == (MAX_TOKEN_LEN - 1))
+ goto too_long_return_error;
+ s[len++] = ch;
+ ch = prep_get_char ();
+ }
+
+ while (DIGIT_CHAR == (type = CHAR_CLASS(ch)))
+ {
+ if (len == (MAX_TOKEN_LEN - 1))
+ goto too_long_return_error;
+ s[len++] = ch;
+ ch = prep_get_char ();
+ }
+ }
+
+ while (ALPHA_CHAR == type)
+ {
+ if (len == (MAX_TOKEN_LEN - 1))
+ goto too_long_return_error;
+ s[len++] = ch;
+ ch = prep_get_char ();
+ type = CHAR_CLASS(ch);
+ }
+
+ unget_prep_char (ch);
+ s[len] = 0;
+
+ switch (SLang_guess_type ((char *) s))
+ {
+ default:
+ tok->v.s_val = (char *) s;
+ _SLparse_error ("Not a number", tok, 0);
+ return (tok->type = EOF_TOKEN);
+
+#if SLANG_HAS_FLOAT
+ case SLANG_FLOAT_TYPE:
+ tok->v.s_val = _SLstring_make_hashed_string ((char *)s, len, &tok->hash);
+ tok->free_sval_flag = 1;
+ return (tok->type = FLOAT_TOKEN);
+
+ case SLANG_DOUBLE_TYPE:
+ tok->v.s_val = _SLstring_make_hashed_string ((char *)s, len, &tok->hash);
+ tok->free_sval_flag = 1;
+ return (tok->type = DOUBLE_TOKEN);
+#endif
+#if SLANG_HAS_COMPLEX
+ case SLANG_COMPLEX_TYPE:
+ tok->v.s_val = _SLstring_make_hashed_string ((char *)s, len, &tok->hash);
+ tok->free_sval_flag = 1;
+ return (tok->type = COMPLEX_TOKEN);
+#endif
+ case SLANG_CHAR_TYPE:
+ tok->v.long_val = (char)SLatol (s);
+ return tok->type = CHAR_TOKEN;
+ case SLANG_UCHAR_TYPE:
+ tok->v.long_val = (unsigned char)SLatol (s);
+ return tok->type = UCHAR_TOKEN;
+ case SLANG_SHORT_TYPE:
+ tok->v.long_val = (short)SLatol (s);
+ return tok->type = SHORT_TOKEN;
+ case SLANG_USHORT_TYPE:
+ tok->v.long_val = (unsigned short)SLatoul (s);
+ return tok->type = USHORT_TOKEN;
+ case SLANG_INT_TYPE:
+ tok->v.long_val = (int)SLatol (s);
+ return tok->type = INT_TOKEN;
+ case SLANG_UINT_TYPE:
+ tok->v.long_val = (unsigned int)SLatoul (s);
+ return tok->type = UINT_TOKEN;
+ case SLANG_LONG_TYPE:
+ tok->v.long_val = SLatol (s);
+ return tok->type = LONG_TOKEN;
+ case SLANG_ULONG_TYPE:
+ tok->v.long_val = SLatoul (s);
+ return tok->type = ULONG_TOKEN;
+ }
+
+ too_long_return_error:
+ _SLparse_error ("Number too long for buffer", NULL, 0);
+ return (tok->type == EOF_TOKEN);
+}
+
+static int get_op_token (_SLang_Token_Type *tok, char ch)
+{
+ unsigned int offset;
+ char second_char;
+ unsigned char type;
+ char *name;
+
+ /* operators are: + - / * ++ -- += -= = == != > < >= <= | etc..
+ * These lex to the longest valid operator token.
+ */
+
+ offset = CHAR_DATA((unsigned char) ch);
+ if (0 == Operators [offset][1])
+ {
+ name = Operators [offset];
+ type = name [3];
+ }
+ else
+ {
+ type = EOF_TOKEN;
+ name = NULL;
+ }
+
+ second_char = prep_get_char ();
+ do
+ {
+ if (second_char == Operators[offset][1])
+ {
+ name = Operators [offset];
+ type = name [3];
+ break;
+ }
+ offset++;
+ }
+ while (ch == Operators[offset][0]);
+
+ tok->type = type;
+
+ if (type == EOF_TOKEN)
+ {
+ _SLparse_error ("Operator not supported", NULL, 0);
+ return type;
+ }
+
+ tok->v.s_val = name;
+
+ if (name[1] == 0)
+ unget_prep_char (second_char);
+
+ return type;
+}
+
+/* If this returns non-zero, then it is a binary string */
+static int expand_escaped_string (register char *s,
+ register char *t, register char *tmax,
+ unsigned int *lenp)
+{
+ char *s0;
+ int is_binary = 0;
+ char ch;
+
+ s0 = s;
+ while (t < tmax)
+ {
+ ch = *t++;
+ if (ch == '\\')
+ {
+ t = _SLexpand_escaped_char (t, &ch);
+ if (ch == 0) is_binary = 1;
+ }
+ *s++ = ch;
+ }
+ *s = 0;
+
+ *lenp = (unsigned char) (s - s0);
+ return is_binary;
+}
+
+static int get_string_token (_SLang_Token_Type *tok, unsigned char quote_char,
+ unsigned char *s)
+{
+ unsigned char ch;
+ unsigned int len = 0;
+ int has_quote = 0;
+ int is_binary;
+
+ while (1)
+ {
+ ch = prep_get_char ();
+ if (ch == 0)
+ {
+ _SLparse_error("Expecting quote-character", NULL, 0);
+ return (tok->type = EOF_TOKEN);
+ }
+ if (ch == quote_char) break;
+
+ s[len++] = ch;
+
+ if (len == (MAX_TOKEN_LEN - 1))
+ {
+ _SLparse_error ("String too long for buffer", NULL, 0);
+ return (tok->type == EOF_TOKEN);
+ }
+
+ if (ch == '\\')
+ {
+ has_quote = 1;
+ ch = prep_get_char ();
+ s[len++] = ch;
+ }
+ }
+
+ s[len] = 0;
+
+ if (has_quote)
+ is_binary = expand_escaped_string ((char *) s, (char *)s, (char *)s + len, &len);
+ else is_binary = 0;
+
+ if ('"' == quote_char)
+ {
+ tok->free_sval_flag = 1;
+ if (is_binary)
+ {
+ tok->v.b_val = SLbstring_create (s, len);
+ return tok->type = BSTRING_TOKEN;
+ }
+ else
+ {
+ tok->v.s_val = _SLstring_make_hashed_string ((char *)s,
+ len,
+ &tok->hash);
+ tok->free_sval_flag = 1;
+ return (tok->type = STRING_TOKEN);
+ }
+ }
+
+ /* else single character */
+ if (s[1] != 0)
+ {
+ _SLparse_error("Single char expected", NULL, 0);
+ return (tok->type = EOF_TOKEN);
+ }
+
+ tok->v.long_val = s[0];
+ return (tok->type = UCHAR_TOKEN);
+}
+
+static int extract_token (_SLang_Token_Type *tok, unsigned char ch, unsigned char t)
+{
+ unsigned char s [MAX_TOKEN_LEN];
+ unsigned int slen;
+
+ s[0] = (char) ch;
+ slen = 1;
+
+ switch (t)
+ {
+ case ALPHA_CHAR:
+ return get_ident_token (tok, s, slen);
+
+ case OP_CHAR:
+ return get_op_token (tok, ch);
+
+ case DIGIT_CHAR:
+ return get_number_token (tok, s, slen);
+
+ case EXCL_CHAR:
+ ch = prep_get_char ();
+ s [slen++] = ch;
+ t = CHAR_CLASS(ch);
+ if (t == ALPHA_CHAR) return get_ident_token (tok, s, slen);
+ if (t == OP_CHAR)
+ {
+ unget_prep_char (ch);
+ return get_op_token (tok, '!');
+ }
+ _SLparse_error("Misplaced !", NULL, 0);
+ return -1;
+
+ case DOT_CHAR:
+ ch = prep_get_char ();
+ if (DIGIT_CHAR == CHAR_CLASS(ch))
+ {
+ s [slen++] = ch;
+ return get_number_token (tok, s, slen);
+ }
+ unget_prep_char (ch);
+ return (tok->type = DOT_TOKEN);
+
+ case SEP_CHAR:
+ return (tok->type = CHAR_DATA(ch));
+
+ case DQUOTE_CHAR:
+ case QUOTE_CHAR:
+ return get_string_token (tok, ch, s);
+
+ default:
+ _SLparse_error("Invalid character", NULL, 0);
+ return (tok->type = EOF_TOKEN);
+ }
+}
+
+int _SLget_rpn_token (_SLang_Token_Type *tok)
+{
+ unsigned char ch;
+
+ tok->v.s_val = "??";
+ while ((ch = *Input_Line_Pointer) != 0)
+ {
+ unsigned char t;
+
+ Input_Line_Pointer++;
+ if (WHITE_CHAR == (t = CHAR_CLASS(ch)))
+ continue;
+
+ if (NL_CHAR == t)
+ break;
+
+ return extract_token (tok, ch, t);
+ }
+ Input_Line_Pointer = Empty_Line;
+ return EOF_TOKEN;
+}
+
+int _SLget_token (_SLang_Token_Type *tok)
+{
+ unsigned char ch;
+ unsigned char t;
+
+ tok->num_refs = 1;
+ tok->free_sval_flag = 0;
+ tok->v.s_val = "??";
+#if _SLANG_HAS_DEBUG_CODE
+ tok->line_number = LLT->line_num;
+#endif
+ if (SLang_Error || (Input_Line == NULL))
+ return (tok->type = EOF_TOKEN);
+
+ while (1)
+ {
+ ch = *Input_Line_Pointer++;
+ if (WHITE_CHAR == (t = CHAR_CLASS (ch)))
+ continue;
+
+ if (t != NL_CHAR)
+ return extract_token (tok, ch, t);
+
+ do
+ {
+ LLT->line_num++;
+#if _SLANG_HAS_DEBUG_CODE
+ tok->line_number++;
+#endif
+ Input_Line = LLT->read(LLT);
+ if ((NULL == Input_Line) || SLang_Error)
+ {
+ Input_Line_Pointer = Input_Line = NULL;
+ return (tok->type = EOF_TOKEN);
+ }
+ }
+ while (0 == SLprep_line_ok(Input_Line, This_SLpp));
+
+ Input_Line_Pointer = Input_Line;
+ if (*Input_Line_Pointer == '.')
+ {
+ Input_Line_Pointer++;
+ return tok->type = RPN_TOKEN;
+ }
+ }
+}
+
+static int prep_exists_function (char *line, char comment)
+{
+ char buf[MAX_FILE_LINE_LEN], *b, *bmax;
+ unsigned char ch;
+
+ bmax = buf + (sizeof (buf) - 1);
+
+ while (1)
+ {
+ /* skip whitespace */
+ while ((ch = (unsigned char) *line),
+ ch && (ch != '\n') && (ch <= ' '))
+ line++;
+
+ if ((ch <= '\n')
+ || (ch == (unsigned char) comment)) break;
+
+ b = buf;
+ while ((ch = (unsigned char) *line) > ' ')
+ {
+ if (b < bmax) *b++ = (char) ch;
+ line++;
+ }
+ *b = 0;
+
+ if (SLang_is_defined (buf))
+ return 1;
+ }
+
+ return 0;
+}
+
+static int prep_eval_expr (char *expr)
+{
+ int ret;
+
+ if (0 != SLang_load_string (expr))
+ return -1;
+ if (-1 == SLang_pop_integer (&ret))
+ return -1;
+ return (ret != 0);
+}
+
+
+int SLang_load_object (SLang_Load_Type *x)
+{
+ SLPreprocess_Type this_pp;
+ SLPreprocess_Type *save_this_pp;
+ SLang_Load_Type *save_llt;
+ char *save_input_line, *save_input_line_ptr;
+#if _SLANG_HAS_DEBUG_CODE
+ int save_compile_line_num_info;
+#endif
+ int save_auto_declare_variables;
+
+ if (SLprep_exists_hook == NULL)
+ SLprep_exists_hook = prep_exists_function;
+
+ if (_SLprep_eval_hook == NULL)
+ _SLprep_eval_hook = prep_eval_expr;
+
+ if (-1 == SLprep_open_prep (&this_pp)) return -1;
+
+ if (-1 == _SLcompile_push_context (x))
+ return -1;
+
+#if _SLANG_HAS_DEBUG_CODE
+ save_compile_line_num_info = _SLang_Compile_Line_Num_Info;
+#endif
+ save_this_pp = This_SLpp;
+ save_input_line = Input_Line;
+ save_input_line_ptr = Input_Line_Pointer;
+ save_llt = LLT;
+ save_auto_declare_variables = _SLang_Auto_Declare_Globals;
+
+ This_SLpp = &this_pp;
+ Input_Line_Pointer = Input_Line = Empty_Line;
+ LLT = x;
+
+ x->line_num = 0;
+ x->parse_level = 0;
+ _SLang_Auto_Declare_Globals = x->auto_declare_globals;
+
+#if _SLANG_HAS_DEBUG_CODE
+ _SLang_Compile_Line_Num_Info = Default_Compile_Line_Num_Info;
+#endif
+
+ _SLparse_start (x);
+ if (SLang_Error)
+ do_line_file_error (x->line_num, x->name);
+
+ _SLang_Auto_Declare_Globals = save_auto_declare_variables;
+
+ if (SLang_Error) SLang_restart (0);
+
+ (void) _SLcompile_pop_context ();
+
+ Input_Line = save_input_line;
+ Input_Line_Pointer = save_input_line_ptr;
+ LLT = save_llt;
+ This_SLpp = save_this_pp;
+
+#if _SLANG_HAS_DEBUG_CODE
+ _SLang_Compile_Line_Num_Info = save_compile_line_num_info;
+#endif
+
+ if (SLang_Error) return -1;
+ return 0;
+}
+
+SLang_Load_Type *SLallocate_load_type (char *name)
+{
+ SLang_Load_Type *x;
+
+ if (NULL == (x = (SLang_Load_Type *)SLmalloc (sizeof (SLang_Load_Type))))
+ return NULL;
+ memset ((char *) x, 0, sizeof (SLang_Load_Type));
+
+ if (name == NULL) name = "";
+
+ x->name = SLang_create_slstring (name);
+ if (x->name == NULL)
+ {
+ SLfree ((char *) x);
+ return NULL;
+ }
+ return x;
+}
+
+void SLdeallocate_load_type (SLang_Load_Type *x)
+{
+ if (x != NULL)
+ {
+ SLang_free_slstring (x->name);
+ SLfree ((char *) x);
+ }
+}
+
+typedef struct
+{
+ char *string;
+ char *ptr;
+}
+String_Client_Data_Type;
+
+static char *read_from_string (SLang_Load_Type *x)
+{
+ String_Client_Data_Type *data;
+ char *s, *s1, ch;
+
+ data = (String_Client_Data_Type *)x->client_data;
+ s1 = s = data->ptr;
+
+ if (*s == 0)
+ return NULL;
+
+ while ((ch = *s) != 0)
+ {
+ s++;
+ if (ch == '\n')
+ break;
+ }
+
+ data->ptr = s;
+ return s1;
+}
+
+int SLang_load_string (char *string)
+{
+ SLang_Load_Type *x;
+ String_Client_Data_Type data;
+ int ret;
+
+ if (string == NULL)
+ return -1;
+
+ /* Grab a private copy in case loading modifies string */
+ if (NULL == (string = SLang_create_slstring (string)))
+ return -1;
+
+ /* To avoid creating a static data space for every string loaded,
+ * all string objects will be regarded as identical. So, identify
+ * all of them by ***string***
+ */
+ if (NULL == (x = SLallocate_load_type ("***string***")))
+ {
+ SLang_free_slstring (string);
+ return -1;
+ }
+
+ x->client_data = (VOID_STAR) &data;
+ x->read = read_from_string;
+
+ data.ptr = data.string = string;
+ if (-1 == (ret = SLang_load_object (x)))
+ SLang_verror (SLang_Error, "called from eval: %s", string);
+
+ SLang_free_slstring (string);
+ SLdeallocate_load_type (x);
+ return ret;
+}
+
+typedef struct
+{
+ char *buf;
+ FILE *fp;
+}
+File_Client_Data_Type;
+
+char *SLang_User_Prompt;
+static char *read_from_file (SLang_Load_Type *x)
+{
+ FILE *fp;
+ File_Client_Data_Type *c;
+
+ c = (File_Client_Data_Type *)x->client_data;
+ fp = c->fp;
+
+ if ((fp == stdin) && (SLang_User_Prompt != NULL))
+ {
+ fputs (SLang_User_Prompt, stdout);
+ fflush (stdout);
+ }
+
+ return fgets (c->buf, MAX_FILE_LINE_LEN, c->fp);
+}
+
+/* Note that file could be freed from Slang during run of this routine
+ * so get it and store it !! (e.g., autoloading)
+ */
+int (*SLang_Load_File_Hook) (char *);
+int SLang_load_file (char *f)
+{
+ File_Client_Data_Type client_data;
+ SLang_Load_Type *x;
+ char *name, *buf;
+ FILE *fp;
+
+ if (SLang_Load_File_Hook != NULL)
+ return (*SLang_Load_File_Hook) (f);
+
+ if (f == NULL) name = "<stdin>"; else name = f;
+
+ name = SLang_create_slstring (name);
+ if (name == NULL)
+ return -1;
+
+ if (NULL == (x = SLallocate_load_type (name)))
+ {
+ SLang_free_slstring (name);
+ return -1;
+ }
+
+ buf = NULL;
+
+ if (f != NULL)
+ fp = fopen (f, "r");
+ else
+ fp = stdin;
+
+ if (fp == NULL)
+ SLang_verror (SL_OBJ_NOPEN, "Unable to open %s", name);
+ else if (NULL != (buf = SLmalloc (MAX_FILE_LINE_LEN + 1)))
+ {
+ client_data.fp = fp;
+ client_data.buf = buf;
+ x->client_data = (VOID_STAR) &client_data;
+ x->read = read_from_file;
+
+ (void) SLang_load_object (x);
+ }
+
+ if ((fp != NULL) && (fp != stdin))
+ fclose (fp);
+
+ SLfree (buf);
+ SLang_free_slstring (name);
+ SLdeallocate_load_type (x);
+
+ if (SLang_Error)
+ return -1;
+
+ return 0;
+}
+
+int SLang_guess_type (char *t)
+{
+ char *p;
+ register char ch;
+ int modifier = 0;
+
+ if (*t == '-') t++;
+ p = t;
+
+#if SLANG_HAS_FLOAT
+ if (*p != '.')
+ {
+#endif
+ modifier = 0;
+ while ((*p >= '0') && (*p <= '9')) p++;
+ if (t == p) return (SLANG_STRING_TYPE);
+ if ((*p == 'x') && (p == t + 1)) /* 0x?? */
+ {
+ modifier |= 8;
+ p++;
+ while (ch = *p,
+ ((ch >= '0') && (ch <= '9'))
+ || (((ch | 0x20) >= 'a') && ((ch | 0x20) <= 'f'))) p++;
+ }
+
+ /* Now look for UL, LU, UH, HU, L, H modifiers */
+ while ((ch = *p) != 0)
+ {
+ ch |= 0x20;
+ if (ch == 'h') modifier |= 1;
+ else if (ch == 'l') modifier |= 2;
+ else if (ch == 'u') modifier |= 4;
+ else break;
+ p++;
+ }
+ if ((1|2) == (modifier & (1|2))) /* hl present */
+ return SLANG_STRING_TYPE;
+
+ if (ch == 0)
+ {
+ if ((modifier & 0x7) == 0) return SLANG_INT_TYPE;
+ if (modifier & 4)
+ {
+ if (modifier & 1) return SLANG_USHORT_TYPE;
+ if (modifier & 2) return SLANG_ULONG_TYPE;
+ return SLANG_UINT_TYPE;
+ }
+ if (modifier & 1) return SLANG_SHORT_TYPE;
+ if (modifier & 2) return SLANG_LONG_TYPE;
+ return SLANG_INT_TYPE;
+ }
+
+ if (modifier) return SLANG_STRING_TYPE;
+#if SLANG_HAS_FLOAT
+ }
+
+ /* now down to double case */
+ if (*p == '.')
+ {
+ p++;
+ while ((*p >= '0') && (*p <= '9')) p++;
+ }
+ if (*p == 0) return(SLANG_DOUBLE_TYPE);
+ if ((*p != 'e') && (*p != 'E'))
+ {
+# if SLANG_HAS_COMPLEX
+ if (((*p == 'i') || (*p == 'j'))
+ && (p[1] == 0))
+ return SLANG_COMPLEX_TYPE;
+# endif
+ if (((*p | 0x20) == 'f') && (p[1] == 0))
+ return SLANG_FLOAT_TYPE;
+
+ return SLANG_STRING_TYPE;
+ }
+
+ p++;
+ if ((*p == '-') || (*p == '+')) p++;
+ while ((*p >= '0') && (*p <= '9')) p++;
+ if (*p != 0)
+ {
+# if SLANG_HAS_COMPLEX
+ if (((*p == 'i') || (*p == 'j'))
+ && (p[1] == 0))
+ return SLANG_COMPLEX_TYPE;
+# endif
+ if (((*p | 0x20) == 'f') && (p[1] == 0))
+ return SLANG_FLOAT_TYPE;
+
+ return SLANG_STRING_TYPE;
+ }
+ return SLANG_DOUBLE_TYPE;
+#else
+ return SLANG_STRING_TYPE;
+#endif /* SLANG_HAS_FLOAT */
+}
+
+static int hex_atoul (unsigned char *s, unsigned long *ul)
+{
+ register unsigned char ch;
+ register unsigned long value;
+ register int base;
+
+ s++; /* skip the leading 0 */
+
+ /* look for 'x' which indicates hex */
+ if ((*s | 0x20) == 'x')
+ {
+ base = 16;
+ s++;
+ if (*s == 0)
+ {
+ SLang_Error = SL_SYNTAX_ERROR;
+ return -1;
+ }
+ }
+ else base = 8;
+
+ value = 0;
+ while ((ch = *s++) != 0)
+ {
+ char ch1 = ch | 0x20;
+ switch (ch1)
+ {
+ default:
+ SLang_Error = SL_SYNTAX_ERROR;
+ break;
+
+ case 'u':
+ case 'l':
+ case 'h':
+ *ul = value;
+ return 0;
+
+ case '8':
+ case '9':
+ if (base != 16) SLang_Error = SL_SYNTAX_ERROR;
+ /* drop */
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ ch1 -= '0';
+ break;
+
+ case 'a':
+ case 'b':
+ case 'c':
+ case 'd':
+ case 'e':
+ case 'f':
+ if (base != 16) SLang_Error = SL_SYNTAX_ERROR;
+ ch1 = (ch1 - 'a') + 10;
+ break;
+ }
+ value = value * base + ch1;
+ }
+ *ul = value;
+ return 0;
+}
+
+/* Note: These routines do not check integer overflow. I would use the C
+ * library functions atol and atoul but some implementations check overflow
+ * and some do not. The following implementations provide a consistent
+ * behavior.
+ */
+unsigned long SLatoul (unsigned char *s)
+{
+ int sign;
+ unsigned long value;
+
+ if (*s == '-') sign = -1;
+ else
+ {
+ sign = 1;
+ if (*s == '+') s++;
+ }
+
+ if (*s == '0')
+ {
+ if (-1 == hex_atoul (s, &value))
+ return (unsigned long) -1;
+ }
+ else
+ {
+ while (WHITE_CHAR == CHAR_CLASS(*s))
+ s++;
+
+ value = 0;
+ while (DIGIT_CHAR == CHAR_CLASS(*s))
+ {
+ value = value * 10 + (unsigned long) (*s - '0');
+ s++;
+ }
+ }
+
+ if (sign == -1)
+ value = (unsigned long)-1L * value;
+
+ return value;
+}
+
+long SLatol (unsigned char *s)
+{
+ while (WHITE_CHAR == CHAR_CLASS(*s))
+ s++;
+
+ if (*s == '-')
+ {
+ long value = (long) SLatoul (s+1);
+ return -value;
+ }
+ return (long) SLatoul (s);
+}
+
+int SLatoi (unsigned char *s)
+{
+ return (int) SLatol (s);
+}
+
+static char *check_byte_compiled_token (char *buf)
+{
+ unsigned int len_lo, len_hi, len;
+
+ len_lo = (unsigned char) *Input_Line_Pointer++;
+ if ((len_lo < 32)
+ || ((len_hi = (unsigned char)*Input_Line_Pointer++) < 32)
+ || ((len = (len_lo - 32) | ((len_hi - 32) << 7)) >= MAX_TOKEN_LEN))
+ {
+ SLang_doerror ("Byte compiled file appears corrupt");
+ return NULL;
+ }
+
+ SLMEMCPY (buf, Input_Line_Pointer, len);
+ buf += len;
+ Input_Line_Pointer += len;
+ *buf = 0;
+ return buf;
+}
+
+void _SLcompile_byte_compiled (void)
+{
+ unsigned char type;
+ _SLang_Token_Type tok;
+ char buf[MAX_TOKEN_LEN];
+ char *ebuf;
+ unsigned int len;
+
+ memset ((char *) &tok, 0, sizeof (_SLang_Token_Type));
+
+ while (SLang_Error == 0)
+ {
+ top_of_switch:
+ type = (unsigned char) *Input_Line_Pointer++;
+ switch (type)
+ {
+ case '\n':
+ case 0:
+ if (NULL == (Input_Line = LLT->read(LLT)))
+ {
+ Input_Line_Pointer = Input_Line = NULL;
+ return;
+ }
+ Input_Line_Pointer = Input_Line;
+ goto top_of_switch;
+
+ case LINE_NUM_TOKEN:
+ case CHAR_TOKEN:
+ case UCHAR_TOKEN:
+ case SHORT_TOKEN:
+ case USHORT_TOKEN:
+ case INT_TOKEN:
+ case UINT_TOKEN:
+ case LONG_TOKEN:
+ case ULONG_TOKEN:
+ if (NULL == check_byte_compiled_token (buf))
+ return;
+ tok.v.long_val = atol (buf);
+ break;
+
+ case COMPLEX_TOKEN:
+ case FLOAT_TOKEN:
+ case DOUBLE_TOKEN:
+ if (NULL == check_byte_compiled_token (buf))
+ return;
+ tok.v.s_val = buf;
+ break;
+
+ case ESC_STRING_TOKEN:
+ if (NULL == (ebuf = check_byte_compiled_token (buf)))
+ return;
+ tok.v.s_val = buf;
+ if (expand_escaped_string (buf, buf, ebuf, &len))
+ {
+ tok.hash = len;
+ type = _BSTRING_TOKEN;
+ }
+ else
+ {
+ tok.hash = _SLstring_hash ((unsigned char *)buf, (unsigned char *)buf + len);
+ type = STRING_TOKEN;
+ }
+ break;
+
+ case TMP_TOKEN:
+ case DEFINE_TOKEN:
+ case DEFINE_STATIC_TOKEN:
+ case DEFINE_PRIVATE_TOKEN:
+ case DEFINE_PUBLIC_TOKEN:
+ case DOT_TOKEN:
+ case STRING_TOKEN:
+ case IDENT_TOKEN:
+ case _REF_TOKEN:
+ case _DEREF_ASSIGN_TOKEN:
+ case _SCALAR_ASSIGN_TOKEN:
+ case _SCALAR_PLUSEQS_TOKEN:
+ case _SCALAR_MINUSEQS_TOKEN:
+ case _SCALAR_TIMESEQS_TOKEN:
+ case _SCALAR_DIVEQS_TOKEN:
+ case _SCALAR_BOREQS_TOKEN:
+ case _SCALAR_BANDEQS_TOKEN:
+ case _SCALAR_PLUSPLUS_TOKEN:
+ case _SCALAR_POST_PLUSPLUS_TOKEN:
+ case _SCALAR_MINUSMINUS_TOKEN:
+ case _SCALAR_POST_MINUSMINUS_TOKEN:
+ case _STRUCT_ASSIGN_TOKEN:
+ case _STRUCT_PLUSEQS_TOKEN:
+ case _STRUCT_MINUSEQS_TOKEN:
+ case _STRUCT_TIMESEQS_TOKEN:
+ case _STRUCT_DIVEQS_TOKEN:
+ case _STRUCT_BOREQS_TOKEN:
+ case _STRUCT_BANDEQS_TOKEN:
+ case _STRUCT_POST_MINUSMINUS_TOKEN:
+ case _STRUCT_MINUSMINUS_TOKEN:
+ case _STRUCT_POST_PLUSPLUS_TOKEN:
+ case _STRUCT_PLUSPLUS_TOKEN:
+ if (NULL == (ebuf = check_byte_compiled_token (buf)))
+ return;
+ tok.v.s_val = buf;
+ tok.hash = _SLstring_hash ((unsigned char *)buf, (unsigned char *)ebuf);
+ break;
+
+ default:
+ break;
+ }
+ tok.type = type;
+
+ (*_SLcompile_ptr) (&tok);
+ }
+}
+
+static int escape_string (unsigned char *s, unsigned char *smax,
+ unsigned char *buf, unsigned char *buf_max,
+ int *is_escaped)
+{
+ unsigned char ch;
+
+ *is_escaped = 0;
+ while (buf < buf_max)
+ {
+ if (s == smax)
+ {
+ *buf = 0;
+ return 0;
+ }
+
+ ch = *s++;
+ switch (ch)
+ {
+ default:
+ *buf++ = ch;
+ break;
+
+ case 0:
+ *buf++ = '\\';
+ if (buf < buf_max) *buf++ = 'x';
+ if (buf < buf_max) *buf++ = '0';
+ if (buf < buf_max) *buf++ = '0';
+ *is_escaped = 1;
+ break; /* return 0; */
+
+ case '\n':
+ *buf++ = '\\';
+ if (buf < buf_max) *buf++ = 'n';
+ *is_escaped = 1;
+ break;
+
+ case '\r':
+ *buf++ = '\\';
+ if (buf < buf_max) *buf++ = 'r';
+ *is_escaped = 1;
+ break;
+
+ case 0x1A: /* ^Z */
+ *buf++ = '\\';
+ if (buf < buf_max) *buf++ = 'x';
+ if (buf < buf_max) *buf++ = '1';
+ if (buf < buf_max) *buf++ = 'A';
+ *is_escaped = 1;
+ break;
+
+ case '\\':
+ *buf++ = ch;
+ if (buf < buf_max) *buf++ = ch;
+ *is_escaped = 1;
+ break;
+ }
+ }
+ _SLparse_error ("String too long to byte-compile", NULL, 0);
+ return -1;
+}
+
+static FILE *Byte_Compile_Fp;
+static unsigned int Byte_Compile_Line_Len;
+
+static int bytecomp_write_data (char *buf, unsigned int len)
+{
+ char *err = "Write Error";
+
+ if ((Byte_Compile_Line_Len + len + 1) >= MAX_FILE_LINE_LEN)
+ {
+ if (EOF == fputs ("\n", Byte_Compile_Fp))
+ {
+ SLang_doerror (err);
+ return -1;
+ }
+ Byte_Compile_Line_Len = 0;
+ }
+
+ if (EOF == fputs (buf, Byte_Compile_Fp))
+ {
+ SLang_doerror (err);
+ return -1;
+ }
+ Byte_Compile_Line_Len += len;
+ return 0;
+}
+
+static void byte_compile_token (_SLang_Token_Type *tok)
+{
+ unsigned char buf [MAX_TOKEN_LEN + 4], *buf_max;
+ unsigned int len;
+ char *b3;
+ int is_escaped;
+ unsigned char *s;
+
+ if (SLang_Error) return;
+
+ buf [0] = (unsigned char) tok->type;
+ buf [1] = 0;
+
+ buf_max = buf + sizeof(buf);
+ b3 = (char *) buf + 3;
+
+ switch (tok->type)
+ {
+ case LINE_NUM_TOKEN:
+ case CHAR_TOKEN:
+ case SHORT_TOKEN:
+ case INT_TOKEN:
+ case LONG_TOKEN:
+ sprintf (b3, "%ld", tok->v.long_val);
+ break;
+
+ case UCHAR_TOKEN:
+ case USHORT_TOKEN:
+ case UINT_TOKEN:
+ case ULONG_TOKEN:
+ sprintf (b3, "%lu", tok->v.long_val);
+ break;
+
+ case _BSTRING_TOKEN:
+ s = (unsigned char *) tok->v.s_val;
+ len = (unsigned int) tok->hash;
+
+ if (-1 == escape_string (s, s + len,
+ (unsigned char *)b3, buf_max,
+ &is_escaped))
+ return;
+
+ buf[0] = ESC_STRING_TOKEN;
+ break;
+
+ case BSTRING_TOKEN:
+ if (NULL == (s = SLbstring_get_pointer (tok->v.b_val, &len)))
+ return;
+
+ if (-1 == escape_string (s, s + len,
+ (unsigned char *)b3, buf_max,
+ &is_escaped))
+ return;
+ buf[0] = ESC_STRING_TOKEN;
+ break;
+
+ case STRING_TOKEN:
+ s = (unsigned char *)tok->v.s_val;
+
+ if (-1 == escape_string (s, s + strlen ((char *)s),
+ (unsigned char *)b3, buf_max,
+ &is_escaped))
+ return;
+
+ if (is_escaped)
+ buf[0] = ESC_STRING_TOKEN;
+ break;
+
+ /* a _SCALAR_* token is attached to an identifier. */
+ case _DEREF_ASSIGN_TOKEN:
+ case _SCALAR_ASSIGN_TOKEN:
+ case _SCALAR_PLUSEQS_TOKEN:
+ case _SCALAR_MINUSEQS_TOKEN:
+ case _SCALAR_TIMESEQS_TOKEN:
+ case _SCALAR_DIVEQS_TOKEN:
+ case _SCALAR_BOREQS_TOKEN:
+ case _SCALAR_BANDEQS_TOKEN:
+ case _SCALAR_PLUSPLUS_TOKEN:
+ case _SCALAR_POST_PLUSPLUS_TOKEN:
+ case _SCALAR_MINUSMINUS_TOKEN:
+ case _SCALAR_POST_MINUSMINUS_TOKEN:
+ case DOT_TOKEN:
+ case TMP_TOKEN:
+ case DEFINE_TOKEN:
+ case DEFINE_STATIC_TOKEN:
+ case DEFINE_PRIVATE_TOKEN:
+ case DEFINE_PUBLIC_TOKEN:
+ case FLOAT_TOKEN:
+ case DOUBLE_TOKEN:
+ case COMPLEX_TOKEN:
+ case IDENT_TOKEN:
+ case _REF_TOKEN:
+ case _STRUCT_ASSIGN_TOKEN:
+ case _STRUCT_PLUSEQS_TOKEN:
+ case _STRUCT_MINUSEQS_TOKEN:
+ case _STRUCT_TIMESEQS_TOKEN:
+ case _STRUCT_DIVEQS_TOKEN:
+ case _STRUCT_BOREQS_TOKEN:
+ case _STRUCT_BANDEQS_TOKEN:
+ case _STRUCT_POST_MINUSMINUS_TOKEN:
+ case _STRUCT_MINUSMINUS_TOKEN:
+ case _STRUCT_POST_PLUSPLUS_TOKEN:
+ case _STRUCT_PLUSPLUS_TOKEN:
+ strcpy (b3, tok->v.s_val);
+ break;
+
+ default:
+ b3 = NULL;
+ }
+
+ if (b3 != NULL)
+ {
+ len = strlen (b3);
+ buf[1] = (unsigned char) ((len & 0x7F) + 32);
+ buf[2] = (unsigned char) (((len >> 7) & 0x7F) + 32);
+ len += 3;
+ }
+ else len = 1;
+
+ (void) bytecomp_write_data ((char *)buf, len);
+}
+
+int SLang_byte_compile_file (char *name, int method)
+{
+ char file [1024];
+
+ (void) method;
+ if (strlen (name) + 2 >= sizeof (file))
+ {
+ SLang_verror (SL_INVALID_PARM, "Filename too long");
+ return -1;
+ }
+ sprintf (file, "%sc", name);
+ if (NULL == (Byte_Compile_Fp = fopen (file, "w")))
+ {
+ SLang_verror(SL_OBJ_NOPEN, "%s: unable to open", file);
+ return -1;
+ }
+
+ Byte_Compile_Line_Len = 0;
+ if (-1 != bytecomp_write_data (".#", 2))
+ {
+ _SLcompile_ptr = byte_compile_token;
+ (void) SLang_load_file (name);
+ _SLcompile_ptr = _SLcompile;
+
+ (void) bytecomp_write_data ("\n", 1);
+ }
+
+ if (EOF == fclose (Byte_Compile_Fp))
+ SLang_doerror ("Write Error");
+
+ if (SLang_Error)
+ {
+ SLang_verror (0, "Error processing %s", name);
+ return -1;
+ }
+ return 0;
+}
+
+int SLang_generate_debug_info (int x)
+{
+ int y = Default_Compile_Line_Num_Info;
+ Default_Compile_Line_Num_Info = x;
+ return y;
+}
diff --git a/mdk-stage1/slang/sltypes.c b/mdk-stage1/slang/sltypes.c
new file mode 100644
index 000000000..05b8741b1
--- /dev/null
+++ b/mdk-stage1/slang/sltypes.c
@@ -0,0 +1,966 @@
+/* Basic type operations for S-Lang */
+/* Copyright (c) 1992, 1996, 2001 John E. Davis
+ * This file is part of the S-Lang library.
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Perl Artistic License.
+ */
+
+#include "slinclud.h"
+
+#if SLANG_HAS_FLOAT
+# include <math.h>
+#endif
+
+#define SL_APP_WANTS_FOREACH /* for String_Type */
+#include "slang.h"
+#include "_slang.h"
+
+int SLpop_string (char **s) /*{{{*/
+{
+ char *sls;
+
+ *s = NULL;
+
+ if (-1 == SLang_pop_slstring (&sls))
+ return -1;
+
+ if (NULL == (*s = SLmake_string (sls)))
+ {
+ SLang_free_slstring (sls);
+ return -1;
+ }
+
+ SLang_free_slstring (sls);
+ return 0;
+}
+
+/*}}}*/
+
+int SLang_pop_slstring (char **s) /*{{{*/
+{
+ return SLclass_pop_ptr_obj (SLANG_STRING_TYPE, (VOID_STAR *)s);
+}
+
+/*}}}*/
+
+/* if *data != 0, string should be freed upon use. */
+int SLang_pop_string(char **s, int *data) /*{{{*/
+{
+ if (SLpop_string (s))
+ return -1;
+
+ *data = 1;
+ return 0;
+}
+
+/*}}}*/
+
+int _SLang_push_slstring (char *s)
+{
+ if (0 == SLclass_push_ptr_obj (SLANG_STRING_TYPE, (VOID_STAR)s))
+ return 0;
+
+ SLang_free_slstring (s);
+ return -1;
+}
+
+int _SLpush_alloced_slstring (char *s, unsigned int len)
+{
+ if (NULL == (s = _SLcreate_via_alloced_slstring (s, len)))
+ return -1;
+
+ return _SLang_push_slstring (s);
+}
+
+int SLang_push_string (char *t) /*{{{*/
+{
+ if (t == NULL)
+ return SLang_push_null ();
+
+ if (NULL == (t = SLang_create_slstring (t)))
+ return -1;
+
+ return _SLang_push_slstring (t);
+}
+
+/*}}}*/
+
+int _SLang_dup_and_push_slstring (char *s)
+{
+ if (NULL == (s = _SLstring_dup_slstring (s)))
+ return SLang_push_null ();
+
+ return _SLang_push_slstring (s);
+}
+
+
+/* This function _always_ frees the malloced string */
+int SLang_push_malloced_string (char *c) /*{{{*/
+{
+ int ret;
+
+ ret = SLang_push_string (c);
+ SLfree (c);
+
+ return ret;
+}
+
+/*}}}*/
+
+#if 0
+static int int_int_power (int a, int b)
+{
+ int r, s;
+
+ if (a == 0) return 0;
+ if (b < 0) return 0;
+ if (b == 0) return 1;
+
+ s = 1;
+ if (a < 0)
+ {
+ if ((b % 2) == 1) s = -1;
+ a = -a;
+ }
+
+ /* FIXME: Priority=low
+ * This needs optimized
+ */
+ r = 1;
+ while (b)
+ {
+ r = r * a;
+ b--;
+ }
+ return r * s;
+}
+#endif
+
+static int
+string_string_bin_op_result (int op, unsigned char a, unsigned char b,
+ unsigned char *c)
+{
+ (void) a;
+ (void) b;
+ switch (op)
+ {
+ default:
+ return 0;
+
+ case SLANG_PLUS:
+ *c = SLANG_STRING_TYPE;
+ break;
+
+ case SLANG_GT:
+ case SLANG_GE:
+ case SLANG_LT:
+ case SLANG_LE:
+ case SLANG_EQ:
+ case SLANG_NE:
+ *c = SLANG_CHAR_TYPE;
+ break;
+ }
+ return 1;
+}
+
+static int
+string_string_bin_op (int op,
+ unsigned char a_type, VOID_STAR ap, unsigned int na,
+ unsigned char b_type, VOID_STAR bp, unsigned int nb,
+ VOID_STAR cp)
+{
+ char *ic;
+ char **a, **b, **c;
+ unsigned int n, n_max;
+ unsigned int da, db;
+
+ (void) a_type;
+ (void) b_type;
+
+ if (na == 1) da = 0; else da = 1;
+ if (nb == 1) db = 0; else db = 1;
+
+ if (na > nb) n_max = na; else n_max = nb;
+
+ a = (char **) ap;
+ b = (char **) bp;
+ for (n = 0; n < n_max; n++)
+ {
+ if ((*a == NULL) || (*b == NULL))
+ {
+ SLang_verror (SL_VARIABLE_UNINITIALIZED, "String element[%u] not initialized for binary operation", n);
+ return -1;
+ }
+ a += da; b += db;
+ }
+
+ a = (char **) ap;
+ b = (char **) bp;
+ ic = (char *) cp;
+ c = NULL;
+
+ switch (op)
+ {
+ case SLANG_DIVIDE:
+ case SLANG_MINUS:
+ default:
+ return 0;
+
+ case SLANG_PLUS:
+ /* Concat */
+ c = (char **) cp;
+ for (n = 0; n < n_max; n++)
+ {
+ if (NULL == (c[n] = SLang_concat_slstrings (*a, *b)))
+ goto return_error;
+
+ a += da; b += db;
+ }
+ break;
+
+ case SLANG_NE:
+ for (n = 0; n < n_max; n++)
+ {
+ ic [n] = (0 != strcmp (*a, *b));
+ a += da;
+ b += db;
+ }
+ break;
+ case SLANG_GT:
+ for (n = 0; n < n_max; n++)
+ {
+ ic [n] = (strcmp (*a, *b) > 0);
+ a += da;
+ b += db;
+ }
+ break;
+ case SLANG_GE:
+ for (n = 0; n < n_max; n++)
+ {
+ ic [n] = (strcmp (*a, *b) >= 0);
+ a += da;
+ b += db;
+ }
+ break;
+ case SLANG_LT:
+ for (n = 0; n < n_max; n++)
+ {
+ ic [n] = (strcmp (*a, *b) < 0);
+ a += da;
+ b += db;
+ }
+ break;
+ case SLANG_LE:
+ for (n = 0; n < n_max; n++)
+ {
+ ic [n] = (strcmp (*a, *b) <= 0);
+ a += da;
+ b += db;
+ }
+ break;
+ case SLANG_EQ:
+ for (n = 0; n < n_max; n++)
+ {
+ ic [n] = (strcmp (*a, *b) == 0);
+ a += da;
+ b += db;
+ }
+ break;
+ }
+ return 1;
+
+ return_error:
+ if (c != NULL)
+ {
+ unsigned int nn;
+ for (nn = 0; nn < n; nn++)
+ {
+ SLang_free_slstring (c[nn]);
+ c[nn] = NULL;
+ }
+ for (nn = n; nn < n_max; nn++)
+ c[nn] = NULL;
+ }
+ return -1;
+}
+
+static void string_destroy (unsigned char unused, VOID_STAR s)
+{
+ (void) unused;
+ SLang_free_slstring (*(char **) s);
+}
+
+static int string_push (unsigned char unused, VOID_STAR sptr)
+{
+ (void) unused;
+ return SLang_push_string (*(char **) sptr);
+}
+
+static int string_cmp (unsigned char unused, VOID_STAR ap, VOID_STAR bp, int *c)
+{
+ char *a, *b;
+ (void) unused;
+
+ a = *(char **) ap;
+ b = *(char **) bp;
+ if (a != b)
+ {
+ if (a == NULL) *c = -1;
+ else if (b == NULL) *c = 1;
+ else *c = strcmp (a, b);
+ return 0;
+ }
+ *c = 0;
+ return 0;
+}
+
+static int string_to_int (unsigned char a_type, VOID_STAR ap, unsigned int na,
+ unsigned char b_type, VOID_STAR bp)
+{
+ char **s;
+ unsigned int i;
+ int *b;
+
+ (void) a_type;
+ (void) b_type;
+
+ s = (char **) ap;
+ b = (int *) bp;
+ for (i = 0; i < na; i++)
+ {
+ if (s[i] == NULL) b[i] = 0;
+ else b[i] = s[i][0];
+ }
+ return 1;
+}
+
+struct _SLang_Foreach_Context_Type
+{
+ char *string;
+ unsigned int n;
+};
+
+static SLang_Foreach_Context_Type *
+string_foreach_open (unsigned char type, unsigned int num)
+{
+ char *s;
+ SLang_Foreach_Context_Type *c;
+
+ (void) type;
+ if (num != 0)
+ {
+ SLang_verror (SL_NOT_IMPLEMENTED,
+ "'foreach using' form not supported by String_Type");
+ SLdo_pop_n (num + 1);
+ return NULL;
+ }
+ if (-1 == SLang_pop_slstring (&s))
+ return NULL;
+
+ c = (SLang_Foreach_Context_Type *)SLmalloc (sizeof (SLang_Foreach_Context_Type));
+ if (c == NULL)
+ {
+ SLang_free_slstring (s);
+ return NULL;
+ }
+
+ memset ((char *) c, 0, sizeof (SLang_Foreach_Context_Type));
+ c->string = s;
+
+ return c;
+}
+
+static void string_foreach_close (unsigned char type, SLang_Foreach_Context_Type *c)
+{
+ (void) type;
+ if (c == NULL) return;
+ SLang_free_slstring (c->string);
+ SLfree ((char *) c);
+}
+
+static int string_foreach (unsigned char type, SLang_Foreach_Context_Type *c)
+{
+ char ch;
+
+ (void) type;
+ ch = c->string[c->n];
+ if (ch == 0)
+ return 0; /* done */
+
+ c->n += 1;
+
+ if (-1 == SLclass_push_int_obj (SLANG_INT_TYPE, ch))
+ return -1;
+
+ return 1;
+}
+
+int _SLstring_list_push (_SLString_List_Type *p)
+{
+ unsigned int num;
+ int inum;
+ SLang_Array_Type *at;
+ char **buf;
+
+ if ((buf = p->buf) == NULL)
+ return SLang_push_null ();
+
+ num = p->num;
+ inum = (int) num;
+
+ if (num == 0) num++;
+ if (num != p->max_num)
+ {
+ if (NULL == (buf = (char **)SLrealloc ((char *) buf, sizeof (char *) * num)))
+ {
+ _SLstring_list_delete (p);
+ return -1;
+ }
+ p->max_num = num;
+ p->buf = buf;
+ }
+
+ if (NULL == (at = SLang_create_array (SLANG_STRING_TYPE, 0, (VOID_STAR) buf, &inum, 1)))
+ {
+ _SLstring_list_delete (p);
+ return -1;
+ }
+ p->buf = NULL;
+ _SLstring_list_delete (p);
+ return SLang_push_array (at, 1);
+}
+
+int _SLstring_list_init (_SLString_List_Type *p, unsigned int max_num, unsigned int delta_num)
+{
+ if (NULL == (p->buf = (char **) SLmalloc (max_num * sizeof (char *))))
+ return -1;
+
+ p->max_num = max_num;
+ p->num = 0;
+ p->delta_num = delta_num;
+ return 0;
+}
+
+int _SLstring_list_append (_SLString_List_Type *p, char *s)
+{
+ if (s == NULL)
+ {
+ _SLstring_list_delete (p);
+ return -1;
+ }
+
+ if (p->max_num == p->num)
+ {
+ char **b;
+ unsigned int max_num = p->num + p->delta_num;
+ b = (char **)SLrealloc ((char *)p->buf, max_num * sizeof (char *));
+ if (b == NULL)
+ {
+ _SLstring_list_delete (p);
+ SLang_free_slstring (s);
+ return -1;
+ }
+ p->buf = b;
+ p->max_num = max_num;
+ }
+
+ p->buf[p->num] = s;
+ p->num++;
+ return 0;
+}
+
+void _SLstring_list_delete (_SLString_List_Type *p)
+{
+ if (p->buf != NULL)
+ {
+ unsigned int i, imax;
+ char **buf = p->buf;
+ imax = p->num;
+ for (i = 0; i < imax; i++)
+ SLang_free_slstring (buf[i]);
+ SLfree ((char *)buf);
+ p->buf = NULL;
+ }
+}
+
+/* Ref type */
+int SLang_pop_ref (SLang_Ref_Type **ref)
+{
+ return SLclass_pop_ptr_obj (SLANG_REF_TYPE, (VOID_STAR *)ref);
+}
+
+/* Note: This is ok if ptr is NULL. Some routines rely on this behavior */
+int _SLang_push_ref (int is_global, VOID_STAR ptr)
+{
+ SLang_Ref_Type *r;
+
+ if (ptr == NULL)
+ return SLang_push_null ();
+
+ r = (SLang_Ref_Type *) SLmalloc (sizeof (SLang_Ref_Type));
+ if (r == NULL) return -1;
+
+ r->is_global = is_global;
+ r->v.nt = (SLang_Name_Type *) ptr;
+
+ if (-1 == SLclass_push_ptr_obj (SLANG_REF_TYPE, (VOID_STAR) r))
+ {
+ SLfree ((char *) r);
+ return -1;
+ }
+ return 0;
+}
+
+static void ref_destroy (unsigned char type, VOID_STAR ptr)
+{
+ (void) type;
+ SLfree ((char *) *(SLang_Ref_Type **)ptr);
+}
+
+void SLang_free_ref (SLang_Ref_Type *ref)
+{
+ SLfree ((char *) ref);
+}
+
+static int ref_push (unsigned char type, VOID_STAR ptr)
+{
+ SLang_Ref_Type *ref;
+
+ (void) type;
+
+ ref = *(SLang_Ref_Type **) ptr;
+
+ if (ref == NULL)
+ return SLang_push_null ();
+
+ return _SLang_push_ref (ref->is_global, (VOID_STAR) ref->v.nt);
+}
+
+int SLang_assign_to_ref (SLang_Ref_Type *ref, unsigned char type, VOID_STAR v)
+{
+ SLang_Object_Type *stkptr;
+ SLang_Class_Type *cl;
+
+ cl = _SLclass_get_class (type);
+
+ /* Use apush since this function is passing ``array'' bytes rather than the
+ * address of the data. I need to somehow make this more consistent. To
+ * see what I mean, consider:
+ *
+ * double z[2];
+ * char *s = "silly";
+ * int i;
+ *
+ * SLang_assign_to_ref (ref, SLANG_INT_TYPE, &i);
+ * SLang_assign_to_ref (ref, SLANG_STRING_TYPE, &s);
+ * SLang_assign_to_ref (ref, SLANG_COMPLEX_TYPE, z);
+ *
+ * That is, all external routines that take a VOID_STAR argument need to
+ * be documented such that how the function should be called with the
+ * various class_types.
+ */
+ if (-1 == (*cl->cl_apush) (type, v))
+ return -1;
+
+ stkptr = _SLStack_Pointer;
+ if (0 == _SLang_deref_assign (ref))
+ return 0;
+
+ if (stkptr != _SLStack_Pointer)
+ SLdo_pop ();
+
+ return -1;
+}
+
+static char *ref_string (unsigned char type, VOID_STAR ptr)
+{
+ SLang_Ref_Type *ref;
+
+ (void) type;
+ ref = *(SLang_Ref_Type **) ptr;
+ if (ref->is_global)
+ {
+ char *name, *s;
+
+ name = ref->v.nt->name;
+ if ((name != NULL)
+ && (NULL != (s = SLmalloc (strlen(name) + 2))))
+ {
+ *s = '&';
+ strcpy (s + 1, name);
+ return s;
+ }
+
+ return NULL;
+ }
+ return SLmake_string ("Local Variable Reference");
+}
+
+static int ref_dereference (unsigned char unused, VOID_STAR ptr)
+{
+ (void) unused;
+ return _SLang_dereference_ref (*(SLang_Ref_Type **) ptr);
+}
+
+static int ref_cmp (unsigned char type, VOID_STAR a, VOID_STAR b, int *c)
+{
+ SLang_Ref_Type *ra, *rb;
+
+ (void) type;
+
+ ra = *(SLang_Ref_Type **)a;
+ rb = *(SLang_Ref_Type **)b;
+
+ if (ra == NULL)
+ {
+ if (rb == NULL) *c = 0;
+ else *c = -1;
+ return 0;
+ }
+ if (rb == NULL)
+ {
+ *c = 1;
+ return 0;
+ }
+
+ if (ra->v.nt == rb->v.nt)
+ *c = 0;
+ else *c = strcmp (ra->v.nt->name, rb->v.nt->name);
+ return 0;
+}
+
+
+SLang_Name_Type *SLang_pop_function (void)
+{
+ SLang_Ref_Type *ref;
+ SLang_Name_Type *f;
+
+ if (SLang_peek_at_stack () == SLANG_STRING_TYPE)
+ {
+ char *name;
+
+ if (-1 == SLang_pop_slstring (&name))
+ return NULL;
+
+ if (NULL == (f = SLang_get_function (name)))
+ {
+ SLang_verror (SL_UNDEFINED_NAME, "Function %s does not exist", name);
+ SLang_free_slstring (name);
+ return NULL;
+ }
+ SLang_free_slstring (name);
+ return f;
+ }
+
+ if (-1 == SLang_pop_ref (&ref))
+ return NULL;
+
+ f = SLang_get_fun_from_ref (ref);
+ SLang_free_ref (ref);
+ return f;
+}
+
+/* This is a placeholder for version 2 */
+void SLang_free_function (SLang_Name_Type *f)
+{
+ (void) f;
+}
+
+/* NULL type */
+int SLang_push_null (void)
+{
+ return SLclass_push_ptr_obj (SLANG_NULL_TYPE, NULL);
+}
+
+int SLang_pop_null (void)
+{
+ SLang_Object_Type obj;
+ return _SLang_pop_object_of_type (SLANG_NULL_TYPE, &obj, 0);
+}
+
+static int null_push (unsigned char unused, VOID_STAR ptr_unused)
+{
+ (void) unused; (void) ptr_unused;
+ return SLang_push_null ();
+}
+
+static int null_pop (unsigned char type, VOID_STAR ptr)
+{
+ (void) type;
+
+ if (-1 == SLang_pop_null ())
+ return -1;
+
+ *(char **) ptr = NULL;
+ return 0;
+}
+
+/* Implement foreach (NULL) using (whatever) to do nothing. This is useful
+ * because suppose that X is a list but is NULL in some situations. Then
+ * when it is NULL, we want foreach(X) to do nothing.
+ */
+static SLang_Foreach_Context_Type *
+null_foreach_open (unsigned char type, unsigned int num)
+{
+ (void) type;
+ SLdo_pop_n (num + 1);
+ return (SLang_Foreach_Context_Type *)1;
+}
+
+static void null_foreach_close (unsigned char type, SLang_Foreach_Context_Type *c)
+{
+ (void) type;
+ (void) c;
+}
+
+static int null_foreach (unsigned char type, SLang_Foreach_Context_Type *c)
+{
+ (void) type;
+ (void) c;
+ return 0;
+}
+
+static int null_to_bool (unsigned char type, int *t)
+{
+ (void) type;
+ *t = 0;
+ return SLang_pop_null ();
+}
+
+/* AnyType */
+int _SLanytype_typecast (unsigned char a_type, VOID_STAR ap, unsigned int na,
+ unsigned char b_type, VOID_STAR bp)
+{
+ SLang_Class_Type *cl;
+ SLang_Any_Type **any;
+ unsigned int i;
+ unsigned int sizeof_type;
+
+ (void) b_type;
+
+ any = (SLang_Any_Type **) bp;
+
+ cl = _SLclass_get_class (a_type);
+ sizeof_type = cl->cl_sizeof_type;
+
+ for (i = 0; i < na; i++)
+ {
+ if ((-1 == (*cl->cl_apush) (a_type, ap))
+ || (-1 == SLang_pop_anytype (&any[i])))
+ {
+ while (i != 0)
+ {
+ i--;
+ SLang_free_anytype (any[i]);
+ any[i] = NULL;
+ }
+ return -1;
+ }
+ ap = (VOID_STAR)((char *)ap + sizeof_type);
+ }
+
+ return 1;
+}
+
+int SLang_pop_anytype (SLang_Any_Type **any)
+{
+ SLang_Object_Type *obj;
+
+ *any = NULL;
+
+ if (NULL == (obj = (SLang_Object_Type *) SLmalloc (sizeof (SLang_Object_Type))))
+ return -1;
+
+ if (-1 == SLang_pop (obj))
+ {
+ SLfree ((char *) obj);
+ return -1;
+ }
+ *any = (SLang_Any_Type *)obj;
+ return 0;
+}
+
+/* This function will result in an object that is represented by the
+ * anytype object.
+ */
+int SLang_push_anytype (SLang_Any_Type *any)
+{
+ return _SLpush_slang_obj ((SLang_Object_Type *)any);
+}
+
+/* After this call, the stack will contain an Any_Type object */
+static int anytype_push (unsigned char type, VOID_STAR ptr)
+{
+ SLang_Any_Type *obj;
+
+ /* Push the object onto the stack, then pop it back off into our anytype
+ * container. That way, any memory managing associated with the type
+ * will be performed automatically. Another way to think of it is that
+ * pushing an Any_Type onto the stack will create another copy of the
+ * object represented by it.
+ */
+ if (-1 == _SLpush_slang_obj (*(SLang_Object_Type **)ptr))
+ return -1;
+
+ if (-1 == SLang_pop_anytype (&obj))
+ return -1;
+
+ /* There is no need to reference count the anytype objects since every
+ * push results in a new anytype container.
+ */
+ if (-1 == SLclass_push_ptr_obj (type, (VOID_STAR) obj))
+ {
+ SLang_free_anytype (obj);
+ return -1;
+ }
+
+ return 0;
+}
+
+static void anytype_destroy (unsigned char type, VOID_STAR ptr)
+{
+ SLang_Object_Type *obj;
+
+ (void) type;
+ obj = *(SLang_Object_Type **)ptr;
+ SLang_free_object (obj);
+ SLfree ((char *) obj);
+}
+
+void SLang_free_anytype (SLang_Any_Type *any)
+{
+ if (any != NULL)
+ anytype_destroy (SLANG_ANY_TYPE, (VOID_STAR) &any);
+}
+
+static int anytype_dereference (unsigned char unused, VOID_STAR ptr)
+{
+ (void) unused;
+ return _SLpush_slang_obj (*(SLang_Object_Type **) ptr);
+}
+
+/* SLANG_INTP_TYPE */
+static int intp_push (unsigned char unused, VOID_STAR ptr)
+{
+ (void) unused;
+ return SLclass_push_int_obj (SLANG_INT_TYPE, **(int **)ptr);
+}
+
+static int intp_pop (unsigned char unused, VOID_STAR ptr)
+{
+ (void) unused;
+ return SLang_pop_integer (*(int **) ptr);
+}
+
+static int undefined_push (unsigned char t, VOID_STAR p)
+{
+ (void) t; (void) p;
+ if (SLang_Error == 0)
+ SLang_Error = SL_VARIABLE_UNINITIALIZED;
+ return -1;
+}
+
+int _SLregister_types (void)
+{
+ SLang_Class_Type *cl;
+
+ /* A good compiler should optimize this code away. */
+ if ((sizeof(short) != SIZEOF_SHORT)
+ || (sizeof(int) != SIZEOF_INT)
+ || (sizeof(long) != SIZEOF_LONG)
+ || (sizeof(float) != SIZEOF_FLOAT)
+ || (sizeof(double) != SIZEOF_DOUBLE))
+ SLang_exit_error ("S-Lang Library not built properly. Fix SIZEOF_* in config.h and recompile");
+
+ if (-1 == _SLclass_init ())
+ return -1;
+
+ /* Undefined Type */
+ if (NULL == (cl = SLclass_allocate_class ("Undefined_Type")))
+ return -1;
+ (void) SLclass_set_push_function (cl, undefined_push);
+ (void) SLclass_set_pop_function (cl, undefined_push);
+ if (-1 == SLclass_register_class (cl, SLANG_UNDEFINED_TYPE, sizeof (int),
+ SLANG_CLASS_TYPE_SCALAR))
+ return -1;
+ /* Make Void_Type a synonym for Undefined_Type. Note that this does
+ * not mean that Void_Type represents SLANG_VOID_TYPE. Void_Type is
+ * used by array_map to indicate no array is to be created.
+ */
+ if (-1 == SLclass_create_synonym ("Void_Type", SLANG_UNDEFINED_TYPE))
+ return -1;
+
+ if (-1 == _SLarith_register_types ())
+ return -1;
+
+ /* SLANG_INTP_TYPE */
+ if (NULL == (cl = SLclass_allocate_class ("_IntegerP_Type")))
+ return -1;
+ (void) SLclass_set_push_function (cl, intp_push);
+ (void) SLclass_set_pop_function (cl, intp_pop);
+ if (-1 == SLclass_register_class (cl, SLANG_INTP_TYPE, sizeof (int),
+ SLANG_CLASS_TYPE_SCALAR))
+ return -1;
+
+ /* String Type */
+
+ if (NULL == (cl = SLclass_allocate_class ("String_Type")))
+ return -1;
+ (void) SLclass_set_destroy_function (cl, string_destroy);
+ (void) SLclass_set_push_function (cl, string_push);
+ cl->cl_foreach_open = string_foreach_open;
+ cl->cl_foreach_close = string_foreach_close;
+ cl->cl_foreach = string_foreach;
+ cl->cl_cmp = string_cmp;
+ if (-1 == SLclass_register_class (cl, SLANG_STRING_TYPE, sizeof (char *),
+ SLANG_CLASS_TYPE_PTR))
+ return -1;
+
+ /* ref Type */
+ if (NULL == (cl = SLclass_allocate_class ("Ref_Type")))
+ return -1;
+ cl->cl_dereference = ref_dereference;
+ cl->cl_push = ref_push;
+ cl->cl_destroy = ref_destroy;
+ cl->cl_string = ref_string;
+ cl->cl_cmp = ref_cmp;
+ if (-1 == SLclass_register_class (cl, SLANG_REF_TYPE,
+ sizeof (SLang_Ref_Type *),
+ SLANG_CLASS_TYPE_PTR))
+ return -1;
+
+ /* NULL Type */
+
+ if (NULL == (cl = SLclass_allocate_class ("Null_Type")))
+ return -1;
+ cl->cl_push = null_push;
+ cl->cl_pop = null_pop;
+ cl->cl_foreach_open = null_foreach_open;
+ cl->cl_foreach_close = null_foreach_close;
+ cl->cl_foreach = null_foreach;
+ cl->cl_to_bool = null_to_bool;
+ if (-1 == SLclass_register_class (cl, SLANG_NULL_TYPE, sizeof (char *),
+ SLANG_CLASS_TYPE_SCALAR))
+ return -1;
+
+ /* AnyType */
+ if (NULL == (cl = SLclass_allocate_class ("Any_Type")))
+ return -1;
+ (void) SLclass_set_push_function (cl, anytype_push);
+ (void) SLclass_set_destroy_function (cl, anytype_destroy);
+ cl->cl_dereference = anytype_dereference;
+ if (-1 == SLclass_register_class (cl, SLANG_ANY_TYPE, sizeof (VOID_STAR),
+ SLANG_CLASS_TYPE_PTR))
+ return -1;
+
+ if (-1 == _SLang_init_bstring ())
+ return -1;
+
+ if ((-1 == SLclass_add_typecast (SLANG_STRING_TYPE, SLANG_INT_TYPE, string_to_int, 0))
+ || (-1 == SLclass_add_binary_op (SLANG_STRING_TYPE, SLANG_STRING_TYPE, string_string_bin_op, string_string_bin_op_result)))
+ return -1;
+
+ return 0;
+}
+
diff --git a/mdk-stage1/slang/slutty.c b/mdk-stage1/slang/slutty.c
new file mode 100644
index 000000000..636c1bb90
--- /dev/null
+++ b/mdk-stage1/slang/slutty.c
@@ -0,0 +1,596 @@
+/* slutty.c --- Unix Low level terminal (tty) functions for S-Lang */
+/* Copyright (c) 1992, 1999, 2001 John E. Davis
+ * This file is part of the S-Lang library.
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Perl Artistic License.
+ */
+
+#include "slinclud.h"
+
+#include <signal.h>
+/* sequent support thanks to Kenneth Lorber <keni@oasys.dt.navy.mil> */
+/* SYSV (SYSV ISC R3.2 v3.0) provided by iain.lea@erlm.siemens.de */
+
+#if defined (_AIX) && !defined (_ALL_SOURCE)
+# define _ALL_SOURCE /* so NBBY is defined in <sys/types.h> */
+#endif
+
+#include <sys/time.h>
+#include <sys/types.h>
+
+#ifdef SYSV
+# include <fcntl.h>
+# ifndef CRAY
+# include <sys/termio.h>
+# include <sys/stream.h>
+# include <sys/ptem.h>
+# include <sys/tty.h>
+# endif
+#endif
+
+#ifdef __BEOS__
+/* Prototype for select */
+# include <net/socket.h>
+#endif
+
+#include <sys/file.h>
+
+#ifndef sun
+# include <sys/ioctl.h>
+#endif
+
+#ifdef __QNX__
+# include <sys/select.h>
+#endif
+
+#include <sys/stat.h>
+#include <errno.h>
+
+#if defined (_AIX) && !defined (FD_SET)
+# include <sys/select.h> /* for FD_ISSET, FD_SET, FD_ZERO */
+#endif
+
+#ifndef O_RDWR
+# include <fcntl.h>
+#endif
+
+#include "slang.h"
+#include "_slang.h"
+
+int SLang_TT_Read_FD = -1;
+int SLang_TT_Baud_Rate;
+
+#ifdef HAVE_TERMIOS_H
+# if !defined(HAVE_TCGETATTR) || !defined(HAVE_TCSETATTR)
+# undef HAVE_TERMIOS_H
+# endif
+#endif
+
+#ifndef HAVE_TERMIOS_H
+
+# if !defined(CBREAK) && defined(sun)
+# ifndef BSD_COMP
+# define BSD_COMP 1
+# endif
+# include <sys/ioctl.h>
+# endif
+
+typedef struct
+ {
+ struct tchars t;
+ struct ltchars lt;
+ struct sgttyb s;
+ }
+TTY_Termio_Type;
+#else
+# include <termios.h>
+typedef struct termios TTY_Termio_Type;
+#endif
+
+static TTY_Termio_Type Old_TTY;
+
+#ifdef HAVE_TERMIOS_H
+typedef struct
+{
+ unsigned int key;
+ unsigned int value;
+} Baud_Rate_Type;
+
+static Baud_Rate_Type Baud_Rates [] =
+{
+#ifdef B0
+ {B0, 0},
+#endif
+#ifdef B50
+ {B50, 50},
+#endif
+#ifdef B75
+ {B75, 75},
+#endif
+#ifdef B110
+ {B110, 110},
+#endif
+#ifdef B134
+ {B134, 134},
+#endif
+#ifdef B150
+ {B150, 150},
+#endif
+#ifdef B200
+ {B200, 200},
+#endif
+#ifdef B300
+ {B300, 300},
+#endif
+#ifdef B600
+ {B600, 600},
+#endif
+#ifdef B1200
+ {B1200, 1200},
+#endif
+#ifdef B1800
+ {B1800, 1800},
+#endif
+#ifdef B2400
+ {B2400, 2400},
+#endif
+#ifdef B4800
+ {B4800, 4800},
+#endif
+#ifdef B9600
+ {B9600, 9600},
+#endif
+#ifdef B19200
+ {B19200, 19200},
+#endif
+#ifdef B38400
+ {B38400, 38400},
+#endif
+#ifdef B57600
+ {B57600, 57600},
+#endif
+#ifdef B115200
+ {B115200, 115200},
+#endif
+#ifdef B230400
+ {B230400, 230400},
+#endif
+ {0, 0}
+};
+
+static void
+set_baud_rate (TTY_Termio_Type *tty)
+{
+#ifdef HAVE_CFGETOSPEED
+ unsigned int speed;
+ Baud_Rate_Type *b, *bmax;
+
+ if (SLang_TT_Baud_Rate)
+ return; /* already set */
+
+ speed = (unsigned int) cfgetospeed (tty);
+
+ b = Baud_Rates;
+ bmax = b + (sizeof (Baud_Rates)/sizeof(Baud_Rates[0]));
+ while (b < bmax)
+ {
+ if (b->key == speed)
+ {
+ SLang_TT_Baud_Rate = b->value;
+ return;
+ }
+ b++;
+ }
+#else
+ (void) tty;
+#endif
+}
+
+#endif /* HAVE_TERMIOS_H */
+
+#ifdef HAVE_TERMIOS_H
+# define GET_TERMIOS(fd, x) tcgetattr(fd, x)
+# define SET_TERMIOS(fd, x) tcsetattr(fd, TCSADRAIN, x)
+#else
+# ifdef TCGETS
+# define GET_TERMIOS(fd, x) ioctl(fd, TCGETS, x)
+# define SET_TERMIOS(fd, x) ioctl(fd, TCSETS, x)
+# else
+# define X(x,m) &(((TTY_Termio_Type *)(x))->m)
+# define GET_TERMIOS(fd, x) \
+ ((ioctl(fd, TIOCGETC, X(x,t)) || \
+ ioctl(fd, TIOCGLTC, X(x,lt)) || \
+ ioctl(fd, TIOCGETP, X(x,s))) ? -1 : 0)
+# define SET_TERMIOS(fd, x) \
+ ((ioctl(fd, TIOCSETC, X(x,t)) ||\
+ ioctl(fd, TIOCSLTC, X(x,lt)) || \
+ ioctl(fd, TIOCSETP, X(x,s))) ? -1 : 0)
+# endif
+#endif
+
+static int TTY_Inited = 0;
+static int TTY_Open = 0;
+
+#ifdef ultrix /* Ultrix gets _POSIX_VDISABLE wrong! */
+# define NULL_VALUE -1
+#else
+# ifdef _POSIX_VDISABLE
+# define NULL_VALUE _POSIX_VDISABLE
+# else
+# define NULL_VALUE 255
+# endif
+#endif
+
+int SLang_init_tty (int abort_char, int no_flow_control, int opost)
+{
+ TTY_Termio_Type newtty;
+
+ SLsig_block_signals ();
+
+ if (TTY_Inited)
+ {
+ SLsig_unblock_signals ();
+ return 0;
+ }
+
+ TTY_Open = 0;
+
+ if ((SLang_TT_Read_FD == -1)
+ || (1 != isatty (SLang_TT_Read_FD)))
+ {
+#ifdef O_RDWR
+# ifndef __BEOS__ /* I have been told that BEOS will HANG if passed /dev/tty */
+ if ((SLang_TT_Read_FD = open("/dev/tty", O_RDWR)) >= 0)
+ {
+ TTY_Open = 1;
+ }
+# endif
+#endif
+ if (TTY_Open == 0)
+ {
+ SLang_TT_Read_FD = fileno (stderr);
+ if (1 != isatty (SLang_TT_Read_FD))
+ {
+ SLang_TT_Read_FD = fileno (stdin);
+ if (1 != isatty (SLang_TT_Read_FD))
+ {
+ fprintf (stderr, "Failed to open terminal.");
+ return -1;
+ }
+ }
+ }
+ }
+
+ SLang_Abort_Char = abort_char;
+
+ /* Some systems may not permit signals to be blocked. As a result, the
+ * return code must be checked.
+ */
+ while (-1 == GET_TERMIOS(SLang_TT_Read_FD, &Old_TTY))
+ {
+ if (errno != EINTR)
+ {
+ SLsig_unblock_signals ();
+ return -1;
+ }
+ }
+
+ while (-1 == GET_TERMIOS(SLang_TT_Read_FD, &newtty))
+ {
+ if (errno != EINTR)
+ {
+ SLsig_unblock_signals ();
+ return -1;
+ }
+ }
+
+#ifndef HAVE_TERMIOS_H
+ newtty.s.sg_flags &= ~(ECHO);
+ newtty.s.sg_flags &= ~(CRMOD);
+ /* if (Flow_Control == 0) newtty.s.sg_flags &= ~IXON; */
+ newtty.t.t_eofc = 1;
+ if (abort_char == -1) SLang_Abort_Char = newtty.t.t_intrc;
+ newtty.t.t_intrc = SLang_Abort_Char; /* ^G */
+ newtty.t.t_quitc = 255;
+ newtty.lt.t_suspc = 255; /* to ignore ^Z */
+ newtty.lt.t_dsuspc = 255; /* to ignore ^Y */
+ newtty.lt.t_lnextc = 255;
+ newtty.s.sg_flags |= CBREAK; /* do I want cbreak or raw????? */
+#else
+
+ /* get baud rate */
+
+ newtty.c_iflag &= ~(ECHO | INLCR | ICRNL);
+#ifdef ISTRIP
+ /* newtty.c_iflag &= ~ISTRIP; */
+#endif
+ if (opost == 0) newtty.c_oflag &= ~OPOST;
+
+ set_baud_rate (&newtty);
+
+ if (no_flow_control) newtty.c_iflag &= ~IXON; else newtty.c_iflag |= IXON;
+
+ newtty.c_cc[VEOF] = 1;
+ newtty.c_cc[VMIN] = 1;
+ newtty.c_cc[VTIME] = 0;
+ newtty.c_lflag = ISIG | NOFLSH;
+ if (abort_char == -1) SLang_Abort_Char = newtty.c_cc[VINTR];
+ newtty.c_cc[VINTR] = SLang_Abort_Char; /* ^G */
+ newtty.c_cc[VQUIT] = NULL_VALUE;
+ newtty.c_cc[VSUSP] = NULL_VALUE; /* to ignore ^Z */
+#ifdef VDSUSP
+ newtty.c_cc[VDSUSP] = NULL_VALUE; /* to ignore ^Y */
+#endif
+#ifdef VLNEXT
+ newtty.c_cc[VLNEXT] = NULL_VALUE; /* to ignore ^V ? */
+#endif
+#ifdef VSWTCH
+ newtty.c_cc[VSWTCH] = NULL_VALUE; /* to ignore who knows what */
+#endif
+#endif /* NOT HAVE_TERMIOS_H */
+
+ while (-1 == SET_TERMIOS(SLang_TT_Read_FD, &newtty))
+ {
+ if (errno != EINTR)
+ {
+ SLsig_unblock_signals ();
+ return -1;
+ }
+ }
+
+ TTY_Inited = 1;
+ SLsig_unblock_signals ();
+ return 0;
+}
+
+void SLtty_set_suspend_state (int mode)
+{
+ TTY_Termio_Type newtty;
+
+ SLsig_block_signals ();
+
+ if (TTY_Inited == 0)
+ {
+ SLsig_unblock_signals ();
+ return;
+ }
+
+ while ((-1 == GET_TERMIOS (SLang_TT_Read_FD, &newtty))
+ && (errno == EINTR))
+ ;
+
+#ifndef HAVE_TERMIOS_H
+ /* I do not know if all systems define the t_dsuspc field */
+ if (mode == 0)
+ {
+ newtty.lt.t_suspc = 255;
+ newtty.lt.t_dsuspc = 255;
+ }
+ else
+ {
+ newtty.lt.t_suspc = Old_TTY.lt.t_suspc;
+ newtty.lt.t_dsuspc = Old_TTY.lt.t_dsuspc;
+ }
+#else
+ if (mode == 0)
+ {
+ newtty.c_cc[VSUSP] = NULL_VALUE;
+#ifdef VDSUSP
+ newtty.c_cc[VDSUSP] = NULL_VALUE;
+#endif
+ }
+ else
+ {
+ newtty.c_cc[VSUSP] = Old_TTY.c_cc[VSUSP];
+#ifdef VDSUSP
+ newtty.c_cc[VDSUSP] = Old_TTY.c_cc[VDSUSP];
+#endif
+ }
+#endif
+
+ while ((-1 == SET_TERMIOS (SLang_TT_Read_FD, &newtty))
+ && (errno == EINTR))
+ ;
+
+ SLsig_unblock_signals ();
+}
+
+void SLang_reset_tty (void)
+{
+ SLsig_block_signals ();
+
+ if (TTY_Inited == 0)
+ {
+ SLsig_unblock_signals ();
+ return;
+ }
+
+ while ((-1 == SET_TERMIOS(SLang_TT_Read_FD, &Old_TTY))
+ && (errno == EINTR))
+ ;
+
+ if (TTY_Open)
+ {
+ while ((-1 == close (SLang_TT_Read_FD))
+ && (errno == EINTR))
+ ;
+
+ TTY_Open = 0;
+ SLang_TT_Read_FD = -1;
+ }
+
+ TTY_Inited = 0;
+ SLsig_unblock_signals ();
+}
+
+static void default_sigint (int sig)
+{
+ sig = errno; /* use parameter */
+
+ SLKeyBoard_Quit = 1;
+ if (SLang_Ignore_User_Abort == 0) SLang_Error = SL_USER_BREAK;
+ SLsignal_intr (SIGINT, default_sigint);
+ errno = sig;
+}
+
+int SLang_set_abort_signal (void (*hand)(int))
+{
+ int save_errno = errno;
+ SLSig_Fun_Type *f;
+
+ if (hand == NULL) hand = default_sigint;
+ f = SLsignal_intr (SIGINT, hand);
+
+ errno = save_errno;
+
+ if (f == (SLSig_Fun_Type *) SIG_ERR)
+ return -1;
+
+ return 0;
+}
+
+#ifndef FD_SET
+#define FD_SET(fd, tthis) *(tthis) = 1 << (fd)
+#define FD_ZERO(tthis) *(tthis) = 0
+#define FD_ISSET(fd, tthis) (*(tthis) & (1 << fd))
+typedef int fd_set;
+#endif
+
+static fd_set Read_FD_Set;
+
+/* HACK: If > 0, use 1/10 seconds. If < 0, use 1/1000 seconds */
+
+int _SLsys_input_pending(int tsecs)
+{
+ struct timeval wait;
+ long usecs, secs;
+
+ if (TTY_Inited == 0) return -1;
+
+ if (tsecs >= 0)
+ {
+ secs = tsecs / 10;
+ usecs = (tsecs % 10) * 100000;
+ }
+ else
+ {
+ tsecs = -tsecs;
+ secs = tsecs / 1000;
+ usecs = (tsecs % 1000) * 1000;
+ }
+
+ wait.tv_sec = secs;
+ wait.tv_usec = usecs;
+
+ FD_ZERO(&Read_FD_Set);
+ FD_SET(SLang_TT_Read_FD, &Read_FD_Set);
+
+ return select(SLang_TT_Read_FD + 1, &Read_FD_Set, NULL, NULL, &wait);
+}
+
+int (*SLang_getkey_intr_hook) (void);
+
+static int handle_interrupt (void)
+{
+ if (SLang_getkey_intr_hook != NULL)
+ {
+ int save_tty_fd = SLang_TT_Read_FD;
+
+ if (-1 == (*SLang_getkey_intr_hook) ())
+ return -1;
+
+ if (save_tty_fd != SLang_TT_Read_FD)
+ return -1;
+ }
+
+ return 0;
+}
+
+unsigned int _SLsys_getkey (void)
+{
+ unsigned char c;
+
+ if (TTY_Inited == 0)
+ {
+ int ic = fgetc (stdin);
+ if (ic == EOF) return SLANG_GETKEY_ERROR;
+ return (unsigned int) ic;
+ }
+
+ while (1)
+ {
+ int ret;
+
+ if (SLKeyBoard_Quit)
+ return SLang_Abort_Char;
+
+ if (0 == (ret = _SLsys_input_pending (100)))
+ continue;
+
+ if (ret != -1)
+ break;
+
+ if (SLKeyBoard_Quit)
+ return SLang_Abort_Char;
+
+ if (errno == EINTR)
+ {
+ if (-1 == handle_interrupt ())
+ return SLANG_GETKEY_ERROR;
+
+ continue;
+ }
+
+ break; /* let read handle it */
+ }
+
+ while (1)
+ {
+ int status = read(SLang_TT_Read_FD, (char *) &c, 1);
+
+ if (status > 0)
+ break;
+
+ if (status == 0)
+ {
+ /* We are at the end of a file. Let application handle it. */
+ return SLANG_GETKEY_ERROR;
+ }
+
+ if (errno == EINTR)
+ {
+ if (-1 == handle_interrupt ())
+ return SLANG_GETKEY_ERROR;
+
+ if (SLKeyBoard_Quit)
+ return SLang_Abort_Char;
+
+ continue;
+ }
+#ifdef EAGAIN
+ if (errno == EAGAIN)
+ {
+ sleep (1);
+ continue;
+ }
+#endif
+#ifdef EWOULDBLOCK
+ if (errno == EWOULDBLOCK)
+ {
+ sleep (1);
+ continue;
+ }
+#endif
+#ifdef EIO
+ if (errno == EIO)
+ {
+ SLang_exit_error ("_SLsys_getkey: EIO error.");
+ }
+#endif
+ return SLANG_GETKEY_ERROR;
+ }
+
+ return((unsigned int) c);
+}
+
diff --git a/mdk-stage1/slang/slxstrng.c b/mdk-stage1/slang/slxstrng.c
new file mode 100644
index 000000000..3f8a4dffa
--- /dev/null
+++ b/mdk-stage1/slang/slxstrng.c
@@ -0,0 +1,43 @@
+/* Copyright (c) 1992, 1999, 2001 John E. Davis
+ * This file is part of the S-Lang library.
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Perl Artistic License.
+ */
+
+/* These routines are simple and inefficient. They were designed to work on
+ * SunOS when using Electric Fence.
+ */
+
+#include "slang.h"
+#include "_slang.h"
+char *SLstrcpy(register char *aa, register char *b)
+{
+ char *a = aa;
+ while ((*a++ = *b++) != 0);
+ return aa;
+}
+
+int SLstrcmp(register char *a, register char *b)
+{
+ while (*a && (*a == *b))
+ {
+ a++;
+ b++;
+ }
+ if (*a) return((unsigned char) *a - (unsigned char) *b);
+ else if (*b) return ((unsigned char) *a - (unsigned char) *b);
+ else return 0;
+}
+
+char *SLstrncpy(char *a, register char *b,register int n)
+{
+ register char *aa = a;
+ while ((n > 0) && *b)
+ {
+ *aa++ = *b++;
+ n--;
+ }
+ while (n-- > 0) *aa++ = 0;
+ return (a);
+}
diff --git a/mdk-stage1/stage1.c b/mdk-stage1/stage1.c
new file mode 100644
index 000000000..63f9d2ed2
--- /dev/null
+++ b/mdk-stage1/stage1.c
@@ -0,0 +1,463 @@
+/*
+ * Guillaume Cottenceau (was gc@mandrakesoft.com)
+ *
+ * Copyright 2000-2004 Mandrakesoft
+ *
+ *
+ * This software may be freely redistributed under the terms of the GNU
+ * public license.
+ *
+ * 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.
+ *
+ */
+
+/*
+ * Portions from Erik Troan (ewt@redhat.com)
+ *
+ * Copyright 1996 Red Hat Software
+ *
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+#include <stdarg.h>
+#include <signal.h>
+#include <linux/unistd.h>
+
+#include "stage1.h"
+
+#include "log.h"
+#include "probing.h"
+#include "frontend.h"
+#include "modules.h"
+#include "tools.h"
+#include "utils.h"
+#include "automatic.h"
+#include "mount.h"
+#include "thirdparty.h"
+
+#ifdef ENABLE_PCMCIA
+#include "pcmcia/pcmcia.h"
+#endif
+
+#ifndef DISABLE_CDROM
+#include "cdrom.h"
+#endif
+
+#ifndef DISABLE_NETWORK
+#include "network.h"
+#endif
+
+#ifndef DISABLE_DISK
+#include "disk.h"
+#endif
+
+
+/************************************************************
+ * globals */
+
+
+
+void fatal_error(char *msg)
+{
+ printf("FATAL ERROR IN STAGE1: %s\n\nI can't recover from this.\nYou may reboot your system.\n", msg);
+ while (1);
+}
+
+
+/************************************************************
+ * special frontend functs
+ * (the principle is to not pollute frontend code with stage1-specific stuff) */
+
+void stg1_error_message(char *msg, ...)
+{
+ va_list args;
+ va_start(args, msg);
+ unset_automatic();
+ verror_message(msg, args);
+ va_end(args);
+}
+
+void stg1_fatal_message(char *msg, ...)
+{
+ va_list args;
+ va_start(args, msg);
+ unset_automatic();
+ verror_message(msg, args);
+ va_end(args);
+ exit(1);
+}
+
+void stg1_info_message(char *msg, ...)
+{
+ va_list args;
+ va_start(args, msg);
+ if (IS_AUTOMATIC) {
+ vlog_message(msg, args);
+ return;
+ }
+ vinfo_message(msg, args);
+ va_end(args);
+}
+
+
+#ifdef SPAWN_SHELL
+static pid_t shell_pid = 0;
+
+/************************************************************
+ * spawns a shell on console #2 */
+static void spawn_shell(void)
+{
+ int fd;
+ char * shell_name[] = { "/sbin/sh", NULL };
+
+ log_message("spawning a shell");
+
+ if (!IS_TESTING) {
+ fd = open("/dev/tty2", O_RDWR);
+ if (fd == -1) {
+ log_message("cannot open /dev/tty2 -- no shell will be provided");
+ return;
+ }
+ else if (access(shell_name[0], X_OK)) {
+ log_message("cannot open shell - %s doesn't exist", shell_name[0]);
+ return;
+ }
+
+ if (!(shell_pid = fork())) {
+ dup2(fd, 0);
+ dup2(fd, 1);
+ dup2(fd, 2);
+
+ close(fd);
+ setsid();
+ if (ioctl(0, TIOCSCTTY, NULL))
+ log_perror("could not set new controlling tty");
+
+ execv(shell_name[0], shell_name);
+ log_message("execve of %s failed: %s", shell_name[0], strerror(errno));
+ exit(-1);
+ }
+
+ close(fd);
+ }
+}
+#endif
+
+#ifdef SPAWN_INTERACTIVE
+char * interactive_fifo = "/tmp/stage1-fifo";
+static pid_t interactive_pid = 0;
+
+/* spawns my small interactive on console #6 */
+static void spawn_interactive(void)
+{
+ int fd;
+ char * dev = "/dev/tty6";
+
+ printf("spawning my interactive on %s\n", dev);
+
+ if (!IS_TESTING) {
+ fd = open(dev, O_RDWR);
+ if (fd == -1) {
+ printf("cannot open %s -- no interactive\n", dev);
+ return;
+ }
+
+ if (mkfifo(interactive_fifo, O_RDWR)) {
+ printf("cannot create fifo -- no interactive\n");
+ return;
+ }
+
+ if (!(interactive_pid = fork())) {
+ int fif_out;
+
+ dup2(fd, 0);
+ dup2(fd, 1);
+ dup2(fd, 2);
+
+ close(fd);
+ setsid();
+ if (ioctl(0, TIOCSCTTY, NULL))
+ perror("could not set new controlling tty");
+
+ fif_out = open(interactive_fifo, O_WRONLY);
+ printf("Please enter your command (availables: [+,-] [rescue]).\n");
+
+ while (1) {
+ char s[50];
+ int i = 0;
+ printf("? ");
+ fflush(stdout);
+ read(0, &(s[i++]), 1);
+ fcntl(0, F_SETFL, O_NONBLOCK);
+ while (read(0, &(s[i++]), 1) > 0 && i < sizeof(s));
+ fcntl(0, F_SETFL, 0);
+ write(fif_out, s, i-2);
+ printf("Ok.\n");
+ }
+ }
+
+ close(fd);
+ }
+}
+#endif
+
+
+#ifdef ENABLE_PCMCIA
+static void handle_pcmcia(void)
+{
+ char * pcmcia_adapter;
+ if (kernel_version() == 2) {
+ stg1_error_message("We now use kernel pcmcia support and this won't work with a 2.2 kernel.");
+ return;
+ }
+
+ pcmcia_adapter = pcmcia_probe();
+ if (!pcmcia_adapter) {
+ log_message("no pcmcia adapter found");
+ return;
+ }
+ my_insmod("pcmcia_core", ANY_DRIVER_TYPE, NULL, 0);
+ my_insmod(pcmcia_adapter, ANY_DRIVER_TYPE, NULL, 0);
+ /* ds is an alias for pcmcia in recent 2.6 kernels
+ but we don't have modules.alias in install, so try to load both */
+ my_insmod("ds", ANY_DRIVER_TYPE, NULL, 0);
+ my_insmod("pcmcia", ANY_DRIVER_TYPE, NULL, 0);
+
+ /* setup a dynamic resource database for non statically mapped PCMCIA sockets */
+ pcmcia_socket_startup(-1);
+
+ add_to_env("PCMCIA", pcmcia_adapter);
+}
+#endif
+
+
+/************************************************************
+ */
+
+#ifndef ENABLE_NETWORK_STANDALONE
+static void method_select_and_prepare(void)
+{
+ enum return_type results;
+ char * choice;
+ char * means[10], * means_auto[10];
+ int i;
+
+#ifndef DISABLE_DISK
+ char * disk_install = "Hard disk"; char * disk_install_auto = "disk";
+#endif
+#ifndef DISABLE_CDROM
+ char * cdrom_install = "CDROM drive"; char * cdrom_install_auto = "cdrom";
+#endif
+#ifndef DISABLE_NETWORK
+ char * network_nfs_install = "NFS server"; char * network_nfs_install_auto = "nfs";
+ char * network_ftp_install = "FTP server"; char * network_ftp_install_auto = "ftp";
+ char * network_http_install = "HTTP server"; char * network_http_install_auto = "http";
+#ifndef DISABLE_KA
+ char * network_ka_install = "KA server"; char * network_ka_install_auto = "ka";
+#endif
+#endif
+ char * thirdparty_install = "Load third party modules"; char * thirdparty_install_auto = "thirdparty";
+
+ i = 0;
+#ifndef DISABLE_NETWORK
+ means[i] = network_nfs_install; means_auto[i++] = network_nfs_install_auto;
+ means[i] = network_ftp_install; means_auto[i++] = network_ftp_install_auto;
+ means[i] = network_http_install; means_auto[i++] = network_http_install_auto;
+#ifndef DISABLE_KA
+ means[i] = network_ka_install; means_auto[i++] = network_ka_install_auto;
+#endif
+#endif
+#ifndef DISABLE_CDROM
+ means[i] = cdrom_install; means_auto[i++] = cdrom_install_auto;
+#endif
+#ifndef DISABLE_DISK
+ means[i] = disk_install; means_auto[i++] = disk_install_auto;
+#endif
+ means[i] = thirdparty_install; means_auto[i++] = thirdparty_install_auto;
+ means[i] = NULL;
+
+ unlink(IMAGE_LOCATION);
+
+ results = ask_from_list_auto("Please choose the installation method.", means, &choice, "method", means_auto);
+
+ if (results != RETURN_OK)
+ return method_select_and_prepare();
+
+#ifndef DISABLE_CDROM
+ if (!strcmp(choice, cdrom_install))
+ results = cdrom_prepare();
+#endif
+
+#ifndef DISABLE_DISK
+ if (!strcmp(choice, disk_install))
+ results = disk_prepare();
+#endif
+
+#ifndef DISABLE_NETWORK
+ if (!strcmp(choice, network_nfs_install))
+ results = nfs_prepare();
+
+ if (!strcmp(choice, network_ftp_install))
+ results = ftp_prepare();
+
+ if (!strcmp(choice, network_http_install))
+ results = http_prepare();
+
+#ifndef DISABLE_KA
+ if (!strcmp(choice, network_ka_install))
+ results = ka_prepare();
+#endif
+#endif
+
+ if (!strcmp(choice, thirdparty_install)) {
+ thirdparty_load_modules();
+ return method_select_and_prepare();
+ }
+
+ if (results != RETURN_OK)
+ return method_select_and_prepare();
+
+ /* try to find third party modules on the install media */
+ thirdparty_load_media_modules();
+}
+#endif
+
+static enum return_type create_initial_fs_symlinks(char* symlinks)
+{
+ FILE *f;
+ char buf[5000];
+
+ if (scall(!(f = fopen(symlinks, "rb")), "fopen"))
+ return RETURN_ERROR;
+ while (fgets(buf, sizeof(buf), f)) {
+ char oldpath[500], newpath[500];
+ buf[strlen(buf)-1] = '\0'; // trim \n
+ if (sscanf(buf, "%s %s", oldpath, newpath) != 2) {
+ sprintf(oldpath, "%s%s", STAGE2_LOCATION, buf);
+ sprintf(newpath, "%s", buf);
+ }
+ recursiveRemove_if_it_exists(newpath);
+ log_message("creating symlink %s -> %s", oldpath, newpath);
+ if (scall(symlink(oldpath, newpath), "symlink"))
+ return RETURN_ERROR;
+ }
+ fclose(f);
+ return RETURN_OK;
+}
+
+void finish_preparing(void)
+{
+ recursiveRemove("/init");
+
+ if (create_initial_fs_symlinks(STAGE2_LOCATION "/usr/share/symlinks") != RETURN_OK)
+ stg1_fatal_message("Fatal error finishing initialization.");
+
+ /* /tmp/syslog is used by the second init, so it must be copied now, not in stage2 */
+ /* we remove it to ensure the old one is not copied over it in stage2 */
+
+#ifdef SPAWN_SHELL
+ if (shell_pid != 0) {
+ int fd;
+ const char *clear = "\033[H\033[J";
+ kill(shell_pid, 9);
+ log_message("killed shell");
+ fd = open("/dev/tty2", O_RDWR);
+ write(fd, clear, strlen(clear));
+ close(fd);
+ }
+#endif
+}
+
+int main(int argc __attribute__ ((unused)), char **argv __attribute__ ((unused)), char **env)
+{
+#ifdef ENABLE_NETWORK_STANDALONE
+ open_log();
+ init_frontend("");
+
+ unlink("/etc/resolv.conf"); /* otherwise it is read-only */
+ set_param(MODE_AUTOMATIC);
+ grab_automatic_params("network:dhcp");
+
+ intf_select_and_up();
+ finish_frontend();
+ return 0;
+#else
+ if (getenv("DEBUGSTAGE1")) {
+ set_param(MODE_DEBUGSTAGE1);
+ set_param(MODE_TESTING);
+ }
+
+#ifdef SPAWN_INTERACTIVE
+ spawn_interactive();
+#endif
+
+ open_log();
+ log_message("welcome to the " DISTRIB_NAME " install (mdk-stage1, version " DISTRIB_VERSION " built " __DATE__ " " __TIME__")");
+ process_cmdline();
+#ifdef SPAWN_SHELL
+ spawn_shell();
+#endif
+ init_modules_insmoding();
+ init_firmware_timeout();
+ init_frontend("Welcome to " DISTRIB_DESCR ", " __DATE__ " " __TIME__);
+
+ probe_that_type(VIRTIO_DEVICES, BUS_ANY);
+
+ /* load usb interface as soon as possible, helps usb mouse detection in stage2 */
+ probe_that_type(USB_CONTROLLERS, BUS_USB);
+
+ if (IS_THIRDPARTY)
+ thirdparty_load_modules();
+
+#ifdef ENABLE_PCMCIA
+ if (!IS_NOAUTO)
+ handle_pcmcia();
+#endif
+
+ if (IS_CHANGEDISK)
+ stg1_info_message("You are starting the installation with an alternate booting method. "
+ "Please change your disk, and insert the Installation disk.");
+
+ if (IS_RESCUE && total_memory() < MEM_LIMIT_RESCUE) {
+ stg1_error_message("You are starting the rescue with a low memory configuration. "
+ "Our experience shows that your system may crash at any point "
+ "or lock up for no apparent reason. Continue at "
+ "your own risk. Alternatively, you may reboot your system now.");
+ }
+
+ method_select_and_prepare();
+
+ thirdparty_destroy();
+
+ if (access(STAGE2_LOCATION, R_OK) != 0)
+ if (symlink(IMAGE_LOCATION_REL "/" LIVE_LOCATION_REL, STAGE2_LOCATION) != 0)
+ log_perror("symlink from " IMAGE_LOCATION_REL "/" LIVE_LOCATION_REL " to " STAGE2_LOCATION " failed");
+
+#ifdef SPAWN_INTERACTIVE
+ if (interactive_pid != 0)
+ kill(interactive_pid, 9);
+#endif
+
+ finish_preparing();
+
+ finish_frontend();
+ close_log();
+
+ if (IS_RESCUE)
+ return 66; /* ask init to exec new init */
+ else
+ return 0x35; /* ask init to run stage2 binary */
+#endif
+}
diff --git a/mdk-stage1/stage1.h b/mdk-stage1/stage1.h
new file mode 100644
index 000000000..f21c6ab07
--- /dev/null
+++ b/mdk-stage1/stage1.h
@@ -0,0 +1,62 @@
+/*
+ * Guillaume Cottenceau (gc@mandrakesoft.com)
+ *
+ * Copyright 2000 Mandrakesoft
+ *
+ * This software may be freely redistributed under the terms of the GNU
+ * public license.
+ *
+ * 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.
+ *
+ */
+
+/*
+ * Portions from Erik Troan (ewt@redhat.com)
+ *
+ * Copyright 1996 Red Hat Software
+ *
+ */
+
+#ifndef _STAGE1_H_
+#define _STAGE1_H_
+
+#include "config-stage1.h"
+#include "params.h"
+
+
+/* Some global stuff */
+
+extern char * interactive_fifo;
+
+#define MODE_TESTING (1 << 0)
+#define MODE_RESCUE (1 << 3)
+#define MODE_AUTOMATIC (1 << 4)
+#define MODE_KEEP_MOUNTED (1 << 5) /* for rescue */
+#define MODE_DEBUGSTAGE1 (1 << 6)
+#define MODE_RAMDISK (1 << 9)
+#define MODE_CHANGEDISK (1 << 10)
+#define MODE_THIRDPARTY (1 << 11)
+#define MODE_NOAUTO (1 << 12)
+#define MODE_NETAUTO (1 << 13)
+#define MODE_RECOVERY (1 << 14)
+
+#define IS_TESTING (get_param(MODE_TESTING))
+#define IS_RESCUE (get_param(MODE_RESCUE))
+#define IS_AUTOMATIC (get_param(MODE_AUTOMATIC))
+#define IS_DEBUGSTAGE1 (get_param(MODE_DEBUGSTAGE1))
+#define IS_CHANGEDISK (get_param(MODE_CHANGEDISK))
+#define IS_THIRDPARTY (get_param(MODE_THIRDPARTY))
+#define IS_NOAUTO (get_param(MODE_NOAUTO))
+#define IS_NETAUTO (get_param(MODE_NETAUTO))
+#define IS_RECOVERY (get_param(MODE_RECOVERY))
+#define KEEP_MOUNTED (!IS_RESCUE || get_param(MODE_KEEP_MOUNTED))
+
+void fatal_error(char *msg) __attribute__ ((noreturn));
+
+
+void stg1_error_message(char *msg, ...) __attribute__ ((format (printf, 1, 2)));
+void stg1_info_message(char *msg, ...) __attribute__ ((format (printf, 1, 2)));
+
+#endif
diff --git a/mdk-stage1/stdio-frontend.c b/mdk-stage1/stdio-frontend.c
new file mode 100644
index 000000000..bf6d5abfc
--- /dev/null
+++ b/mdk-stage1/stdio-frontend.c
@@ -0,0 +1,357 @@
+/*
+ * Guillaume Cottenceau (gc@mandrakesoft.com)
+ *
+ * Copyright 2000 Mandrakesoft
+ *
+ * This software may be freely redistributed under the terms of the GNU
+ * public license.
+ *
+ * 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.
+ *
+ */
+
+
+/*
+ * Each different frontend must implement all functions defined in frontend.h
+ */
+
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <termios.h>
+
+#include <probing.h>
+
+#include "frontend.h"
+#include "utils.h"
+
+void init_frontend(char * welcome_msg)
+{
+ printf(welcome_msg);
+ printf("\n");
+}
+
+
+void finish_frontend(void)
+{
+}
+
+static void get_any_response(void)
+{
+ unsigned char t;
+ printf("\n\t(press <enter> to proceed)");
+ fflush(stdout);
+ read(0, &t, 1);
+ fcntl(0, F_SETFL, O_NONBLOCK);
+ while (read(0, &t, 1) > 0);
+ fcntl(0, F_SETFL, 0);
+}
+
+static int get_int_response(void)
+{
+ char s[50];
+ int j = 0;
+ unsigned int i = 0; /* (0) tied to Cancel */
+ fflush(stdout);
+ read(0, &(s[i++]), 1);
+ fcntl(0, F_SETFL, O_NONBLOCK);
+ do {
+ int v = s[i-1];
+ if (v >= '0' && v <= '9')
+ j = j*10 + (v - '0');
+ } while (read(0, &(s[i++]), 1) > 0 && i < sizeof(s));
+ fcntl(0, F_SETFL, 0);
+ return j;
+}
+
+static char * get_string_response(char * initial_string)
+{
+ /* I won't use a scanf/%s since I also want the null string to be accepted -- also, I want the initial_string */
+ char s[500];
+ int i = 0;
+ char buf[10];
+ int b_index = 0;
+ char b;
+
+ struct termios t;
+
+ memset(s, '\0', sizeof(s));
+
+ if (initial_string) {
+ printf(initial_string);
+ strcpy(s, initial_string);
+ i = strlen(s);
+ }
+
+ /* from ncurses/tinfo/lib_raw.c:(cbreak) */
+ tcgetattr(0, &t);
+ t.c_lflag &= ~ICANON;
+ t.c_lflag |= ISIG;
+ t.c_lflag &= ~ECHO;
+ t.c_iflag &= ~ICRNL;
+ t.c_cc[VMIN] = 1;
+ t.c_cc[VTIME] = 0;
+ tcsetattr(0, TCSADRAIN, &t);
+
+ fflush(stdout);
+
+ fcntl(0, F_SETFL, O_NONBLOCK);
+
+ while (1) {
+ if (read(0, &b, 1) > 0) {
+ if (b_index == 1) {
+ if (b == 91) {
+ buf[b_index] = b;
+ b_index++;
+ continue;
+ }
+ else
+ b_index = 0;
+ }
+ if (b_index == 2) {
+ if (b == 67) {
+ if (s[i] != '\0') {
+ printf("\033[C");
+ i++;
+ }
+ }
+ if (b == 68) {
+ if (i > 0) {
+ printf("\033[D");
+ i--;
+ }
+ }
+ b_index = 0;
+ continue;
+ }
+
+ if (b == 13)
+ break;
+ if (b == 127) {
+ if (i > 0) {
+ printf("\033[D");
+ printf(" ");
+ printf("\033[D");
+ if (s[i] == '\0')
+ s[i-1] = '\0';
+ else
+ s[i-1] = ' ';
+ i--;
+ }
+ } else if (b == 27) {
+ buf[b_index] = b;
+ b_index++;
+ } else {
+ printf("%c", b);
+ s[i] = b;
+ i++;
+ }
+ }
+ }
+
+ t.c_lflag |= ICANON;
+ t.c_lflag |= ECHO;
+ t.c_iflag |= ICRNL;
+ tcsetattr(0, TCSADRAIN, &t);
+
+ fcntl(0, F_SETFL, 0);
+
+ printf("\n");
+ return strdup(s);
+}
+
+static void blocking_msg(char *type, char *fmt, va_list ap)
+{
+ printf(type);
+ vprintf(fmt, ap);
+ get_any_response();
+}
+
+void verror_message(char *msg, va_list ap)
+{
+ blocking_msg("> Error! ", msg, ap);
+}
+
+void vinfo_message(char *msg, va_list ap)
+{
+ blocking_msg("> Notice: ", msg, ap);
+}
+
+void vwait_message(char *msg, va_list ap)
+{
+ printf("Please wait: ");
+ vprintf(msg, ap);
+ fflush(stdout);
+}
+
+void remove_wait_message(void)
+{
+ printf("\n");
+}
+
+
+static int size_progress;
+static int actually_drawn;
+#define PROGRESS_SIZE 45
+void init_progression_raw(char *msg, int size)
+{
+ int i;
+ size_progress = size;
+ printf("%s ", msg);
+ if (size) {
+ actually_drawn = 0;
+ for (i=0; i<PROGRESS_SIZE; i++)
+ printf(".");
+ printf("]\033[G%s [", msg); /* only works on ANSI-compatibles */
+ fflush(stdout);
+ } else
+ printf("\n");
+}
+
+void update_progression_raw(int current_size)
+{
+ if (size_progress) {
+ if (current_size > size_progress)
+ current_size = size_progress;
+ while ((int)((current_size*PROGRESS_SIZE)/size_progress) > actually_drawn) {
+ printf("*");
+ actually_drawn++;
+ }
+ } else
+ printf("\033[GStatus: [%8d] bytes loaded...", current_size);
+
+ fflush(stdout);
+}
+
+void end_progression_raw(void)
+{
+ if (size_progress) {
+ update_progression_raw(size_progress);
+ printf("]\n");
+ } else
+ printf(" done.\n");
+}
+
+
+enum return_type ask_from_list_index(char *msg, char ** elems, char ** elems_comments, int *answer)
+{
+ int justify_number = 1;
+ void print_choice_number(int i) {
+ char tmp[500];
+ snprintf(tmp, sizeof(tmp), "[%%%dd]", justify_number);
+ printf(tmp, i);
+ }
+ int i = 1;
+ int j = 0;
+
+ if (string_array_length(elems) >= 10)
+ justify_number = 2;
+
+ i = 1;
+
+ printf("> %s\n", msg);
+ print_choice_number(0);
+ printf(" Cancel");
+
+ while (elems && *elems) {
+ if (elems_comments && *elems_comments) {
+ printf("\n");
+ print_choice_number(i);
+ printf(" %s (%s)", *elems, *elems_comments);
+ j = 0;
+ } else {
+ if (j == 0)
+ printf("\n");
+ print_choice_number(i);
+ printf(" %-14s ", *elems);
+ j++;
+ }
+ if (j == 4)
+ j = 0;
+
+ if (elems_comments)
+ elems_comments++;
+ i++;
+ elems++;
+ }
+
+ printf("\n? ");
+
+ j = get_int_response();
+
+ if (j == 0)
+ return RETURN_BACK;
+
+ if (j >= 1 && j <= i) {
+ *answer = j - 1;
+ return RETURN_OK;
+ }
+
+ return RETURN_ERROR;
+}
+
+
+enum return_type ask_yes_no(char *msg)
+{
+ int j;
+
+ printf("> %s\n[0] Yes [1] No [2] Back\n? ", msg);
+
+ j = get_int_response();
+
+ if (j == 0)
+ return RETURN_OK;
+ else if (j == 2)
+ return RETURN_BACK;
+ else return RETURN_ERROR;
+}
+
+
+enum return_type ask_from_entries(char *msg, char ** questions, char *** answers, int entry_size UNUSED, void (*callback_func)(char ** strings) UNUSED)
+{
+ int j, i = 0;
+ char ** already_answers = NULL;
+
+ printf("> %s\n", msg);
+
+ while (questions && *questions) {
+ printf("(%c) %s\n", i + 'a', *questions);
+ i++;
+ questions++;
+ }
+
+ if (*answers == NULL)
+ *answers = (char **) malloc(sizeof(char *) * i);
+ else
+ already_answers = *answers;
+
+ while (1) {
+ int r;
+ for (j = 0 ; j < i ; j++) {
+ printf("(%c) ? ", j + 'a');
+ if (already_answers && *already_answers) {
+ (*answers)[j] = get_string_response(*already_answers);
+ already_answers++;
+ } else
+ (*answers)[j] = get_string_response(NULL);
+
+ }
+ printf("[0] Cancel [1] Accept [2] Re-enter answers\n? ");
+ r = get_int_response();
+ if (r == 0)
+ return RETURN_BACK;
+ if (r == 1)
+ return RETURN_OK;
+ }
+}
+
+
+void suspend_to_console(void) {}
+void resume_from_suspend(void) {}
diff --git a/mdk-stage1/sysfs/Makefile b/mdk-stage1/sysfs/Makefile
new file mode 100644
index 000000000..5cab07408
--- /dev/null
+++ b/mdk-stage1/sysfs/Makefile
@@ -0,0 +1,39 @@
+ #******************************************************************************
+ #
+ # Guillaume Cottenceau (gc@mandrakesoft.com)
+ # Olivier Blin (blino@mandriva.com)
+ #
+ # Copyright 2006 Mandriva
+ #
+ # This software may be freely redistributed under the terms of the GNU
+ # public license.
+ #
+ # 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.
+ #
+ #*****************************************************************************
+
+# minimal sysfs library ripped from sysfsutils-2.0.0
+
+top_dir = ..
+
+include $(top_dir)/Makefile.common
+
+TARGET = libsysfs.a
+
+all: $(TARGET)
+
+clean:
+ rm -f *.o $(TARGET)
+
+FLAGS = -D__linux__ -Wall -Werror -Wno-deprecated-declarations -Os -fomit-frame-pointer -pipe -c -I.. -D_BSD_SOURCE
+
+OBJS = sysfs_attr.o sysfs_utils.o
+
+$(TARGET): $(OBJS)
+ ar -cru $@ $^
+ ranlib $@
+
+$(OBJS): %.o: %.c
+ $(DIET) gcc $(FLAGS) $(INCLUDES) -c $< -o $@
diff --git a/mdk-stage1/sysfs/libsysfs.h b/mdk-stage1/sysfs/libsysfs.h
new file mode 100644
index 000000000..7bdf54fea
--- /dev/null
+++ b/mdk-stage1/sysfs/libsysfs.h
@@ -0,0 +1,90 @@
+/*
+ * libsysfs.h
+ *
+ * Header Definitions for libsysfs
+ *
+ * Copyright (C) IBM Corp. 2004-2005
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+#ifndef _LIBSYSFS_H_
+#define _LIBSYSFS_H_
+
+#include <sys/types.h>
+#include <string.h>
+
+#define SYSFS_FSTYPE_NAME "sysfs"
+#define SYSFS_PROC_MNTS "/proc/mounts"
+#define SYSFS_BUS_NAME "bus"
+#define SYSFS_CLASS_NAME "class"
+#define SYSFS_BLOCK_NAME "block"
+#define SYSFS_DEVICES_NAME "devices"
+#define SYSFS_DRIVERS_NAME "drivers"
+#define SYSFS_MODULE_NAME "module"
+#define SYSFS_NAME_ATTRIBUTE "name"
+#define SYSFS_MOD_PARM_NAME "parameters"
+#define SYSFS_MOD_SECT_NAME "sections"
+#define SYSFS_UNKNOWN "unknown"
+#define SYSFS_PATH_ENV "SYSFS_PATH"
+
+#define SYSFS_PATH_MAX 256
+#define SYSFS_NAME_LEN 64
+#define SYSFS_BUS_ID_SIZE 32
+
+/* mount path for sysfs, can be overridden by exporting SYSFS_PATH */
+#define SYSFS_MNT_PATH "/sys"
+
+enum sysfs_attribute_method {
+ SYSFS_METHOD_SHOW = 0x01, /* attr can be read by user */
+ SYSFS_METHOD_STORE = 0x02, /* attr can be changed by user */
+};
+
+/*
+ * NOTE:
+ * 1. We have the statically allocated "name" as the first element of all
+ * the structures. This feature is used in the "sorter" function for dlists
+ * 2. As is the case with attrlist
+ * 3. As is the case with path
+ */
+struct sysfs_attribute {
+ char name[SYSFS_NAME_LEN];
+ char path[SYSFS_PATH_MAX];
+ char *value;
+ unsigned short len; /* value length */
+ enum sysfs_attribute_method method; /* show and store */
+};
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Function Prototypes
+ */
+extern int sysfs_get_name_from_path(const char *path, char *name, size_t len);
+
+/* sysfs directory and file access */
+extern void sysfs_close_attribute(struct sysfs_attribute *sysattr);
+extern struct sysfs_attribute *sysfs_open_attribute(const char *path);
+extern int sysfs_read_attribute(struct sysfs_attribute *sysattr);
+extern int sysfs_write_attribute(struct sysfs_attribute *sysattr,
+ const char *new_value, size_t len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBSYSFS_H_ */
diff --git a/mdk-stage1/sysfs/sysfs.h b/mdk-stage1/sysfs/sysfs.h
new file mode 100644
index 000000000..76754a421
--- /dev/null
+++ b/mdk-stage1/sysfs/sysfs.h
@@ -0,0 +1,64 @@
+/*
+ * sysfs.h
+ *
+ * Internal Header Definitions for libsysfs
+ *
+ * Copyright (C) IBM Corp. 2003-2005
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+#ifndef _SYSFS_H_
+#define _SYSFS_H_
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <ctype.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#define safestrcpy(to, from) strncpy(to, from, sizeof(to)-1)
+#define safestrcat(to, from) strncat(to, from, sizeof(to) - strlen(to)-1)
+
+#define safestrcpymax(to, from, max) \
+do { \
+ to[max-1] = '\0'; \
+ strncpy(to, from, max-1); \
+} while (0)
+
+#define safestrcatmax(to, from, max) \
+do { \
+ to[max-1] = '\0'; \
+ strncat(to, from, max - strlen(to)-1); \
+} while (0)
+
+extern struct sysfs_attribute *get_attribute(void *dev, const char *name);
+extern struct dlist *read_dir_subdirs(const char *path);
+extern struct dlist *read_dir_links(const char *path);
+extern struct dlist *get_dev_attributes_list(void *dev);
+extern struct dlist *get_attributes_list(struct dlist *alist, const char *path);
+
+/* Debugging */
+#ifdef DEBUG
+#define dprintf(format, arg...) fprintf(stderr, format, ## arg)
+#else
+#define dprintf(format, arg...) do { } while (0)
+#endif
+
+#endif /* _SYSFS_H_ */
diff --git a/mdk-stage1/sysfs/sysfs_attr.c b/mdk-stage1/sysfs/sysfs_attr.c
new file mode 100644
index 000000000..6d6771188
--- /dev/null
+++ b/mdk-stage1/sysfs/sysfs_attr.c
@@ -0,0 +1,241 @@
+/*
+ * sysfs_dir.c
+ *
+ * Directory utility functions for libsysfs
+ *
+ * Copyright (C) IBM Corp. 2003-2005
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+#include "libsysfs.h"
+#include "sysfs.h"
+
+/**
+ * sysfs_close_attribute: closes and cleans up attribute
+ * @sysattr: attribute to close.
+ */
+void sysfs_close_attribute(struct sysfs_attribute *sysattr)
+{
+ if (sysattr) {
+ if (sysattr->value)
+ free(sysattr->value);
+ free(sysattr);
+ }
+}
+
+/**
+ * alloc_attribute: allocates and initializes attribute structure
+ * returns struct sysfs_attribute with success and NULL with error.
+ */
+static struct sysfs_attribute *alloc_attribute(void)
+{
+ return (struct sysfs_attribute *)
+ calloc(1, sizeof(struct sysfs_attribute));
+}
+
+/**
+ * sysfs_open_attribute: creates sysfs_attribute structure
+ * @path: path to attribute.
+ * returns sysfs_attribute struct with success and NULL with error.
+ */
+struct sysfs_attribute *sysfs_open_attribute(const char *path)
+{
+ struct sysfs_attribute *sysattr = NULL;
+ struct stat fileinfo;
+
+ if (!path) {
+ errno = EINVAL;
+ return NULL;
+ }
+ sysattr = alloc_attribute();
+ if (!sysattr) {
+ dprintf("Error allocating attribute at %s\n", path);
+ return NULL;
+ }
+ if (sysfs_get_name_from_path(path, sysattr->name,
+ SYSFS_NAME_LEN) != 0) {
+ dprintf("Error retrieving attrib name from path: %s\n", path);
+ sysfs_close_attribute(sysattr);
+ return NULL;
+ }
+ safestrcpy(sysattr->path, path);
+ if ((stat(sysattr->path, &fileinfo)) != 0) {
+ dprintf("Stat failed: No such attribute?\n");
+ sysattr->method = 0;
+ free(sysattr);
+ sysattr = NULL;
+ } else {
+ if (fileinfo.st_mode & S_IRUSR)
+ sysattr->method |= SYSFS_METHOD_SHOW;
+ if (fileinfo.st_mode & S_IWUSR)
+ sysattr->method |= SYSFS_METHOD_STORE;
+ }
+
+ return sysattr;
+}
+
+/**
+ * sysfs_read_attribute: reads value from attribute
+ * @sysattr: attribute to read
+ * returns 0 with success and -1 with error.
+ */
+int sysfs_read_attribute(struct sysfs_attribute *sysattr)
+{
+ char *fbuf = NULL;
+ char *vbuf = NULL;
+ ssize_t length = 0;
+ long pgsize = 0;
+ int fd;
+
+ if (!sysattr) {
+ errno = EINVAL;
+ return -1;
+ }
+ if (!(sysattr->method & SYSFS_METHOD_SHOW)) {
+ dprintf("Show method not supported for attribute %s\n",
+ sysattr->path);
+ errno = EACCES;
+ return -1;
+ }
+ pgsize = getpagesize();
+ fbuf = (char *)calloc(1, pgsize+1);
+ if (!fbuf) {
+ dprintf("calloc failed\n");
+ return -1;
+ }
+ if ((fd = open(sysattr->path, O_RDONLY)) < 0) {
+ dprintf("Error reading attribute %s\n", sysattr->path);
+ free(fbuf);
+ return -1;
+ }
+ length = read(fd, fbuf, pgsize);
+ if (length < 0) {
+ dprintf("Error reading from attribute %s\n", sysattr->path);
+ close(fd);
+ free(fbuf);
+ return -1;
+ }
+ if (sysattr->len > 0) {
+ if ((sysattr->len == length) &&
+ (!(strncmp(sysattr->value, fbuf, length)))) {
+ close(fd);
+ free(fbuf);
+ return 0;
+ }
+ free(sysattr->value);
+ }
+ sysattr->len = length;
+ close(fd);
+ vbuf = (char *)realloc(fbuf, length+1);
+ if (!vbuf) {
+ dprintf("realloc failed\n");
+ free(fbuf);
+ return -1;
+ }
+ sysattr->value = vbuf;
+
+ return 0;
+}
+
+/**
+ * sysfs_write_attribute: write value to the attribute
+ * @sysattr: attribute to write
+ * @new_value: value to write
+ * @len: length of "new_value"
+ * returns 0 with success and -1 with error.
+ */
+int sysfs_write_attribute(struct sysfs_attribute *sysattr,
+ const char *new_value, size_t len)
+{
+ int fd;
+ int length;
+
+ if (!sysattr || !new_value || len == 0) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (!(sysattr->method & SYSFS_METHOD_STORE)) {
+ dprintf ("Store method not supported for attribute %s\n",
+ sysattr->path);
+ errno = EACCES;
+ return -1;
+ }
+ if (sysattr->method & SYSFS_METHOD_SHOW) {
+ /*
+ * read attribute again to see if we can get an updated value
+ */
+ if ((sysfs_read_attribute(sysattr))) {
+ dprintf("Error reading attribute\n");
+ return -1;
+ }
+ if ((strncmp(sysattr->value, new_value, sysattr->len)) == 0 &&
+ (len == sysattr->len)) {
+ dprintf("Attr %s already has the requested value %s\n",
+ sysattr->name, new_value);
+ return 0;
+ }
+ }
+ /*
+ * open O_WRONLY since some attributes have no "read" but only
+ * "write" permission
+ */
+ if ((fd = open(sysattr->path, O_WRONLY)) < 0) {
+ dprintf("Error reading attribute %s\n", sysattr->path);
+ return -1;
+ }
+
+ length = write(fd, new_value, len);
+ if (length < 0) {
+ dprintf("Error writing to the attribute %s - invalid value?\n",
+ sysattr->name);
+ close(fd);
+ return -1;
+ } else if ((unsigned int)length != len) {
+ dprintf("Could not write %zd bytes to attribute %s\n",
+ len, sysattr->name);
+ /*
+ * since we could not write user supplied number of bytes,
+ * restore the old value if one available
+ */
+ if (sysattr->method & SYSFS_METHOD_SHOW) {
+ length = write(fd, sysattr->value, sysattr->len);
+ close(fd);
+ return -1;
+ }
+ }
+
+ /*
+ * Validate length that has been copied. Alloc appropriate area
+ * in sysfs_attribute. Verify first if the attribute supports reading
+ * (show method). If it does not, do not bother
+ */
+ if (sysattr->method & SYSFS_METHOD_SHOW) {
+ if (length != sysattr->len) {
+ sysattr->value = (char *)realloc
+ (sysattr->value, length);
+ sysattr->len = length;
+ safestrcpymax(sysattr->value, new_value, length);
+ } else {
+ /*"length" of the new value is same as old one */
+ safestrcpymax(sysattr->value, new_value, length);
+ }
+ }
+
+ close(fd);
+ return 0;
+}
+
diff --git a/mdk-stage1/sysfs/sysfs_utils.c b/mdk-stage1/sysfs/sysfs_utils.c
new file mode 100644
index 000000000..a0354a8f8
--- /dev/null
+++ b/mdk-stage1/sysfs/sysfs_utils.c
@@ -0,0 +1,59 @@
+/*
+ * sysfs_utils.c
+ *
+ * System utility functions for libsysfs
+ *
+ * Copyright (C) IBM Corp. 2003-2005
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+#include "libsysfs.h"
+#include "sysfs.h"
+
+/**
+ * sysfs_get_name_from_path: returns last name from a "/" delimited path
+ * @path: path to get name from
+ * @name: where to put name
+ * @len: size of name
+ */
+int sysfs_get_name_from_path(const char *path, char *name, size_t len)
+{
+ char tmp[SYSFS_PATH_MAX];
+ char *n = NULL;
+
+ if (!path || !name || len == 0) {
+ errno = EINVAL;
+ return -1;
+ }
+ memset(tmp, 0, SYSFS_PATH_MAX);
+ safestrcpy(tmp, path);
+ n = strrchr(tmp, '/');
+ if (n == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+ if (*(n+1) == '\0') {
+ *n = '\0';
+ n = strrchr(tmp, '/');
+ if (n == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+ }
+ n++;
+ safestrcpymax(name, n, len);
+ return 0;
+}
diff --git a/mdk-stage1/thirdparty.c b/mdk-stage1/thirdparty.c
new file mode 100644
index 000000000..dcdb77062
--- /dev/null
+++ b/mdk-stage1/thirdparty.c
@@ -0,0 +1,460 @@
+/*
+ * Guillaume Cottenceau (gc@mandrakesoft.com)
+ * Olivier Blin (oblin@mandrakesoft.com)
+ *
+ * Copyright 2005 Mandrakesoft
+ *
+ * This software may be freely redistributed under the terms of the GNU
+ * public license.
+ *
+ * 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.
+ *
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/mount.h>
+#include <sys/utsname.h>
+
+#include "stage1.h"
+#include "tools.h"
+#include "utils.h"
+#include "log.h"
+#include "modules.h"
+#include "mount.h"
+#include "frontend.h"
+#include "partition.h"
+#include "automatic.h"
+#include "probing.h"
+
+#include "thirdparty.h"
+
+#define THIRDPARTY_MOUNT_LOCATION "/tmp/thirdparty"
+
+#define N_PCITABLE_ENTRIES 100
+static struct pcitable_entry pcitable[N_PCITABLE_ENTRIES];
+static int pcitable_len = 0;
+
+static enum return_type thirdparty_choose_device(char ** device, int probe_only)
+{
+ char ** medias, ** medias_models;
+ char ** ptr, ** ptr_models;
+#ifndef DISABLE_DISK
+ char ** disk_medias, ** disk_medias_models;
+ int disk_count;
+ char * parts[50];
+ char * parts_comments[50];
+#endif
+#ifndef DISABLE_CDROM
+ char ** cdrom_medias, ** cdrom_medias_models;
+ int cdrom_count;
+#endif
+ char * floppy_dev;
+ enum return_type results;
+ int count = 0;
+
+ wait_message("Looking for floppy, disk and cdrom devices ...");
+
+#ifndef DISABLE_DISK
+ disk_count = get_disks(&disk_medias, &disk_medias_models);
+ count += disk_count;
+#endif
+#ifndef DISABLE_CDROM
+ cdrom_count = get_cdroms(&cdrom_medias, &cdrom_medias_models);
+ count += cdrom_count;
+#endif
+
+ floppy_dev = floppy_device();
+ if (strstr(floppy_dev, "/dev/") == floppy_dev) {
+ floppy_dev = floppy_dev + 5;
+ }
+ if (floppy_dev)
+ count += 1;
+
+ remove_wait_message();
+
+ if (count == 0) {
+ stg1_error_message("I can't find any floppy, disk or cdrom on this system. "
+ "No third-party kernel modules will be used.");
+ return RETURN_BACK;
+ }
+
+ if (probe_only) {
+#ifndef DISABLE_DISK
+ free(disk_medias);
+ free(disk_medias_models);
+#endif
+#ifndef DISABLE_CDROM
+ free(cdrom_medias);
+ free(cdrom_medias_models);
+#endif
+ return RETURN_OK;
+ }
+
+ ptr = medias = malloc((count + 1) * sizeof(char *));
+ ptr_models =medias_models = malloc((count + 1) * sizeof(char *));
+#ifndef DISABLE_DISK
+ memcpy(ptr, disk_medias, disk_count * sizeof(char *));
+ memcpy(ptr_models, disk_medias_models, disk_count * sizeof(char *));
+ free(disk_medias);
+ free(disk_medias_models);
+ ptr += disk_count;
+ ptr_models += disk_count;
+#endif
+#ifndef DISABLE_CDROM
+ memcpy(ptr, cdrom_medias, cdrom_count * sizeof(char *));
+ memcpy(ptr_models, cdrom_medias_models, cdrom_count * sizeof(char *));
+ free(cdrom_medias);
+ free(cdrom_medias_models);
+ cdrom_medias = ptr; /* used later to know if a cdrom is selected */
+ ptr += cdrom_count;
+ ptr_models += cdrom_count;
+#endif
+ if (floppy_dev) {
+ ptr[0] = floppy_dev;
+ ptr_models[0] = "Floppy device";
+ ptr++;
+ ptr_models++;
+ }
+ ptr[0] = NULL;
+ ptr_models[0] = NULL;
+
+ if (count == 1) {
+ *device = medias[0];
+ } else {
+ results = ask_from_list_comments("If you want to insert third-party kernel modules, "
+ "please select the disk containing the modules.",
+ medias, medias_models, device);
+ if (results != RETURN_OK)
+ return results;
+ }
+
+ if (streq(*device, floppy_dev)) {
+ /* a floppy is selected, don't try to list partitions */
+ return RETURN_OK;
+ }
+
+#ifndef DISABLE_CDROM
+ for (ptr = cdrom_medias; ptr < cdrom_medias + cdrom_count; ptr++) {
+ if (*device == *ptr) {
+ /* a cdrom is selected, don't try to list partitions */
+ log_message("thirdparty: a cdrom is selected, using it (%s)", *device);
+ return RETURN_OK;
+ }
+ }
+#endif
+
+#ifndef DISABLE_DISK
+ /* a disk or usb key is selected */
+ if (list_partitions(*device, parts, parts_comments)) {
+ stg1_error_message("Could not read partitions information.");
+ return RETURN_ERROR;
+ }
+
+ if (parts[0] == NULL) {
+ stg1_error_message("No partition found.");
+ return RETURN_ERROR;
+ }
+
+ /* only one partition has been discovered, don't ask which one to use */
+ if (parts[1] == NULL) {
+ log_message("thirdparty: found only one partition on device (%s)", parts[0]);
+ *device = parts[0];
+ return RETURN_OK;
+ }
+
+ results = ask_from_list_comments("Please select the partition containing "
+ "the third party modules.",
+ parts, parts_comments, device);
+ if (results == RETURN_OK)
+ return RETURN_OK;
+#endif
+
+ stg1_error_message("Sorry, no third party device can be used.");
+
+ return RETURN_BACK;
+}
+
+
+static enum return_type thirdparty_mount_device(char * device)
+{
+ log_message("third party: trying to mount device %s", device);
+ if (try_mount(device, THIRDPARTY_MOUNT_LOCATION) != 0) {
+ stg1_error_message("I can't mount the selected device (%s).", device);
+ return RETURN_ERROR;
+ }
+ return RETURN_OK;
+}
+
+
+static enum return_type thirdparty_prompt_modules(const char *modules_location, char ** modules_list)
+{
+ enum return_type results;
+ char final_name[500];
+ char *module_name;
+ int rc;
+ char * questions[] = { "Options", NULL };
+ static char ** answers = NULL;
+
+ while (1) {
+ results = ask_from_list("Which driver would you like to insmod?", modules_list, &module_name);
+ if (results != RETURN_OK)
+ break;
+
+ sprintf(final_name, "%s/%s", modules_location, module_name);
+
+ results = ask_from_entries("Please enter the options:", questions, &answers, 24, NULL);
+ if (results != RETURN_OK)
+ continue;
+
+ rc = insmod_local_file(final_name, answers[0]);
+ if (rc) {
+ log_message("\tfailed");
+ stg1_error_message("Insmod failed.");
+ }
+ }
+ return RETURN_OK;
+}
+
+
+static int pcitable_orderer(const void *a, const void *b)
+{
+ int ret;
+ struct pcitable_entry *ap = (struct pcitable_entry *)a;
+ struct pcitable_entry *bp = (struct pcitable_entry *)b;
+
+ if ((ret = ap->vendor - bp->vendor) != 0)
+ return ret;
+ if ((ret = ap->device - bp->device) != 0)
+ return ret;
+ if ((ret = ap->subvendor - bp->subvendor) != 0)
+ return ret;
+ if ((ret = ap->subdevice - bp->subdevice) != 0)
+ return ret;
+
+ return 0;
+}
+
+
+static void thirdparty_load_pcitable(const char *modules_location)
+{
+ char pcitable_filename[100];
+ FILE * f = NULL;
+
+ sprintf(pcitable_filename, "%s/pcitable", modules_location);
+ if (!(f = fopen(pcitable_filename, "rb"))) {
+ log_message("third_party: no external pcitable found");
+ return;
+ }
+ pcitable_len = 0;
+ while (pcitable_len < N_PCITABLE_ENTRIES) {
+ char buf[200];
+ struct pcitable_entry *e;
+ if (!fgets(buf, sizeof(buf), f)) break;
+ e = &pcitable[pcitable_len++];
+ if (sscanf(buf, "%hx\t%hx\t\"%[^ \"]\"\t\"%[^\"]\"", &e->vendor, &e->device, e->module, e->description) == 4)
+ e->subvendor = e->subdevice = PCITABLE_MATCH_ALL;
+ else
+ sscanf(buf, "%hx\t%hx\t%x\t%x\t\"%[^ \"]\"\t\"%[^\"]\"", &e->vendor, &e->device, &e->subvendor, &e->subdevice, e->module, e->description);
+ }
+ fclose(f);
+
+ /* sort pcitable by most specialised entries first */
+ qsort(pcitable, pcitable_len, sizeof(pcitable[0]), pcitable_orderer);
+}
+
+
+static int thirdparty_is_detected(char *driver) {
+ int i, j;
+
+ for (i = 0; i < detected_devices_len ; i++) {
+ /* first look for the IDs in the third-party pcitable */
+ for (j = 0; j < pcitable_len ; j++) {
+ if (pcitable[j].vendor == detected_devices[i].vendor &&
+ pcitable[j].device == detected_devices[i].device &&
+ !strcmp(pcitable[j].module, driver)) {
+ const int subvendor = pcitable[j].subvendor;
+ const int subdevice = pcitable[j].subdevice;
+ if ((subvendor == PCITABLE_MATCH_ALL && subdevice == PCITABLE_MATCH_ALL) ||
+ (subvendor == detected_devices[i].subvendor && subdevice == detected_devices[i].subdevice)) {
+ log_message("probing: found device for module %s", driver);
+ return 1;
+ }
+ }
+ }
+ /* if not found, compare with the detected driver */
+ if (!strcmp(detected_devices[i].module, driver)) {
+ log_message("probing: found device for module %s", driver);
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static enum return_type thirdparty_autoload_modules(const char *modules_location, char ** modules_list, FILE *f, int load_detected_only)
+{
+ while (1) {
+ char final_name[500];
+ char module[500];
+ char * options;
+ char ** entry = modules_list;
+
+ if (!fgets(module, sizeof(module), f)) break;
+ if (module[0] == '#' || strlen(module) == 0)
+ continue;
+
+ while (module[strlen(module)-1] == '\n')
+ module[strlen(module)-1] = '\0';
+ options = strchr(module, ' ');
+ if (options) {
+ options[0] = '\0';
+ options++;
+ }
+
+ if (load_detected_only && !thirdparty_is_detected(module)) {
+ log_message("third party: no device detected for module %s, skipping", module);
+ continue;
+ }
+
+ log_message("third party: auto-loading module (%s) with options (%s)", module, options);
+ while (entry && *entry) {
+ if (!strncmp(*entry, module, strlen(module)) && (*entry)[strlen(module)] == '.') {
+ sprintf(final_name, "%s/%s", modules_location, *entry);
+ if (insmod_local_file(final_name, options)) {
+ log_message("\t%s (third party media): failed", *entry);
+ stg1_error_message("Insmod %s (third party media) failed.", *entry);
+ }
+ break;
+ }
+ entry++;
+ }
+ if (!entry || !*entry) {
+ enum insmod_return ret = my_insmod(module, ANY_DRIVER_TYPE, options, 0);
+ if (ret != INSMOD_OK) {
+ log_message("\t%s (marfile): failed", module);
+ stg1_error_message("Insmod %s (marfile) failed.", module);
+ }
+ }
+ }
+
+ return RETURN_OK;
+}
+
+static enum return_type thirdparty_try_directory(char * root_directory, int interactive) {
+ char modules_location[100];
+ char modules_location_release[100];
+ char *list_filename;
+ FILE *f_load, *f_detect;
+ char **modules_list, **modules_list_release;
+ struct utsname kernel_uname;
+
+ /* look first in the specific third-party directory */
+ snprintf(modules_location, sizeof(modules_location), "%s" THIRDPARTY_DIRECTORY, root_directory);
+ modules_list = list_directory(modules_location);
+
+ /* if it's empty, look in the root of selected device */
+ if (!modules_list || !modules_list[0]) {
+ modules_location[strlen(root_directory)] = '\0';
+ modules_list = list_directory(modules_location);
+ if (interactive)
+ add_to_env("THIRDPARTY_DIR", "");
+ } else {
+ if (interactive)
+ add_to_env("THIRDPARTY_DIR", THIRDPARTY_DIRECTORY);
+ }
+
+ if (uname(&kernel_uname)) {
+ log_perror("uname failed");
+ return RETURN_ERROR;
+ }
+ snprintf(modules_location_release, sizeof(modules_location_release), "%s/%s", modules_location, kernel_uname.release);
+ modules_list_release = list_directory(modules_location_release);
+ if (modules_list_release && modules_list_release[0]) {
+ strcpy(modules_location, modules_location_release);
+ modules_list = modules_list_release;
+ }
+
+ log_message("third party: using modules location %s", modules_location);
+
+ if (!modules_list || !*modules_list) {
+ log_message("third party: no modules found");
+ if (interactive)
+ stg1_error_message("No modules found on selected device.");
+ return RETURN_ERROR;
+ }
+
+ list_filename = alloca(strlen(modules_location) + 10 /* max: "/to_detect" */ + 1);
+
+ sprintf(list_filename, "%s/to_load", modules_location);
+ f_load = fopen(list_filename, "rb");
+ if (f_load) {
+ thirdparty_autoload_modules(modules_location, modules_list, f_load, 0);
+ fclose(f_load);
+ }
+
+ sprintf(list_filename, "%s/to_detect", modules_location);
+ f_detect = fopen(list_filename, "rb");
+ if (f_detect) {
+ probing_detect_devices();
+ thirdparty_load_pcitable(modules_location);
+ thirdparty_autoload_modules(modules_location, modules_list, f_detect, 1);
+ fclose(f_detect);
+ }
+
+ if (f_load || f_detect)
+ return RETURN_OK;
+ else if (interactive) {
+ if (IS_AUTOMATIC)
+ stg1_error_message("I can't find a \"to_load\" file. Please select the modules manually.");
+ log_message("third party: no \"to_load\" file, prompting for modules");
+ return thirdparty_prompt_modules(modules_location, modules_list);
+ } else {
+ return RETURN_OK;
+ }
+}
+
+void thirdparty_load_media_modules(void)
+{
+ thirdparty_try_directory(IMAGE_LOCATION, 0);
+}
+
+void thirdparty_load_modules(void)
+{
+ enum return_type results;
+ char * device;
+
+ device = NULL;
+ if (IS_AUTOMATIC) {
+ device = get_auto_value("thirdparty");
+ thirdparty_choose_device(NULL, 1); /* probe only to create devices */
+ log_message("third party: trying automatic device %s", device);
+ if (thirdparty_mount_device(device) != RETURN_OK)
+ device = NULL;
+ }
+
+ while (!device || streq(device, "")) {
+ results = thirdparty_choose_device(&device, 0);
+ if (results == RETURN_BACK)
+ return;
+ if (thirdparty_mount_device(device) != RETURN_OK)
+ device = NULL;
+ }
+
+ log_message("third party: using device %s", device);
+ add_to_env("THIRDPARTY_DEVICE", device);
+
+ results = thirdparty_try_directory(THIRDPARTY_MOUNT_LOCATION, 1);
+ umount(THIRDPARTY_MOUNT_LOCATION);
+
+ if (results != RETURN_OK)
+ return thirdparty_load_modules();
+}
+
+void thirdparty_destroy(void)
+{
+ probing_destroy();
+}
diff --git a/mdk-stage1/thirdparty.h b/mdk-stage1/thirdparty.h
new file mode 100644
index 000000000..c999d6a58
--- /dev/null
+++ b/mdk-stage1/thirdparty.h
@@ -0,0 +1,35 @@
+/*
+ * Guillaume Cottenceau (gc@mandrakesoft.com)
+ * Olivier Blin (oblin@mandrakesoft.com)
+ *
+ * Copyright 2000 Mandrakesoft
+ *
+ * This software may be freely redistributed under the terms of the GNU
+ * public license.
+ *
+ * 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.
+ *
+ */
+
+#ifndef _THIRDPARTY_H_
+#define _THIRDPARTY_H_
+
+#define THIRDPARTY_DIRECTORY "/install/thirdparty"
+
+/* load third party modules present on install media
+ * use to_load and to_detect files in /install/thirdparty
+ * do not prompt user
+ */
+void thirdparty_load_media_modules(void);
+
+/* load modules if to_load or to_detect files are present
+ * prompt user if no to_load file is present
+ */
+void thirdparty_load_modules(void);
+
+/* destroy all data structures related to the thirdparty module */
+void thirdparty_destroy(void);
+
+#endif
diff --git a/mdk-stage1/tools.c b/mdk-stage1/tools.c
new file mode 100644
index 000000000..43d01811a
--- /dev/null
+++ b/mdk-stage1/tools.c
@@ -0,0 +1,361 @@
+/*
+ * Guillaume Cottenceau (gc@mandrakesoft.com)
+ *
+ * Copyright 2000 Mandrakesoft
+ *
+ * This software may be freely redistributed under the terms of the GNU
+ * public license.
+ *
+ * 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.
+ *
+ */
+
+/*
+ * Portions from Erik Troan (ewt@redhat.com)
+ *
+ * Copyright 1996 Red Hat Software
+ *
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdio.h>
+#include <dirent.h>
+#include <sys/types.h>
+#include <sys/mount.h>
+#include <sys/poll.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+#include <linux/fd.h>
+#include "stage1.h"
+#include "log.h"
+#include "mount.h"
+#include "frontend.h"
+#include "automatic.h"
+
+#include "tools.h"
+#include "utils.h"
+#include "params.h"
+#include "probing.h"
+#include "modules.h"
+#include "lomount.h"
+
+int image_has_stage2()
+{
+ return access(COMPRESSED_FILE_REL(IMAGE_LOCATION "/"), R_OK) == 0 ||
+ access(IMAGE_LOCATION "/" LIVE_LOCATION_REL, R_OK) == 0;
+}
+
+enum return_type create_IMAGE_LOCATION(char *location_full)
+{
+ struct stat statbuf;
+ int offset = strncmp(location_full, IMAGE_LOCATION_DIR, sizeof(IMAGE_LOCATION_DIR) - 1) == 0 ? sizeof(IMAGE_LOCATION_DIR) - 1 : 0;
+ char *with_arch = asprintf_("%s/%s", location_full, ARCH);
+
+ log_message("trying %s", with_arch);
+
+ if (stat(with_arch, &statbuf) == 0 && S_ISDIR(statbuf.st_mode))
+ location_full = with_arch;
+
+ log_message("assuming %s is a mirror tree", location_full + offset);
+
+ unlink(IMAGE_LOCATION);
+ if (symlink(location_full + offset, IMAGE_LOCATION) != 0)
+ return RETURN_ERROR;
+
+ return RETURN_OK;
+}
+
+int ramdisk_possible(void)
+{
+ if (total_memory() > (IS_RESCUE ? MEM_LIMIT_RESCUE : MEM_LIMIT_DRAKX))
+ return 1;
+ else {
+ log_message("warning, ramdisk is not possible due to low mem!");
+ return 0;
+ }
+}
+
+int compressed_image_preload(void)
+{
+ if (total_memory() > (IS_RESCUE ? MEM_LIMIT_RESCUE_PRELOAD : MEM_LIMIT_DRAKX_PRELOAD))
+ return 1;
+ else {
+ log_message("warning, not preloading compressed due to low mem");
+ return 0;
+ }
+}
+
+enum return_type save_fd(int from_fd, char * to, void (*callback_func)(int overall))
+{
+ FILE * f_to;
+ size_t quantity __attribute__((aligned(16))), overall = 0;
+ char buf[4096] __attribute__((aligned(4096)));
+ int ret = RETURN_ERROR;
+
+ if (!(f_to = fopen(to, "w"))) {
+ log_perror(to);
+ goto close_from;
+ }
+
+ do {
+ quantity = read(from_fd, buf, sizeof(buf));
+ if (quantity > 0) {
+ if (fwrite(buf, 1, quantity, f_to) != quantity) {
+ log_message("short write (%s)", strerror(errno));
+ goto cleanup;
+ }
+ } else if (quantity == -1) {
+ log_message("an error occured: %s", strerror(errno));
+ goto cleanup;
+ }
+
+ if (callback_func) {
+ overall += quantity;
+ callback_func(overall);
+ }
+ } while (quantity);
+
+ ret = RETURN_OK;
+
+ cleanup:
+ fclose(f_to);
+ close_from:
+ close(from_fd);
+
+ return ret;
+}
+
+enum return_type copy_file(char * from, char * to, void (*callback_func)(int overall))
+{
+ int from_fd;
+
+ log_message("copy_file: %s -> %s", from, to);
+
+ from_fd = open(from, O_RDONLY);
+ if (from_fd != -1) {
+ return save_fd(from_fd, to, callback_func);
+ } else {
+ log_perror(from);
+ return RETURN_ERROR;
+ }
+}
+
+enum return_type recursiveRemove(char *file)
+{
+ struct stat sb;
+
+ if (lstat(file, &sb) != 0) {
+ log_message("failed to stat %s: %d", file, errno);
+ return RETURN_ERROR;
+ }
+
+ /* only descend into subdirectories if device is same as dir */
+ if (S_ISDIR(sb.st_mode)) {
+ char * strBuf = alloca(strlen(file) + 1024);
+ DIR * dir;
+ struct dirent * d;
+
+ if (!(dir = opendir(file))) {
+ log_message("error opening %s: %d", file, errno);
+ return RETURN_ERROR;
+ }
+ while ((d = readdir(dir))) {
+ if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
+ continue;
+
+ strcpy(strBuf, file);
+ strcat(strBuf, "/");
+ strcat(strBuf, d->d_name);
+
+ if (recursiveRemove(strBuf) != 0) {
+ closedir(dir);
+ return RETURN_ERROR;
+ }
+ }
+ closedir(dir);
+
+ if (rmdir(file)) {
+ log_message("failed to rmdir %s: %d", file, errno);
+ return RETURN_ERROR;
+ }
+ } else {
+ if (unlink(file) != 0) {
+ log_message("failed to remove %s: %d", file, errno);
+ return RETURN_ERROR;
+ }
+ }
+ return RETURN_OK;
+}
+
+enum return_type recursiveRemove_if_it_exists(char *file)
+{
+ struct stat sb;
+
+ if (lstat(file, &sb) != 0) {
+ /* if file doesn't exist, simply return OK */
+ return RETURN_OK;
+ }
+
+ return recursiveRemove(file);
+}
+
+enum return_type mount_compressed_image(char *compressed_image, char *location_mount)
+{
+ if (lomount(compressed_image, location_mount, NULL, 1)) {
+ stg1_error_message("Could not mount compressed loopback :(.");
+ return RETURN_ERROR;
+ }
+ return RETURN_OK;
+}
+
+enum return_type preload_mount_compressed_fd(int compressed_fd, int image_size, char *image_name, char *location_mount)
+{
+ int ret;
+ char *compressed_tmpfs = asprintf_("/tmp/%s", image_name);
+ char *buf = "Loading program into memory...";
+ init_progression(buf, image_size);
+ ret = save_fd(compressed_fd, compressed_tmpfs, update_progression);
+ end_progression();
+ if (ret != RETURN_OK)
+ return ret;
+
+ return mount_compressed_image(compressed_tmpfs, location_mount);
+}
+
+enum return_type mount_compressed_image_may_preload(char *image_name, char *location_mount, int preload)
+{
+ char *compressed_image = asprintf_("%s/%s", COMPRESSED_LOCATION, image_name);
+
+ log_message("mount_compressed_may_preload: %s into %s (preload = %d)", compressed_image, location_mount, preload);
+
+ if (access(compressed_image, R_OK) != 0) return RETURN_ERROR;
+
+ if (preload) {
+ int compressed_fd = open(compressed_image, O_RDONLY);
+ if (compressed_fd != -1) {
+ return preload_mount_compressed_fd(compressed_fd, file_size(compressed_image), image_name, location_mount);
+ } else {
+ log_perror(compressed_image);
+ return RETURN_ERROR;
+ }
+ } else {
+ return mount_compressed_image(compressed_image, location_mount);
+ }
+}
+
+enum return_type may_load_compressed_image(void)
+{
+ if (!IS_RESCUE && access(IMAGE_LOCATION "/" LIVE_LOCATION_REL, R_OK) == 0) {
+ /* LIVE install */
+ return RETURN_OK;
+ } else {
+ /* compressed install */
+ return mount_compressed_image_may_preload(COMPRESSED_NAME(""), STAGE2_LOCATION, compressed_image_preload());
+ }
+}
+
+enum return_type load_compressed_fd(int fd, int size)
+{
+ return preload_mount_compressed_fd(fd, size, COMPRESSED_NAME(""), STAGE2_LOCATION);
+}
+
+int try_mount(char * dev, char * location)
+{
+ char device_fullname[50];
+ snprintf(device_fullname, sizeof(device_fullname), "/dev/%s", dev);
+
+ if (my_mount(device_fullname, location, "ext2", 0) == -1 &&
+ my_mount(device_fullname, location, "ext4", 0) == -1 &&
+ my_mount(device_fullname, location, "vfat", 0) == -1 &&
+ my_mount(device_fullname, location, "ntfs", 0) == -1 &&
+ my_mount(device_fullname, location, "reiserfs", 0) == -1 &&
+ my_mount(device_fullname, location, "jfs", 0) == -1 &&
+ my_mount(device_fullname, location, "xfs", 0) == -1 &&
+ my_mount(device_fullname, location, "iso9660", 0) == -1) {
+ return 1;
+ }
+
+ return 0;
+}
+
+#ifndef DISABLE_DISK
+int get_disks(char *** names, char *** models)
+{
+ char ** ptr;
+ int count = 0;
+
+ my_insmod("ide_disk", ANY_DRIVER_TYPE, NULL, 0);
+ my_insmod("sd_mod", ANY_DRIVER_TYPE, NULL, 0);
+
+ get_medias(DISK, names, models, BUS_ANY);
+
+ ptr = *names;
+ while (ptr && *ptr) {
+ count++;
+ ptr++;
+ }
+
+ return count;
+}
+#endif
+
+#ifndef DISABLE_CDROM
+int get_cdroms(char *** names, char *** models)
+{
+ char ** ptr;
+ int count = 0;
+
+ my_insmod("ide_cd_mod", ANY_DRIVER_TYPE, NULL, 0);
+ my_insmod("sr_mod", ANY_DRIVER_TYPE, NULL, 0);
+
+ get_medias(CDROM, names, models, BUS_ANY);
+
+ ptr = *names;
+ while (ptr && *ptr) {
+ count++;
+ ptr++;
+ }
+
+ return count;
+}
+#endif
+
+char * floppy_device(void)
+{
+ char ** names, ** models;
+ int fd;
+ my_insmod("floppy", ANY_DRIVER_TYPE, NULL, 0);
+ fd = open("/dev/fd0", O_RDONLY|O_NONBLOCK);
+ if (fd != -1) {
+ char drivtyp[17];
+ if (!ioctl(fd, FDGETDRVTYP, (void *)drivtyp)) {
+ struct floppy_drive_struct ds;
+ log_message("/dev/fd0 type: %s", drivtyp);
+ if (!ioctl(fd, FDPOLLDRVSTAT, &ds)) {
+ log_message("\ttrack: %d", ds.track);
+ if (ds.track >= 0) {
+ close(fd);
+ return "/dev/fd0";
+ }
+ }
+ } else {
+ log_perror("can't FDGETDRVTYP /dev/fd0");
+ }
+ close(fd);
+ }
+ log_message("seems that you don't have a regular floppy drive");
+ my_insmod("sd_mod", ANY_DRIVER_TYPE, NULL, 0);
+ get_medias(FLOPPY, &names, &models, BUS_ANY);
+ if (names && *names)
+ return asprintf_("/dev/%s", *names);
+ else
+ return "/dev/fd0";
+}
diff --git a/mdk-stage1/tools.h b/mdk-stage1/tools.h
new file mode 100644
index 000000000..85ff42196
--- /dev/null
+++ b/mdk-stage1/tools.h
@@ -0,0 +1,49 @@
+
+/*
+ * Guillaume Cottenceau (gc@mandrakesoft.com)
+ *
+ * Copyright 2000 Mandrakesoft
+ *
+ * This software may be freely redistributed under the terms of the GNU
+ * public license.
+ *
+ * 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.
+ *
+ */
+
+/*
+ * Portions from Erik Troan (ewt@redhat.com)
+ *
+ * Copyright 1996 Red Hat Software
+ *
+ */
+
+#ifndef _TOOLS_H_
+#define _TOOLS_H_
+
+#include <stdlib.h>
+#include "bootsplash.h"
+
+int image_has_stage2();
+enum return_type create_IMAGE_LOCATION(char *location_full);
+int ramdisk_possible(void);
+enum return_type copy_file(char * from, char * to, void (*callback_func)(int overall));
+enum return_type recursiveRemove(char *file);
+enum return_type recursiveRemove_if_it_exists(char *file);
+enum return_type preload_mount_compressed_fd(int compressed_fd, int image_size, char *image_name, char *location_mount);
+enum return_type mount_compressed_image(char *compressed_image, char *location_mount);
+enum return_type mount_compressed_image_may_preload(char *image_name, char *location_mount, int preload);
+enum return_type load_compressed_fd(int fd, int size);
+enum return_type may_load_compressed_image(void);
+int try_mount(char * dev, char * location);
+#ifndef DISABLE_DISK
+int get_disks(char *** names, char *** models);
+#endif
+#ifndef DISABLE_CDROM
+int get_cdroms(char *** names, char *** models);
+#endif
+char * floppy_device(void);
+
+#endif
diff --git a/mdk-stage1/url.c b/mdk-stage1/url.c
new file mode 100644
index 000000000..77233847e
--- /dev/null
+++ b/mdk-stage1/url.c
@@ -0,0 +1,560 @@
+/*
+ * Guillaume Cottenceau (gc@mandrakesoft.com)
+ *
+ * Copyright 2000 Mandrakesoft
+ *
+ * This software may be freely redistributed under the terms of the GNU
+ * public license.
+ *
+ * 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.
+ *
+ */
+
+/*
+ * Portions from Erik Troan <ewt@redhat.com> and Matt Wilson <msw@redhat.com>
+ *
+ * Copyright 1999 Red Hat, Inc.
+ *
+ */
+
+#include <alloca.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <netinet/in_systm.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <netdb.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <sys/poll.h>
+
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <arpa/inet.h>
+
+#include "dns.h"
+#include "log.h"
+#include "tools.h"
+#include "utils.h"
+
+#include "url.h"
+
+
+#define TIMEOUT_SECS 60
+#define BUFFER_SIZE 4096
+#define HTTP_MAX_RECURSION 5
+
+
+static int ftp_check_response(int sock, char ** str)
+{
+ static char buf[BUFFER_SIZE + 1];
+ int bufLength = 0;
+ struct pollfd polls;
+ char * chptr, * start;
+ int bytesRead, rc = 0;
+ int doesContinue = 1;
+ char errorCode[4];
+
+ errorCode[0] = '\0';
+
+ do {
+ polls.fd = sock;
+ polls.events = POLLIN;
+ if (poll(&polls, 1, TIMEOUT_SECS*1000) != 1)
+ return FTPERR_BAD_SERVER_RESPONSE;
+
+ bytesRead = read(sock, buf + bufLength, sizeof(buf) - bufLength - 1);
+
+ bufLength += bytesRead;
+
+ buf[bufLength] = '\0';
+
+ /* divide the response into lines, checking each one to see if
+ we are finished or need to continue */
+
+ start = chptr = buf;
+
+ do {
+ while (*chptr != '\n' && *chptr) chptr++;
+
+ if (*chptr == '\n') {
+ *chptr = '\0';
+ if (*(chptr - 1) == '\r') *(chptr - 1) = '\0';
+ if (str) *str = start;
+
+ if (errorCode[0]) {
+ if (!strncmp(start, errorCode, 3) && start[3] == ' ')
+ doesContinue = 0;
+ } else {
+ strncpy(errorCode, start, 3);
+ errorCode[3] = '\0';
+ if (start[3] != '-') {
+ doesContinue = 0;
+ }
+ }
+
+ start = chptr + 1;
+ chptr++;
+ } else {
+ chptr++;
+ }
+ } while (*chptr);
+
+ if (doesContinue && chptr > start) {
+ memcpy(buf, start, chptr - start - 1);
+ bufLength = chptr - start - 1;
+ } else {
+ bufLength = 0;
+ }
+ } while (doesContinue);
+
+ if (*errorCode == '4' || *errorCode == '5') {
+ if (!strncmp(errorCode, "550", 3)) {
+ return FTPERR_FILE_NOT_FOUND;
+ }
+
+ return FTPERR_BAD_SERVER_RESPONSE;
+ }
+
+ if (rc) return rc;
+
+ return 0;
+}
+
+static int ftp_command(int sock, char * command, char * param)
+{
+ char buf[500];
+ int rc;
+
+ snprintf(buf, sizeof(buf), "%s%s%s\r\n", command, param ? " " : "", param ? param : "");
+
+ if (write(sock, buf, strlen(buf)) != (ssize_t)strlen(buf)) {
+ return FTPERR_SERVER_IO_ERROR;
+ }
+
+ if ((rc = ftp_check_response(sock, NULL)))
+ return rc;
+
+ return 0;
+}
+
+static int get_host_address(char * host, struct in_addr * address)
+{
+ if (isdigit(host[0])) {
+ if (!inet_aton(host, address)) {
+ return FTPERR_BAD_HOST_ADDR;
+ }
+ } else {
+ if (mygethostbyname(host, address))
+ return FTPERR_BAD_HOSTNAME;
+ }
+
+ return 0;
+}
+
+int ftp_open_connection(char * host, char * name, char * password, char * proxy)
+{
+ int sock;
+ struct in_addr serverAddress;
+ struct sockaddr_in destPort;
+ int rc;
+ int port = 21;
+
+ if (!strcmp(name, "")) {
+ name = "anonymous";
+ password = "-drakx@";
+ }
+
+ if (strcmp(proxy, "")) {
+ name = asprintf_("%s@%s", name, host);
+ host = proxy;
+ }
+
+ if ((rc = get_host_address(host, &serverAddress))) return rc;
+
+ sock = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
+ if (sock < 0) {
+ return FTPERR_FAILED_CONNECT;
+ }
+
+ destPort.sin_family = AF_INET;
+ destPort.sin_port = htons(port);
+ destPort.sin_addr = serverAddress;
+
+ if (connect(sock, (struct sockaddr *) &destPort, sizeof(destPort))) {
+ close(sock);
+ return FTPERR_FAILED_CONNECT;
+ }
+
+ /* ftpCheckResponse() assumes the socket is nonblocking */
+ if (fcntl(sock, F_SETFL, O_NONBLOCK)) {
+ close(sock);
+ return FTPERR_FAILED_CONNECT;
+ }
+
+ if ((rc = ftp_check_response(sock, NULL))) {
+ return rc;
+ }
+
+ if ((rc = ftp_command(sock, "USER", name))) {
+ close(sock);
+ return rc;
+ }
+
+ if ((rc = ftp_command(sock, "PASS", password))) {
+ close(sock);
+ return rc;
+ }
+
+ if ((rc = ftp_command(sock, "TYPE", "I"))) {
+ close(sock);
+ return rc;
+ }
+
+ return sock;
+}
+
+
+int ftp_data_command(int sock, char * command, char * param)
+{
+ int dataSocket;
+ struct sockaddr_in dataAddress;
+ int i, j;
+ char * passReply;
+ char * chptr;
+ char retrCommand[500];
+ int rc;
+
+ if (write(sock, "PASV\r\n", 6) != 6) {
+ return FTPERR_SERVER_IO_ERROR;
+ }
+ if ((rc = ftp_check_response(sock, &passReply)))
+ return FTPERR_PASSIVE_ERROR;
+
+ chptr = passReply;
+ while (*chptr && *chptr != '(') chptr++;
+ if (*chptr != '(') return FTPERR_PASSIVE_ERROR;
+ chptr++;
+ passReply = chptr;
+ while (*chptr && *chptr != ')') chptr++;
+ if (*chptr != ')') return FTPERR_PASSIVE_ERROR;
+ *chptr-- = '\0';
+
+ while (*chptr && *chptr != ',') chptr--;
+ if (*chptr != ',') return FTPERR_PASSIVE_ERROR;
+ chptr--;
+ while (*chptr && *chptr != ',') chptr--;
+ if (*chptr != ',') return FTPERR_PASSIVE_ERROR;
+ *chptr++ = '\0';
+
+ /* now passReply points to the IP portion, and chptr points to the
+ port number portion */
+
+ dataAddress.sin_family = AF_INET;
+ if (sscanf(chptr, "%d,%d", &i, &j) != 2) {
+ return FTPERR_PASSIVE_ERROR;
+ }
+ dataAddress.sin_port = htons((i << 8) + j);
+
+ chptr = passReply;
+ while (*chptr++) {
+ if (*chptr == ',') *chptr = '.';
+ }
+
+ if (!inet_aton(passReply, &dataAddress.sin_addr))
+ return FTPERR_PASSIVE_ERROR;
+
+ dataSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
+ if (dataSocket < 0) {
+ return FTPERR_FAILED_CONNECT;
+ }
+
+ if (!param)
+ sprintf(retrCommand, "%s\r\n", command);
+ else
+ sprintf(retrCommand, "%s %s\r\n", command, param);
+
+ i = strlen(retrCommand);
+
+ if (write(sock, retrCommand, i) != i) {
+ return FTPERR_SERVER_IO_ERROR;
+ }
+
+ if (connect(dataSocket, (struct sockaddr *) &dataAddress,
+ sizeof(dataAddress))) {
+ close(dataSocket);
+ return FTPERR_FAILED_DATA_CONNECT;
+ }
+
+ if ((rc = ftp_check_response(sock, NULL))) {
+ close(dataSocket);
+ return rc;
+ }
+
+ return dataSocket;
+}
+
+
+int ftp_get_filesize(int sock, char * remotename)
+{
+ int size = 0;
+ char buf[2000];
+ char file[500];
+ char * ptr;
+ int fd, rc, tot;
+ int i;
+
+ strcpy(buf, remotename);
+ ptr = strrchr(buf, '/');
+ if (!*ptr)
+ return -1;
+ *ptr = '\0';
+
+ strcpy(file, ptr+1);
+
+ if ((rc = ftp_command(sock, "CWD", buf))) {
+ return -1;
+ }
+
+ fd = ftp_data_command(sock, "LIST", file);
+ if (fd <= 0) {
+ close(sock);
+ return -1;
+ }
+
+ ptr = buf;
+ while ((tot = read(fd, ptr, sizeof(buf) - (ptr - buf) - 1)) != 0)
+ ptr += tot;
+ *ptr = '\0';
+ close(fd);
+
+ if (!(ptr = strstr(buf, file))) {
+ log_message("FTP/get_filesize: Bad mood, directory does not contain searched file (%s)", file);
+ if (ftp_end_data_command(sock))
+ close(sock);
+ return -1;
+ }
+
+ for (i=0; i<4; i++) {
+ while (*ptr && *ptr != ' ')
+ ptr--;
+ while (*ptr && *ptr == ' ')
+ ptr--;
+ }
+ while (*ptr && *ptr != ' ')
+ ptr--;
+
+ if (ptr)
+ size = charstar_to_int(ptr+1);
+ else
+ size = 0;
+
+ if (ftp_end_data_command(sock)) {
+ close(sock);
+ return -1;
+ }
+
+ return size;
+}
+
+
+int ftp_start_download(int sock, char * remotename, int * size)
+{
+ if ((*size = ftp_get_filesize(sock, remotename)) == -1) {
+ log_message("FTP: could not get filesize (trying to continue)");
+ *size = 0;
+ }
+ return ftp_data_command(sock, "RETR", remotename);
+}
+
+
+int ftp_end_data_command(int sock)
+{
+ if (ftp_check_response(sock, NULL))
+ return FTPERR_BAD_SERVER_RESPONSE;
+
+ return 0;
+}
+
+
+char *str_ftp_error(int error)
+{
+ return error == FTPERR_PASSIVE_ERROR ? "error with passive connection" :
+ error == FTPERR_FAILED_CONNECT ? "couldn't connect to server" :
+ error == FTPERR_FILE_NOT_FOUND ? "file not found" :
+ error == FTPERR_BAD_SERVER_RESPONSE ? "bad server response (server too busy?)" :
+ NULL;
+}
+
+
+static int _http_download_file(char * hostname, char * remotename, int * size, char * proxyprotocol, char * proxyname, char * proxyport, int recursion)
+{
+ char * buf;
+ char headers[4096];
+ char * nextChar = headers;
+ int statusCode;
+ struct in_addr serverAddress;
+ struct pollfd polls;
+ int sock;
+ int rc;
+ struct sockaddr_in destPort;
+ const char * header_content_length = "Content-Length: ";
+ const char * header_location = "Location: http://";
+ char * http_server_name;
+ int http_server_port;
+
+ if (proxyprotocol) {
+ http_server_name = proxyname;
+ http_server_port = atoi(proxyport);
+ } else {
+ http_server_name = hostname;
+ http_server_port = 80;
+ }
+
+ log_message("HTTP: connecting to server %s:%i (%s)",
+ http_server_name, http_server_port,
+ proxyprotocol ? "proxy" : "no proxy");
+
+ if ((rc = get_host_address(http_server_name, &serverAddress))) return rc;
+
+ sock = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
+ if (sock < 0) {
+ return FTPERR_FAILED_CONNECT;
+ }
+
+ destPort.sin_family = AF_INET;
+ destPort.sin_port = htons(http_server_port);
+ destPort.sin_addr = serverAddress;
+
+ if (connect(sock, (struct sockaddr *) &destPort, sizeof(destPort))) {
+ close(sock);
+ return FTPERR_FAILED_CONNECT;
+ }
+
+ buf = proxyprotocol ? asprintf_("GET %s://%s%s HTTP/1.0\r\nHost: %s\r\n\r\n", proxyprotocol, hostname, remotename, hostname)
+ : asprintf_("GET %s HTTP/1.0\r\nHost: %s\r\n\r\n", remotename, hostname);
+
+ write(sock, buf, strlen(buf));
+
+ /* This is fun; read the response a character at a time until we:
+
+ 1) Get our first \r\n; which lets us check the return code
+ 2) Get a \r\n\r\n, which means we're done */
+
+ *nextChar = '\0';
+ statusCode = 0;
+ while (!strstr(headers, "\r\n\r\n")) {
+ polls.fd = sock;
+ polls.events = POLLIN;
+ rc = poll(&polls, 1, TIMEOUT_SECS*1000);
+
+ if (rc == 0) {
+ close(sock);
+ return FTPERR_SERVER_TIMEOUT;
+ } else if (rc < 0) {
+ close(sock);
+ return FTPERR_SERVER_IO_ERROR;
+ }
+
+ if (read(sock, nextChar, 1) != 1) {
+ close(sock);
+ return FTPERR_SERVER_IO_ERROR;
+ }
+
+ nextChar++;
+ *nextChar = '\0';
+
+ if (nextChar - headers == sizeof(headers)) {
+ close(sock);
+ return FTPERR_SERVER_IO_ERROR;
+ }
+
+ if (!statusCode && strstr(headers, "\r\n")) {
+ char * start, * end;
+
+ start = headers;
+ while (!isspace(*start) && *start) start++;
+ if (!*start) {
+ close(sock);
+ return FTPERR_SERVER_IO_ERROR;
+ }
+ start++;
+
+ end = start;
+ while (!isspace(*end) && *end) end++;
+ if (!*end) {
+ close(sock);
+ return FTPERR_SERVER_IO_ERROR;
+ }
+
+ *end = '\0';
+ log_message("HTTP: server response '%s'", start);
+ if (streq(start, "404")) {
+ close(sock);
+ return FTPERR_FILE_NOT_FOUND;
+ } else if (streq(start, "302")) {
+ log_message("HTTP: found, but document has moved");
+ statusCode = 302;
+ } else if (streq(start, "200")) {
+ statusCode = 200;
+ } else {
+ close(sock);
+ return FTPERR_BAD_SERVER_RESPONSE;
+ }
+
+ *end = ' ';
+ }
+ }
+
+ if (statusCode == 302) {
+ if (recursion >= HTTP_MAX_RECURSION) {
+ log_message("HTTP: too many levels of recursion, aborting");
+ close(sock);
+ return FTPERR_UNKNOWN;
+ }
+ if ((buf = strstr(headers, header_location))) {
+ char * found_host;
+ char *found_file;
+ found_host = buf + strlen(header_location);
+ if ((found_file = index(found_host, '/'))) {
+ if ((buf = index(found_file, '\r'))) {
+ buf[0] = '\0';
+ remotename = strdup(found_file);
+ found_file[0] = '\0';
+ hostname = strdup(found_host);
+ log_message("HTTP: redirected to new host \"%s\" and file \"%s\"", hostname, remotename);
+ }
+ }
+
+ }
+ /*
+ * don't fail if new URL can't be parsed,
+ * asking the same URL may work if the DNS server are doing round-robin
+ */
+ return _http_download_file(hostname, remotename, size, proxyprotocol, proxyname, proxyport, recursion + 1);
+ }
+
+ if ((buf = strstr(headers, header_content_length)))
+ *size = charstar_to_int(buf + strlen(header_content_length));
+ else
+ *size = 0;
+
+ return sock;
+}
+
+
+int http_download_file(char * hostname, char * remotename, int * size, char * proxyprotocol, char * proxyname, char * proxyport)
+{
+ return _http_download_file(hostname, remotename, size, proxyprotocol, proxyname, proxyport, 0);
+}
diff --git a/mdk-stage1/url.h b/mdk-stage1/url.h
new file mode 100644
index 000000000..7a9dcfb4b
--- /dev/null
+++ b/mdk-stage1/url.h
@@ -0,0 +1,46 @@
+/*
+ * Guillaume Cottenceau (gc@mandrakesoft.com)
+ *
+ * Copyright 2000 Mandrakesoft
+ *
+ * This software may be freely redistributed under the terms of the GNU
+ * public license.
+ *
+ * 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.
+ *
+ */
+
+/*
+ * Portions from Erik Troan <ewt@redhat.com> and Matt Wilson <msw@redhat.com>
+ *
+ * Copyright 1999 Red Hat, Inc.
+ *
+ */
+
+#ifndef _URL_H_
+#define _URL_H_
+
+int ftp_open_connection(char * host, char * name, char * password, char * proxy);
+int ftp_get_filesize(int sock, char * remotename);
+int ftp_start_download(int sock, char * remotename, int * size);
+int ftp_end_data_command(int sock);
+char *str_ftp_error(int error);
+
+int http_download_file(char * hostname, char * remotename, int * size, char * proxyprotocol, char * proxyname, char * proxyport);
+
+
+#define FTPERR_BAD_SERVER_RESPONSE -1
+#define FTPERR_SERVER_IO_ERROR -2
+#define FTPERR_SERVER_TIMEOUT -3
+#define FTPERR_BAD_HOST_ADDR -4
+#define FTPERR_BAD_HOSTNAME -5
+#define FTPERR_FAILED_CONNECT -6
+#define FTPERR_FILE_IO_ERROR -7
+#define FTPERR_PASSIVE_ERROR -8
+#define FTPERR_FAILED_DATA_CONNECT -9
+#define FTPERR_FILE_NOT_FOUND -10
+#define FTPERR_UNKNOWN -100
+
+#endif
diff --git a/mdk-stage1/usb-resource/Makefile b/mdk-stage1/usb-resource/Makefile
new file mode 100644
index 000000000..6f1a47f3b
--- /dev/null
+++ b/mdk-stage1/usb-resource/Makefile
@@ -0,0 +1,25 @@
+ #******************************************************************************
+ #
+ # $Id: Makefile 213578 2005-08-25 11:41:51Z prigaux $
+ #
+ # Guillaume Cottenceau (gc@mandrakesoft.com)
+ #
+ # Copyright 2000 Mandrakesoft
+ #
+ # This software may be freely redistributed under the terms of the GNU
+ # public license.
+ #
+ # 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.
+ #
+ #*****************************************************************************
+
+
+all: usb-ids.h
+
+usb-ids.h: /usr/share/ldetect-lst/usbtable.gz update-usb-ids.pl
+ perl update-usb-ids.pl > $@ || rm -f $@
+
+clean:
+ rm -f usb-ids.h
diff --git a/mdk-stage1/usb-resource/update-usb-ids.pl b/mdk-stage1/usb-resource/update-usb-ids.pl
new file mode 100755
index 000000000..9d6ca1cfc
--- /dev/null
+++ b/mdk-stage1/usb-resource/update-usb-ids.pl
@@ -0,0 +1,24 @@
+#!/usr/bin/perl
+
+use lib '../kernel';
+use strict;
+use MDK::Common;
+
+my @modules = chomp_(`perl ../../kernel/modules.pl pci_modules4stage1 "bus/usb"`)
+ or die "unable to get USB controller modules";
+print "char *usb_controller_modules[] = {
+";
+printf qq|\t"%s",\n|, $_ foreach @modules;
+print "};
+unsigned int usb_controller_modules_len = sizeof(usb_controller_modules) / sizeof(char *);
+";
+
+@modules = chomp_(`perl ../../kernel/modules.pl pci_modules4stage1 "network/usb disk/usb"`)
+ or die "unable to get USB modules";
+
+print "char *usb_modules[] = {
+";
+printf qq|\t"%s",\n|, $_ foreach @modules;
+print "};
+unsigned int usb_modules_len = sizeof(usb_modules) / sizeof(char *);
+";
diff --git a/mdk-stage1/utils.c b/mdk-stage1/utils.c
new file mode 100644
index 000000000..434704bef
--- /dev/null
+++ b/mdk-stage1/utils.c
@@ -0,0 +1,191 @@
+/*
+ * Guillaume Cottenceau (gc@mandrakesoft.com)
+ *
+ * Copyright 2000 Mandrakesoft
+ *
+ * This software may be freely redistributed under the terms of the GNU
+ * public license.
+ *
+ * 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.
+ *
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <dirent.h>
+#include <sys/utsname.h>
+
+#include "utils.h"
+#include "log.h"
+
+// warning, many things rely on the fact that:
+// - when failing it returns 0
+// - it stops on first non-digit char
+int charstar_to_int(const char * s)
+{
+ int number = 0;
+ while (*s && isdigit(*s)) {
+ number = (number * 10) + (*s - '0');
+ s++;
+ }
+ return number;
+}
+
+off_t file_size(const char * path)
+{
+ struct stat statr;
+ if (stat(path, &statr))
+ return -1;
+ else
+ return statr.st_size;
+}
+
+char * cat_file(const char * file, struct stat * s) {
+ char * buf;
+ int fd = open(file, O_RDONLY);
+ if (fd == -1) {
+ log_perror(file);
+ return NULL;
+ }
+
+ fstat(fd, s);
+ buf = malloc(s->st_size + 1);
+ if (read(fd, buf, s->st_size) != (ssize_t)s->st_size) {
+ close(fd);
+ free(buf);
+ log_perror(file);
+ return NULL;
+ }
+ buf[s->st_size] = '\0';
+ close(fd);
+
+ return buf;
+}
+
+int line_counts(const char * buf) {
+ const char * ptr = buf;
+ int line = 0;
+ while (ptr) {
+ line++;
+ ptr = strchr(ptr + 1, '\n');
+ }
+ return line;
+}
+
+int total_memory(void)
+{
+ int value;
+
+ /* drakx powered: use /proc/kcore and rounds every 4 Mbytes */
+ value = 4 * ((int)((float)file_size("/proc/kcore") / 1024 / 1024 / 4 + 0.5));
+ log_message("Total Memory: %d Mbytes", value);
+
+ return value;
+}
+
+/* pixel's */
+void * memdup(void *src, size_t size)
+{
+ void * r;
+ r = malloc(size);
+ memcpy(r, src, size);
+ return r;
+}
+
+
+void add_to_env(char * name, char * value)
+{
+ FILE* fakeenv = fopen("/tmp/env", "a");
+ if (fakeenv) {
+ char* e = asprintf_("%s=%s\n", name, value);
+ fwrite(e, 1, strlen(e), fakeenv);
+ free(e);
+ fclose(fakeenv);
+ } else
+ log_message("couldn't fopen to fake env");
+}
+
+char ** list_directory(char * direct)
+{
+ char * tmp[50000]; /* in /dev there can be many many files.. */
+ int i = 0;
+ struct dirent *ep;
+ DIR *dp = opendir(direct);
+ while (dp && (ep = readdir(dp))) {
+ if (strcmp(ep->d_name, ".") && strcmp(ep->d_name, "..")) {
+ tmp[i] = strdup(ep->d_name);
+ i++;
+ }
+ }
+ if (dp)
+ closedir(dp);
+ tmp[i] = NULL;
+ return memdup(tmp, sizeof(char*) * (i+1));
+}
+
+
+int string_array_length(char ** a)
+{
+ int i = 0;
+ if (!a)
+ return -1;
+ while (a && *a) {
+ a++;
+ i++;
+ }
+ return i;
+}
+
+int kernel_version(void)
+{
+ struct utsname val;
+ if (uname(&val)) {
+ log_perror("uname failed");
+ return -1;
+ }
+ return charstar_to_int(val.release + 2);
+}
+
+char * asprintf_(const char *msg, ...)
+{
+ int n;
+ char * s;
+ char dummy;
+ va_list arg_ptr;
+ va_start(arg_ptr, msg);
+ n = vsnprintf(&dummy, sizeof(dummy), msg, arg_ptr);
+ va_start(arg_ptr, msg);
+ if ((s = malloc(n + 1))) {
+ vsnprintf(s, n + 1, msg, arg_ptr);
+ va_end(arg_ptr);
+ return s;
+ }
+ va_end(arg_ptr);
+ return strdup("");
+}
+
+int scall_(int retval, char * msg, char * file, int line)
+{
+ char tmp[5000];
+ sprintf(tmp, "%s(%s:%d) failed", msg, file, line);
+ if (retval)
+ log_perror(tmp);
+ return retval;
+}
+
+void lowercase(char *s)
+{
+ int i = 0;
+ while (s[i]) {
+ s[i] = tolower(s[i]);
+ i++;
+ }
+}
diff --git a/mdk-stage1/utils.h b/mdk-stage1/utils.h
new file mode 100644
index 000000000..fe02bc00c
--- /dev/null
+++ b/mdk-stage1/utils.h
@@ -0,0 +1,38 @@
+/*
+ * Guillaume Cottenceau (gc@mandrakesoft.com)
+ *
+ * Copyright 2000 Mandrakesoft
+ *
+ * This software may be freely redistributed under the terms of the GNU
+ * public license.
+ *
+ * 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.
+ *
+ */
+
+#ifndef _UTILS_H_
+#define _UTILS_H_
+
+#include <sys/stat.h>
+
+int charstar_to_int(const char * s);
+off_t file_size(const char * path);
+char * cat_file(const char * file, struct stat * s);
+int line_counts(const char * buf);
+int total_memory(void);
+void * memdup(void *src, size_t size);
+void add_to_env(char * name, char * value);
+char ** list_directory(char * direct);
+int string_array_length(char ** a);
+int kernel_version(void);
+char * asprintf_(const char *msg, ...);
+int scall_(int retval, char * msg, char * file, int line);
+#define scall(retval, msg) scall_(retval, msg, __FILE__, __LINE__)
+void lowercase(char *s);
+
+#define ptr_begins_static_str(pointer,static_str) (!strncmp(pointer,static_str,sizeof(static_str)-1))
+#define streq(a,b) (!strcmp(a,b))
+
+#endif
diff --git a/mdk-stage1/wireless.c b/mdk-stage1/wireless.c
new file mode 100644
index 000000000..ca0387fce
--- /dev/null
+++ b/mdk-stage1/wireless.c
@@ -0,0 +1,160 @@
+/*
+ * Olivier Blin (oblin@mandriva.com)
+ *
+ * Copyright 2005 Mandriva
+ *
+ * This software may be freely redistributed under the terms of the GNU
+ * public license.
+ *
+ * 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.
+ *
+ */
+
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <linux/types.h>
+#include <linux/if.h>
+#include <linux/wireless.h>
+
+#include "automatic.h"
+#include "stage1.h"
+#include "log.h"
+#include "utils.h"
+#include "wireless.h"
+
+static int wireless_ioctl(int socket, const char *ifname, int request, struct iwreq *wrq);
+static int wireless_set_mode_managed(int socket, const char *ifname);
+static int wireless_disable_key(int socket, const char *ifname);
+static int wireless_set_restricted_key(int socket, const char *ifname, const char *key);
+static int wireless_set_essid(int socket, const char *ifname, const char *essid);
+
+int wireless_open_socket()
+{
+ return socket(AF_INET, SOCK_DGRAM, 0);
+}
+
+int wireless_close_socket(int socket)
+{
+ return close(socket);
+}
+
+static int wireless_ioctl(int socket, const char *ifname, int request, struct iwreq *wrq)
+{
+ strncpy(wrq->ifr_name, ifname, IFNAMSIZ);
+ return ioctl(socket, request, wrq);
+}
+
+int wireless_is_aware(int socket, const char *ifname)
+{
+ struct iwreq wrq;
+ return wireless_ioctl(socket, ifname, SIOCGIWNAME, &wrq) == 0;
+}
+
+static int wireless_set_mode_managed(int socket, const char *ifname)
+{
+ struct iwreq wrq;
+
+ wrq.u.mode = IW_MODE_INFRA; /* managed */
+
+ return wireless_ioctl(socket, ifname, SIOCSIWMODE, &wrq) == 0;
+}
+
+static int wireless_set_essid(int socket, const char *ifname, const char *essid)
+{
+ struct iwreq wrq;
+
+ wrq.u.essid.flags = 1;
+ wrq.u.essid.pointer = (void *) essid;
+ wrq.u.essid.length = strlen(essid) + 1;
+
+ return wireless_ioctl(socket, ifname, SIOCSIWESSID, &wrq) == 0;
+}
+
+static int wireless_disable_key(int socket, const char *ifname)
+{
+ struct iwreq wrq;
+
+ wrq.u.data.flags = IW_ENCODE_DISABLED;
+ wrq.u.data.pointer = NULL;
+ wrq.u.data.length = 0;
+
+ return wireless_ioctl(socket, ifname, SIOCSIWENCODE, &wrq) == 0;
+}
+
+static int wireless_set_restricted_key(int socket, const char *ifname, const char *key)
+{
+ struct iwreq wrq;
+ char real_key[IW_ENCODING_TOKEN_MAX];
+ int key_len = 0;
+ unsigned int tmp;
+
+ while (sscanf(key + 2*key_len, "%2X", &tmp) == 1)
+ real_key[key_len++] = (char) tmp;
+
+ wrq.u.data.flags = IW_ENCODE_RESTRICTED;
+ wrq.u.data.pointer = (char *) real_key;
+ wrq.u.data.length = key_len;
+
+ return wireless_ioctl(socket, ifname, SIOCSIWENCODE, &wrq) == 0;
+}
+
+enum return_type configure_wireless(const char *ifname)
+{
+ enum return_type results;
+ char * questions[] = { "ESSID", "WEP key", NULL };
+ char * questions_auto[] = { "essid", "wep_key" };
+ static char ** answers = NULL;
+ int wsock = wireless_open_socket();
+
+ if (!wireless_is_aware(wsock, ifname)) {
+ log_message("interface %s doesn't support wireless", ifname);
+ wireless_close_socket(wsock);
+ return RETURN_OK;
+ }
+
+ results = ask_from_entries_auto("Please enter your wireless settings. "
+ "The ESSID is your wireless network identifier. "
+ "The WEP key must be entered in hexadecimal, without any separator.",
+ questions, &answers, 32, questions_auto, NULL);
+ if (results != RETURN_OK) {
+ wireless_close_socket(wsock);
+ return RETURN_BACK;
+ }
+
+ if (!wireless_set_mode_managed(wsock, ifname)) {
+ stg1_error_message("unable to set mode Managed on device \"%s\": %s", ifname, strerror(errno));
+ wireless_close_socket(wsock);
+ return RETURN_ERROR;
+ }
+
+ if (answers[1] && !streq(answers[1], "")) {
+ log_message("setting WEP key \"%s\" on device \"%s\"", answers[1], ifname);
+ if (!wireless_set_restricted_key(wsock, ifname, answers[1])) {
+ stg1_error_message("unable to set WEP key \"%s\" on device \"%s\": %s", answers[1], ifname, strerror(errno));
+ return RETURN_ERROR;
+ }
+ } else {
+ log_message("disabling WEP key on device \"%s\"", ifname);
+ if (!wireless_disable_key(wsock, ifname)) {
+ stg1_error_message("unable to disable WEP key on device \"%s\": %s", ifname, strerror(errno));
+ return RETURN_ERROR;
+ }
+ }
+
+ /* most devices perform discovery when ESSID is set, it needs to be last */
+ log_message("setting ESSID \"%s\" on device \"%s\"", answers[0], ifname);
+ if (!wireless_set_essid(wsock, ifname, answers[0])) {
+ stg1_error_message("unable to set ESSID \"%s\" on device \"%s\": %s", answers[0], ifname, strerror(errno));
+ return RETURN_ERROR;
+ }
+
+ wireless_close_socket(wsock);
+ return RETURN_OK;
+}
diff --git a/mdk-stage1/wireless.h b/mdk-stage1/wireless.h
new file mode 100644
index 000000000..3e5bb7790
--- /dev/null
+++ b/mdk-stage1/wireless.h
@@ -0,0 +1,25 @@
+/*
+ * Olivier Blin (oblin@mandriva.com)
+ *
+ * Copyright 2005 Mandriva
+ *
+ * This software may be freely redistributed under the terms of the GNU
+ * public license.
+ *
+ * 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.
+ *
+ */
+
+#ifndef _WIRELESS_H_
+#define _WIRELESS_H_
+
+#include "frontend.h"
+
+int wireless_open_socket();
+int wireless_close_socket(int socket);
+int wireless_is_aware(int socket, const char *ifname);
+enum return_type configure_wireless(const char *ifname);
+
+#endif
diff --git a/mdk-stage1/zlibsupport.c b/mdk-stage1/zlibsupport.c
new file mode 100644
index 000000000..ecbe7a5ef
--- /dev/null
+++ b/mdk-stage1/zlibsupport.c
@@ -0,0 +1,119 @@
+/* Support for compressed modules. Willy Tarreau <willy@meta-x.org>
+ * did the support for modutils, Andrey Borzenkov <arvidjaar@mail.ru>
+ * ported it to module-init-tools, and I said it was too ugly to live
+ * and rewrote it 8).
+ *
+ * (C) 2003 Rusty Russell, IBM Corporation.
+ */
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/mman.h>
+
+#include "zlibsupport.h"
+
+#ifdef CONFIG_USE_ZLIB
+#include <zlib.h>
+
+void *grab_contents(gzFile *gzfd, unsigned long *size)
+{
+ unsigned int max = 16384;
+ void *buffer = malloc(max);
+ int ret;
+
+ if (!buffer)
+ return NULL;
+
+ *size = 0;
+ while ((ret = gzread(gzfd, buffer + *size, max - *size)) > 0) {
+ *size += ret;
+ if (*size == max) {
+ void *p;
+
+ p = realloc(buffer, max *= 2);
+ if (!p)
+ goto out_err;
+
+ buffer = p;
+ }
+ }
+ if (ret < 0)
+ goto out_err;
+
+ return buffer;
+
+out_err:
+ free(buffer);
+ return NULL;
+}
+
+void *grab_fd(int fd, unsigned long *size)
+{
+ gzFile gzfd;
+
+ gzfd = gzdopen(fd, "rb");
+ if (!gzfd)
+ return NULL;
+
+ /* gzclose(gzfd) would close fd, which would drop locks.
+ Don't blame zlib: POSIX locking semantics are so horribly
+ broken that they should be ripped out. */
+ return grab_contents(gzfd, size);
+}
+
+/* gzopen handles uncompressed files transparently. */
+void *grab_file(const char *filename, unsigned long *size)
+{
+ gzFile gzfd;
+ void *buffer;
+
+ gzfd = gzopen(filename, "rb");
+ if (!gzfd)
+ return NULL;
+ buffer = grab_contents(gzfd, size);
+ gzclose(gzfd);
+ return buffer;
+}
+
+void release_file(void *data, unsigned long size)
+{
+ free(data);
+}
+#else /* ... !CONFIG_USE_ZLIB */
+
+void *grab_fd(int fd, unsigned long *size)
+{
+ struct stat st;
+ void *map;
+ int ret;
+
+ ret = fstat(fd, &st);
+ if (ret < 0)
+ return NULL;
+ *size = st.st_size;
+ map = mmap(0, *size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
+ if (map == MAP_FAILED)
+ map = NULL;
+ return map;
+}
+
+void *grab_file(const char *filename, unsigned long *size)
+{
+ int fd;
+ void *map;
+
+ fd = open(filename, O_RDONLY, 0);
+ if (fd < 0)
+ return NULL;
+ map = grab_fd(fd, size);
+ close(fd);
+ return map;
+}
+
+void release_file(void *data, unsigned long size)
+{
+ munmap(data, size);
+}
+#endif
diff --git a/mdk-stage1/zlibsupport.h b/mdk-stage1/zlibsupport.h
new file mode 100644
index 000000000..be3c7296a
--- /dev/null
+++ b/mdk-stage1/zlibsupport.h
@@ -0,0 +1,11 @@
+#ifndef _ZLIB_SUPPORT_H
+#define _ZLIB_SUPPORT_H
+
+/* Grab file. Decompresses if that is supported. Returns NULL on error. */
+extern void *grab_file(const char *filename, unsigned long *size);
+extern void *grab_fd(int fd, unsigned long *size);
+
+/* Free it up. */
+extern void release_file(void *data, unsigned long size);
+
+#endif /* _ZLIB_SUPPORT_H */